Index: src/Validate/ReplacePseudoFunc.cpp
===================================================================
--- src/Validate/ReplacePseudoFunc.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Validate/ReplacePseudoFunc.cpp	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
@@ -21,5 +21,4 @@
 
 struct ReplaceEnumInstWithPos final : public ast::WithShortCircuiting {
-    void previsit(const ast::ObjectDecl*) { visit_children = false; }
     const ast::ObjectDecl* postvisit(const ast::ObjectDecl* decl) {
         auto enumInst = decl->type.strict_as<ast::EnumInstType>();
@@ -84,5 +83,6 @@
     }
 
-    if (fname == "labelE" || fname == "valueE" || fname == "posE") {
+    if (fname == "labelE" || fname == "valueE" || fname == "posE" ||
+        fname == "pred" || fname == "succ") {
         visit_children = false;
     }
@@ -226,5 +226,5 @@
 }
 
-ast::ApplicationExpr const* getPseudoFuncApplication(
+ast::ApplicationExpr const* resolveAttributeFunctions(
     const CodeLocation location, ResolvExpr::ResolveContext context,
     const ast::VariableExpr* arg, const ast::EnumDecl* base,
@@ -241,4 +241,6 @@
         auto rep = argAsDecl->accept(replacer);
         auto mutatedArg = ast::mutate_field(arg, &ast::VariableExpr::var, rep);
+        mutatedArg = ast::mutate_field(mutatedArg, &ast::VariableExpr::result,
+                                       mutatedArg->var->get_type());
         auto untyped =
             new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
@@ -290,5 +292,5 @@
                                                               referredName);
                     else {
-                        return getPseudoFuncApplication(
+                        return resolveAttributeFunctions(
                             location, context, arg.get(), base, "values_");
                     }
@@ -297,10 +299,10 @@
 
             if (fname == "labelE") {
-                if (auto labelExpr = getPseudoFuncApplication(
+                if (auto labelExpr = resolveAttributeFunctions(
                         location, context, arg.get(), base, "labels_")) {
                     return labelExpr;
                 }
             } else if (fname == "valueE") {
-                if (auto valueExpr = getPseudoFuncApplication(
+                if (auto valueExpr = resolveAttributeFunctions(
                         location, context, arg.get(), base, "values_")) {
                     return valueExpr;
@@ -314,10 +316,10 @@
             ResolvExpr::ResolveContext context{symtab, transUnit().global};
             if (fname == "labelE") {
-                if (auto labelExpr = getPseudoFuncApplication(
+                if (auto labelExpr = resolveAttributeFunctions(
                         location, context, arg.get(), base, "labels_")) {
                     return labelExpr;
                 }
             } else if (fname == "valueE") {
-                if (auto valueExpr = getPseudoFuncApplication(
+                if (auto valueExpr = resolveAttributeFunctions(
                         location, context, arg.get(), base, "values_")) {
                     return valueExpr;
@@ -345,36 +347,171 @@
     const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
         auto fname = ast::getFunctionName(expr);
-        if (fname != "?[?]") return expr;
-        if (expr->args.size() != 2) return expr;
-
-        auto arg1AsVar =
-            reduceCastExpr(expr->args.front()).as<ast::VariableExpr>();
-        auto arg2AsVar =
-            reduceCastExpr(expr->args.back()).as<ast::VariableExpr>();
-
-        if (!arg1AsVar || !arg2AsVar) return expr;
-
-        auto arg1Asecl = arg1AsVar->var.as<ast::ObjectDecl>();
-        auto arg2Asecl = arg2AsVar->var.as<ast::ObjectDecl>();
-
-        if (!arg1Asecl || !arg2Asecl) return expr;
-        auto arrInst = arg1Asecl->type.as<ast::ArrayType>();
-        auto pointerInst = arg1Asecl->type.as<ast::PointerType>();
-        if (!arrInst && !pointerInst) {
-            return expr;
-        }
-        auto enumInst = arg2Asecl->type.as<ast::EnumInstType>();
-        if (!enumInst) return expr;
-
-        const std::string arrName = arg1Asecl->name;
-        if (arrName != getValueArrayName(enumInst->base->name)) return expr;
-        ast::Pass<ReplaceEnumInstWithPos> replacer;
-        auto rep = arg2Asecl->accept(replacer);
-        if (!rep) return expr;
-        auto mutObj =
-            ast::mutate_field(arg2AsVar, &ast::VariableExpr::var, rep);
-        auto mut = ast::mutate_field_index(expr, &ast::ApplicationExpr::args, 1,
-                                           mutObj);
-        return mut;
+        if (fname == "?[?]") {
+            if (expr->args.size() != 2) return expr;
+
+            auto arg1AsVar =
+                reduceCastExpr(expr->args.front()).as<ast::VariableExpr>();
+            auto arg2AsVar =
+                reduceCastExpr(expr->args.back()).as<ast::VariableExpr>();
+
+            if (!arg1AsVar || !arg2AsVar) return expr;
+
+            auto arg1AsDecl = arg1AsVar->var.as<ast::ObjectDecl>();
+            auto arg2AsDecl = arg2AsVar->var.as<ast::ObjectDecl>();
+
+            if (!arg1AsDecl || !arg2AsDecl) return expr;
+            auto arrInst = arg1AsDecl->type.as<ast::ArrayType>();
+            auto pointerInst = arg1AsDecl->type.as<ast::PointerType>();
+            if (!arrInst && !pointerInst) {
+                return expr;
+            }
+            auto enumInst = arg2AsDecl->type.as<ast::EnumInstType>();
+            if (!enumInst) return expr;
+
+            const std::string arrName = arg1AsDecl->name;
+            if (arrName != getValueArrayName(enumInst->base->name)) return expr;
+            ast::Pass<ReplaceEnumInstWithPos> replacer;
+            auto rep = arg2AsDecl->accept(replacer);
+            if (!rep) return expr;
+            auto mutObj =
+                ast::mutate_field(arg2AsVar, &ast::VariableExpr::var, rep);
+            mutObj = ast::mutate_field(mutObj, &ast::VariableExpr::result,
+                                       mutObj->var->get_type());
+            auto mut = ast::mutate_field_index(
+                expr, &ast::ApplicationExpr::args, 1, mutObj);
+            return mut;
+        }
+        // else if (fname == "succ" || fname == "pred") {
+        //     if (expr->args.size() != 1) return expr;
+        //     auto argExpr = expr->args.front();
+        //     auto argAsVar = reduceCastExpr(argExpr).as<ast::VariableExpr>();
+
+        //     if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
+        //         if (auto enumInst = argAsDecl->type.as<ast::EnumInstType>())
+        //         {
+        //             auto enumPos = new ast::EnumPosType(enumInst);
+        //             auto castExpr =
+        //                 new ast::CastExpr(argExpr->location, argExpr,
+        //                 enumPos);
+        //             auto mut = ast::mutate_field_index(
+        //                 expr, &ast::ApplicationExpr::args, 0, castExpr);
+        //             return mut;
+        //         } else if (auto enumPos =
+        //                        argAsDecl->type.as<ast::EnumPosType>()) {
+        //             //     std::cout << "pos" << std::endl;
+        //             return expr;
+        //         }
+        //     }
+        // }
+        return expr;
+    }
+};
+
+struct ReplaceSuccAndPred final : public ast::WithSymbolTable,
+                                  public ast::WithConstTranslationUnit {
+    const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
+        auto fname = ast::getFunctionName(expr);
+        if (fname == "succ" || fname == "pred") {
+            const CodeLocation& location = expr->location;
+            if (expr->args.size() != 1) return expr;
+
+            // if (auto argAsVar = reduceCastExpr(expr->args.front())
+            //                         .as<ast::VariableExpr>()) {
+            //     if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
+            //         auto enumPos = argAsDecl->type.as<ast::EnumPosType>();
+            //         if (!enumPos) return expr;
+            //         // ast::Pass<ReplaceEnumInstWithPos> replacer;
+            //         // auto posObj = argAsDecl->accept(replacer);
+            //         // if (!posObj) return expr;
+
+            //         // auto newParam = new ast::VariableExpr( location,
+            //         posObj
+            //         // );
+
+            //         auto untyped = new ast::UntypedExpr(
+            //             location,
+            //             new ast::NameExpr(location, fname == "succ"
+            //                                             ? "_successor_"
+            //                                             : "_predessor_"),
+            //             {argAsVar});
+
+            //         ResolvExpr::ResolveContext context{symtab,
+            //                                            transUnit().global};
+
+            //         auto typedResult =
+            //             ResolvExpr::findVoidExpression(untyped, context);
+
+            //         ast::ptr<ast::ApplicationExpr> ret =
+            //             typedResult.strict_as<ast::ApplicationExpr>();
+
+            //         return ast::deepCopy(ret);
+            //     }
+            // }
+            auto param = expr->args.front();
+            if (auto argAsVar = reduceCastExpr(param).as<ast::VariableExpr>()) {
+                if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
+                    if (auto enumInst =
+                            argAsDecl->type.as<ast::EnumInstType>()) {
+                        auto castTo = new ast::EnumPosType(enumInst);
+                        auto castExpr =
+                            new ast::CastExpr(param->location, param, castTo);
+
+                        auto untyped = new ast::UntypedExpr(
+                            expr->location,
+                            new ast::NameExpr(location, fname == "succ"
+                                                            ? "_successor_"
+                                                            : "_predessor_"),
+                            {castExpr});
+                        ResolvExpr::ResolveContext context{symtab,
+                                                           transUnit().global};
+                        auto typedResult =
+                            ResolvExpr::findVoidExpression(untyped, context);
+                        ast::ptr<ast::ApplicationExpr> ret =
+                            typedResult.strict_as<ast::ApplicationExpr>();
+                        return ast::deepCopy(ret);
+                    } else if (auto posType =
+                                   argAsDecl->type.as<ast::EnumPosType>()) {
+                        // Very nasty fix. Must be revisit
+                        if (auto paramAsVar = param.as<ast::VariableExpr>()) {
+                            if (paramAsVar->result.as<ast::EnumInstType>()) {
+                                auto paramToUse = ast::mutate_field(
+                                    paramAsVar, &ast::VariableExpr::result,
+                                    posType);
+                                auto untyped = new ast::UntypedExpr(
+                                    expr->location,
+                                    new ast::NameExpr(location,
+                                                      fname == "succ"
+                                                          ? "_successor_"
+                                                          : "_predessor_"),
+                                    {paramToUse});
+                                ResolvExpr::ResolveContext context{
+                                    symtab, transUnit().global};
+                                auto typedResult =
+                                    ResolvExpr::findVoidExpression(untyped,
+                                                                   context);
+                                ast::ptr<ast::ApplicationExpr> ret =
+                                    typedResult
+                                        .strict_as<ast::ApplicationExpr>();
+                                return ast::deepCopy(ret);
+                            }
+                        }
+                        auto untyped = new ast::UntypedExpr(
+                            expr->location,
+                            new ast::NameExpr(location, fname == "succ"
+                                                            ? "_successor_"
+                                                            : "_predessor_"),
+                            {param});
+                        ResolvExpr::ResolveContext context{symtab,
+                                                           transUnit().global};
+                        auto typedResult =
+                            ResolvExpr::findVoidExpression(untyped, context);
+                        ast::ptr<ast::ApplicationExpr> ret =
+                            typedResult.strict_as<ast::ApplicationExpr>();
+                        return ast::deepCopy(ret);
+                    }
+                }
+            }
+        }
+        return expr;
     }
 };
@@ -385,7 +522,10 @@
     ast::Pass<WrapEnumValueExpr>::run(translationUnit);
     ast::Pass<FindGenEnumArray>::run(translationUnit);
+
     ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
     ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
     ast::Pass<ReplaceEnumInst>::run(translationUnit);
+
+    ast::Pass<ReplaceSuccAndPred>::run(translationUnit);
 }
 }  // namespace Validate
