Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/AST/Print.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -175,4 +175,13 @@
 		}
 
+		auto ptrToEnum = dynamic_cast<const ast::EnumDecl *>(node);
+		if ( ! short_mode && ptrToEnum && ptrToEnum->base ) {
+			os << endl << indent << "... with base type" << endl;
+			++indent;
+			os << indent;
+			ptrToEnum->base->accept( *this );
+			--indent;
+		}
+
 		os << " " << (node->body ? "with" : "without") << " body";
 
@@ -198,11 +207,5 @@
 		}
 
-		auto ptrToEnum = dynamic_cast<const ast::EnumDecl *>(node);
-		if ( ! short_mode && ptrToEnum && ptrToEnum->base ) {
-			os << endl << indent << ".. with (enum) base" << endl;
-			++indent;
-			ptrToEnum->base->accept( *this );
-			--indent;
-		}
+
 
 		os << endl;
Index: src/CodeGen/CodeGenerator.cpp
===================================================================
--- src/CodeGen/CodeGenerator.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/CodeGen/CodeGenerator.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -331,14 +331,14 @@
 	extension( decl );
 	auto members = decl->members;
-	if ( decl->base && !members.empty() ) {
-		long long curVal = 0;
-		for ( auto member : members ) {
-			auto obj = member.strict_as<ast::ObjectDecl>();
-			output << "static ";
-			output << genType( decl->base, mangleName( obj ), options );
-			genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
-			output << ";" << endl;
-		}
-	} else {
+	// if ( decl->base && !members.empty() ) {
+	// 	long long curVal = 0;
+	// 	for ( auto member : members ) {
+	// 		auto obj = member.strict_as<ast::ObjectDecl>();
+	// 		output << "static ";
+	// 		output << genType( decl->base, mangleName( obj ), options );
+	// 		genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
+	// 		output << ";" << endl;
+	// 	}
+	// } else {
 		output << "enum ";
 		genAttributes( decl->attributes );
@@ -353,5 +353,5 @@
 				auto obj = member.strict_as<ast::ObjectDecl>();
 				output << indent << mangleName( obj );
-				if ( obj->init ) {
+				if ( !decl->base && obj->init ) {
 					output << " = ";
 					obj->init->accept( *visitor );
@@ -363,5 +363,5 @@
 			output << indent << "}";
 		}
-	}
+	// }
 }
 
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/CodeGen/GenType.cc	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -228,12 +228,12 @@
 
 void GenType::postvisit( ast::EnumInstType const * type ) {
-	if ( type->base && type->base->base ) {
-		result = genType( type->base->base, result, options );
-	} else {
+	// if ( type->base && type->base->base ) {
+	// 	result = genType( type->base->base, result, options );
+	// } else {
 		result = type->name + " " + result;
 		if ( options.genC ) {
 			result = "enum " + result;
 		}
-	}
+	// }
 	handleQualifiers( type );
 }
Index: src/GenPoly/Lvalue.cpp
===================================================================
--- src/GenPoly/Lvalue.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/GenPoly/Lvalue.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -133,4 +133,18 @@
 			return func->linkage == ast::Linkage::Intrinsic
 				&& lvalueFunctions.count( func->name );
+		}
+	}
+	return false;
+}
+
+bool isGeneratedInstrinct( ast::Expr const * expr ) {
+	if ( auto app = dynamic_cast<ast::ApplicationExpr const *>( expr ) ) {
+		if ( app->args.size() == 2 && ast::getFunction( app )->name == "?[?]" ) {
+			auto param_1 = dynamic_cast<ast::VariableExpr const *>(app->args.front().get());
+			if ( param_1 ) {
+				auto param_1_as_obj = param_1->var.as<ast::ObjectDecl>();
+				return ( param_1_as_obj->name.find( "values_") != std::string::npos
+					||  param_1_as_obj->name.find( "labels_" ) != std::string::npos );
+			}
 		}
 	}
@@ -161,5 +175,6 @@
 ast::Expr const * FixIntrinsicResults::postvisit(
 		ast::ApplicationExpr const * expr ) {
-	if ( skip == SkipInProgress || !isIntrinsicReference( expr ) ) {
+
+	if ( skip == SkipInProgress || !isIntrinsicReference( expr ) || isGeneratedInstrinct( expr ) ) {
 		return expr;
 	}
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -891,4 +891,18 @@
 		} else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
+		} else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
+			// The Attribute Arrays are not yet generated, need to proxy them
+			// as attribute function call
+			const CodeLocation & location = cand->expr->location;
+			if ( enumInst->base && enumInst->base->base ) {
+				auto valueName = new ast::NameExpr(location, "valueE");
+				auto untypedValueCall = new ast::UntypedExpr( 
+					location, valueName, { aggrExpr } );
+				auto result = ResolvExpr::findVoidExpression( untypedValueCall, context );
+				assert( result.get() );
+				CandidateRef newCand = std::make_shared<Candidate>(
+					*cand, result, Cost::safe );
+				candidates.emplace_back( std::move( newCand ) );
+			}
 		}
 	}
@@ -961,14 +975,4 @@
 
 					if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);						
-					// else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
-					// 	const ast::EnumDecl * enumDecl = enumInst->base; // Here
-					// 	if ( const ast::Type* enumType = enumDecl->base ) {
-					// 		// instance of enum (T) is a instance of type (T)
-					// 		funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
-					// 	} else {
-					// 		// instance of an untyped enum is techically int
-					// 		funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
-					// 	}
-					// }
 					else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
 				}
@@ -1399,6 +1403,34 @@
 		// not sufficient to just pass `variableExpr` here, type might have changed since
 		// creation
-		addCandidate(
-			new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
+		if ( auto obj =  dynamic_cast<const ast::ObjectDecl *>( variableExpr->var.get() )) {
+			if ( auto enumInstType = dynamic_cast<const ast::EnumInstType *>( obj->type.get() ) ) {
+				if ( enumInstType->base && enumInstType->base->base ) {
+					const CodeLocation & location = variableExpr->location;
+					auto ids = symtab.lookupId( "valueE" );
+						for ( ast::SymbolTable::IdData & id : ids ) {
+							if ( auto func = id.id.as<ast::FunctionDecl>() ) {
+								if ( func->params.size() == 1 ) {
+									ast::ptr<ast::DeclWithType> valueEParam = func->params.front();
+									auto valueEParamType = valueEParam->get_type();
+									ast::OpenVarSet funcOpen;
+									ast::AssertionSet funcNeed, funcHave;
+									ast::TypeEnvironment funcEnv{ tenv };
+									ast::ptr<ast::Type> common;
+									if ( unifyInexact( valueEParamType, enumInstType, funcEnv, funcNeed, funcHave, funcOpen, WidenMode{ true, true }, common ) ) {
+										auto appl = new ast::ApplicationExpr( location,
+											ast::VariableExpr::functionPointer( location,  func), { variableExpr } );
+										// addCandidate( appl, copy( tenv ),  );
+										Candidate cand {appl, copy( tenv )};
+										addCandidate( cand, appl, Cost::safe );
+									}
+								}
+							}
+						}
+				}
+			
+			}
+		} 
+		addCandidate( variableExpr, tenv );
+		
 	}
 
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/ResolvExpr/ConversionCost.cc	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -279,13 +279,8 @@
 		conversionCostFromBasicToBasic( basicType, dstAsBasic );
 	} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-		const ast::EnumDecl * enumDecl = enumInst->base.get();
-		if ( enumDecl->isTyped && !enumDecl->base.get() ) {
-			cost = Cost::infinity;
-		} else if ( const ast::Type * enumType = enumDecl->base.get() ) {
-			if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) {
-				conversionCostFromBasicToBasic( basicType, enumTypeAsBasic );
-			} else {
-				cost = Cost::infinity;
-			}
+		auto enumDecl = enumInst->base;
+		if ( auto baseType = enumDecl->base.get() ) {
+			cost = costCalc( basicType, baseType, srcIsLvalue, symtab, env );
+			cost.incUnsafe();
 		} else {
             cost = Cost::unsafe;
@@ -367,11 +362,11 @@
 
 void ConversionCost::postvisit( const ast::EnumInstType * enumInstType ) {
-	const ast::EnumDecl * baseEnum = enumInstType->base;
-	if ( const ast::Type * baseType = baseEnum->base ) {
-		costCalc( baseType, dst, srcIsLvalue, symtab, env );
-	} else {
-		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
-		cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
-	}
+	//	const ast::EnumDecl * baseEnum = enumInstType->base;
+	// if ( const ast::Type * baseType = baseEnum->base ) {
+	// 	costCalc( baseType, dst, srcIsLvalue, symtab, env );
+	// } else {
+	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
+	cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
+	// }
 	if ( cost < Cost::unsafe ) {
 		cost.incSafe();
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/ResolvExpr/Unify.cc	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -73,17 +73,4 @@
 		ast::Type * newFirst  = shallowCopy( first  );
 		ast::Type * newSecond = shallowCopy( second );
-		if ( auto temp = dynamic_cast<const ast::EnumInstType *>(first) ) {
-			if ( !dynamic_cast< const ast::EnumInstType * >( second ) ) {
-				const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get());
-				if ( auto t = baseEnum->base.get() ) {
-					newFirst = ast::shallowCopy( t );
-				}
-			}
-		} else if ( auto temp = dynamic_cast<const ast::EnumInstType *>(second) ) {
-			const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get());
-			if ( auto t = baseEnum->base.get() ) {
-				newSecond = ast::shallowCopy( t );
-			}
-		}
 
 		newFirst ->qualifiers = {};
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/Validate/Autogen.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -197,8 +197,21 @@
 
 	bool shouldAutogen() const final { return true; }
+	void genAttrFuncForward();
+	void __attribute__ ((unused)) genDualFuncs();
 private:
 	void genFuncBody( ast::FunctionDecl * decl ) final;
 	void genFieldCtors() final;
 	const ast::Decl * getDecl() const final { return decl; }
+
+	ast::ObjectDecl * dualDstParam() const;
+
+	ast::FunctionDecl * genPosProto() const;
+	ast::FunctionDecl * genLabelProto() const;
+	ast::FunctionDecl * genValueProto() const;
+
+	ast::FunctionDecl * genCopyEnumToDualProto() const;
+	ast::FunctionDecl * genAssignEnumToDualProto() const;
+
+	void genDualBody( ast::FunctionDecl * decl );
 };
 
@@ -238,17 +251,13 @@
 // --------------------------------------------------------------------------
 void AutogenerateRoutines::previsit( const ast::EnumDecl * enumDecl ) {
-	// Must visit children (enum constants) to add them to the symbol table.
 	if ( !enumDecl->body ) return;
-
-	// if ( auto enumBaseType = enumDecl->base ) {
-	// 	if ( auto enumBaseTypeAsStructInst = dynamic_cast<const ast::StructInstType *>(enumBaseType.get()) ) {
-	// 		const ast::StructDecl * structDecl = enumBaseTypeAsStructInst->base.get();
-	// 		this->previsit( structDecl );
-	// 	}
-	// }
 
 	ast::EnumInstType enumInst( enumDecl->name );
 	enumInst.base = enumDecl;
 	EnumFuncGenerator gen( enumDecl, &enumInst, functionNesting );
+	if ( enumDecl->base ) {
+		gen.genAttrFuncForward();
+		// gen.genDualFuncs();
+	}
 	gen.generateAndAppendFunctions( declsToAddAfter );
 }
@@ -742,15 +751,25 @@
 		 * returns to zero.
 		 */
+		auto dstExpr = new ast::VariableExpr( location, dstParam );
+		const ast::Expr * srcExpr;
+		if ( decl->base ) {
+			srcExpr = new ast::ApplicationExpr( location,
+			ast::VariableExpr::functionPointer( location, genPosProto() ), 
+			{
+				new ast::VariableExpr( location, srcParam )
+			}
+			);
+		} else {
+			srcExpr = new ast::VariableExpr( location, srcParam );
+		}
+
 		auto callExpr = new ast::ApplicationExpr( location,
 			ast::VariableExpr::functionPointer( location, functionDecl ),
 			{
-				new ast::VariableExpr( location, dstParam ),
-				new ast::VariableExpr( location, srcParam ),
+				dstExpr,
+				srcExpr,
 			}
 		);
-		// auto fname = ast::getFunctionName( callExpr );
-		// if (fname == "posE" ) {
-		// 	std::cerr << "Found posE autogen" << std::endl;
-		// }
+
 		functionDecl->stmts = new ast::CompoundStmt( location,
 			{ new ast::ExprStmt( location, callExpr ) }
@@ -768,4 +787,95 @@
 			forwards.back().get_and_mutate() );
 		addUnusedAttribute( fwd->params.front() );
+	}
+}
+
+ast::FunctionDecl * EnumFuncGenerator::genPosProto() const {
+	return genProto( "posE", 
+		{ new ast::ObjectDecl( getLocation(), "_i", 
+		new ast::EnumInstType( decl ) )}, 
+		{ new ast::ObjectDecl( getLocation(), "_ret", 
+		new ast::BasicType{ ast::BasicType::UnsignedInt } )} );
+}
+
+ast::FunctionDecl * EnumFuncGenerator::genLabelProto() const {
+	return genProto( "labelE",
+		{ new ast::ObjectDecl( getLocation(), "_i", 
+		new ast::EnumInstType( decl ) ) },
+		{ new ast::ObjectDecl( getLocation(), "_ret", 
+		new ast::PointerType( new ast::BasicType{ ast::BasicType::Char } ) ) } );
+}
+
+ast::FunctionDecl * EnumFuncGenerator::genValueProto() const {
+	return genProto( "valueE", 
+		{ new ast::ObjectDecl( getLocation(), "_i", new ast::EnumInstType( decl ) )},
+		{ new ast::ObjectDecl( getLocation(), "_ret", ast::deepCopy( decl->base ) ) } );
+}
+
+void EnumFuncGenerator::genAttrFuncForward() {	
+	if ( decl->base ) {
+		ast::FunctionDecl *(EnumFuncGenerator::*attrProtos[3])() const = {
+			&EnumFuncGenerator::genPosProto, &EnumFuncGenerator::genLabelProto, 
+			&EnumFuncGenerator::genValueProto };
+		for ( auto & generator : attrProtos ) {
+			produceForwardDecl( (this->*generator)() );
+		}
+	}
+}
+
+ast::ObjectDecl * EnumFuncGenerator::dualDstParam() const {
+	auto base = decl->base;
+	assert( base );
+	return new ast::ObjectDecl( getLocation(), "_dst",
+		new ast::ReferenceType( ast::deepCopy( base ) ) );
+}
+
+// void ?{}(T & _dst, enum E _src )
+ast::FunctionDecl * EnumFuncGenerator::genCopyEnumToDualProto() const {
+	return genProto( "?{}", { dualDstParam(), srcParam() }, {} );
+}
+
+// T ?{}(T & _dst, enum E _src )
+ast::FunctionDecl * EnumFuncGenerator::genAssignEnumToDualProto() const {
+	auto retval = dualDstParam();
+	retval->name = "_ret";
+	return genProto( "?=?", { dualDstParam(), srcParam() }, { retval });
+}
+
+void EnumFuncGenerator::genDualBody( ast::FunctionDecl * functionDecl ) {
+	assert( decl->base );
+	const CodeLocation& location = functionDecl->location;
+	auto & params = functionDecl->params;
+	
+	assert( 2 == params.size() );
+	auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+	auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+
+	auto dstExpr = new ast::VariableExpr( location, dstParam );
+
+	auto srcExpr = new ast::ApplicationExpr( location,
+		ast::VariableExpr::functionPointer( location, genValueProto() ),
+		{
+			new ast::VariableExpr( location, srcParam )
+		});
+	auto callExpr = new ast::ApplicationExpr( location,
+		ast::VariableExpr::functionPointer( location, functionDecl ),
+		{ dstExpr, srcExpr } );
+	functionDecl->stmts = new ast::CompoundStmt( location,
+		{ new ast::ExprStmt( location, callExpr)} );
+}
+
+void EnumFuncGenerator::genDualFuncs() {
+	assert( decl->base );
+	ast::FunctionDecl *(EnumFuncGenerator::*dualProtos[2])() const = {
+			&EnumFuncGenerator::genCopyEnumToDualProto, 
+			&EnumFuncGenerator::genAssignEnumToDualProto };
+	for ( auto & generator : dualProtos ) {
+		ast::FunctionDecl * decl = (this->*generator)();
+		produceForwardDecl( decl );
+		genDualBody( decl );
+		if ( CodeGen::isAssignment( decl->name ) ) {
+			appendReturnThis( decl );
+		}
+		produceDecl( decl );
 	}
 }
Index: src/Validate/ReplacePseudoFunc.cpp
===================================================================
--- src/Validate/ReplacePseudoFunc.cpp	(revision e71b09ae00f2abd7047a70e3eaf09175d9b787f0)
+++ src/Validate/ReplacePseudoFunc.cpp	(revision 32490deb2180d977e78b79e5c2342a8fa2357a53)
@@ -17,7 +17,74 @@
 std::set<std::string> queryValues;
 
+struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
+                                 public ast::WithSymbolTable,
+                                 public ast::WithConstTranslationUnit {
+    void previsit(const ast::DeclStmt* expr);
+    void previsit(const ast::ApplicationExpr* expr);
+    void previsit(const ast::CastExpr* expr);
+
+    ast::Expr const* postvisit(const ast::VariableExpr* expr);
+};
+
 struct FindGenEnumArray final : public ast::WithShortCircuiting {
     void previsit(const ast::ApplicationExpr* enumDecl);
 };
+
+struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
+                                         public ast::WithSymbolTable,
+                                         public ast::WithShortCircuiting {
+    void previsit(const ast::EnumDecl* enumDecl);
+};
+
+struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
+                               public ast::WithSymbolTable,
+                               public ast::WithConstTranslationUnit {
+    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
+};
+
+void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
+
+    auto varExpr = expr->func.as<ast::VariableExpr>();
+    auto fname = ast::getFunctionName(expr);
+	if ( !varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic ) {
+        if ( fname == "?{}" || fname == "?=?" )
+		    visit_children = false;
+	}
+
+    if (fname == "labelE" || fname == "valueE" || fname == "posE")
+        visit_children = false;
+}
+
+void WrapEnumValueExpr::previsit(const ast::DeclStmt*) {
+    visit_children = false;
+}
+
+void WrapEnumValueExpr::previsit(const ast::CastExpr* expr) {
+    if (expr->result && expr->result.as<ast::ReferenceType>()) {
+        visit_children = false;
+    }
+}
+
+ast::Expr const* WrapEnumValueExpr::postvisit(const ast::VariableExpr* expr) {
+    visit_children = false;
+    if (!expr->result) {
+        return expr;
+    }
+    if (auto enumInst = expr->result.as<ast::EnumInstType>()) {
+        if (enumInst->base && enumInst->base->base) {
+            auto untyped = new ast::UntypedExpr(
+                expr->location, new ast::NameExpr(expr->location, "valueE"),
+                {new ast::VariableExpr(*expr)});
+            ResolvExpr::ResolveContext context{symtab, transUnit().global};
+            auto result = ResolvExpr::findVoidExpression(untyped, context);
+            if (result.get()) {
+                ast::ptr<ast::ApplicationExpr> ret =
+                    result.strict_as<ast::ApplicationExpr>();
+                return new ast::ApplicationExpr(*ret);
+            }
+        }
+    }
+    return expr;
+}
 
 void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
@@ -48,10 +115,4 @@
 }
 
-struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
-                                         public ast::WithSymbolTable,
-                                         public ast::WithShortCircuiting {
-    void previsit(const ast::EnumDecl* enumDecl);
-};
-
 void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
     visit_children = false;
@@ -67,13 +128,14 @@
             location, ast::ConstantExpr::from_string(location, mem->name)));
     }
+    // Values only
     if (queryValues.count(enumDecl->name)) {
         auto init = new ast::ListInit(location, std::move(inits));
-        auto values = new ast::ObjectDecl(
-            location, "values_" + enumDecl->name,
-            new ast::ArrayType(
-                enumDecl->base,
-                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
-                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
-            init, ast::Storage::Static, ast::Linkage::AutoGen);
+        const ast::ArrayType* arrT = new ast::ArrayType(
+            enumDecl->base,
+            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
+            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
+        ast::ObjectDecl* values = new ast::ObjectDecl(
+            location, "values_" + enumDecl->name, arrT, init,
+            ast::Storage::Static, ast::Linkage::AutoGen);
         symtab.addId(values);
         values->mangleName = Mangle::mangle(values);
@@ -82,5 +144,5 @@
     if (queryLabels.count(enumDecl->name)) {
         auto label_strings = new ast::ListInit(location, std::move(labels));
-        auto label_arr = new ast::ObjectDecl(
+        auto labels = new ast::ObjectDecl(
             location, "labels_" + enumDecl->name,
             new ast::ArrayType(
@@ -89,15 +151,26 @@
                 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
             label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
-        symtab.addId(label_arr);
-        label_arr->mangleName = Mangle::mangle(label_arr);
-        declsToAddAfter.push_back(label_arr);
-    }
-}
-
-struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
-                               public ast::WithSymbolTable,
-                               public ast::WithConstTranslationUnit {
-    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
-};
+        symtab.addId(labels);
+        labels->mangleName = Mangle::mangle(labels);
+        declsToAddAfter.push_back(labels);
+    }
+}
+
+ast::ApplicationExpr const* getPseudoFuncApplication(
+    const CodeLocation location, ResolvExpr::ResolveContext context,
+    const ast::VariableExpr* arg, const ast::EnumDecl* base, const std::string & name) {
+    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
+    auto result = ResolvExpr::findVoidExpression(toResolve, context);
+    assert(result.get());
+    auto arrAsVar = result.strict_as<ast::VariableExpr>();
+    auto untyped = new ast::UntypedExpr(
+        location, new ast::NameExpr(location, "?[?]"),
+        {new ast::VariableExpr(*arrAsVar), new ast::VariableExpr(*arg)});
+    auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
+
+    ast::ptr<ast::ApplicationExpr> ret =
+        typedResult.strict_as<ast::ApplicationExpr>();
+    return ast::deepCopy(ret);
+}
 
 ast::Expr const* ReplacePseudoFuncCore::postvisit(
@@ -125,4 +198,6 @@
         }
         const ast::EnumDecl* base = argType->base;
+        ResolvExpr::ResolveContext context{symtab, transUnit().global};
+        // If resolvable as constant
         for (size_t i = 0; i < base->members.size(); i++) {
             if (base->members[i]->name == referredName) {
@@ -133,56 +208,21 @@
                                                           referredName);
                 else
-                    return new ast::TypeExpr(expr->location, argType);
-            }
-        }
-
-        ResolvExpr::ResolveContext context{symtab, transUnit().global};
+                    return getPseudoFuncApplication(location, context, arg.get(),
+                                               base, "values_");
+            }
+        }
 
         if (fname == "labelE") {
-            ast::Expr* toResolve =
-                new ast::NameExpr(expr->location, "labels_" + base->name);
-            auto result = ResolvExpr::findVoidExpression(toResolve, context);
-            if (result.get()) {
-                auto arrAsVar = result.strict_as<ast::VariableExpr>();
-                auto untyped = new ast::UntypedExpr(
-                    location, new ast::NameExpr(location, "?[?]"),
-                    {new ast::VariableExpr(*arrAsVar),
-                     ast::ConstantExpr::from_int(
-                         location,
-                         0)});  /// TODO: dummy value.
-                                /// To make it works need to change the unifier
-
-                auto typedResult =
-                    ResolvExpr::findVoidExpression(untyped, context);
-                if (result.get()) {
-                    ast::ptr<ast::ApplicationExpr> ret =
-                        typedResult.strict_as<ast::ApplicationExpr>();
-                    return new ast::ApplicationExpr(*ret);
-                }
-            }
-        }
-        
-        if (fname == "valueE") {
-            ast::Expr* toResolve =
-                new ast::NameExpr(expr->location, "values_" + base->name);
-            auto result = ResolvExpr::findVoidExpression(toResolve, context);
-            if (result.get()) {
-                auto arrAsVar = result.strict_as<ast::VariableExpr>();
-                auto untyped = new ast::UntypedExpr(
-                    location, new ast::NameExpr(location, "?[?]"),
-                    {new ast::VariableExpr(*arrAsVar),
-                     ast::ConstantExpr::from_int(
-                         location,
-                         0)});  /// TODO: dummy value.
-                                /// To make it works need to change the unifier
-
-                auto typedResult =
-                    ResolvExpr::findVoidExpression(untyped, context);
-                if (result.get()) {
-                    ast::ptr<ast::ApplicationExpr> ret =
-                        typedResult.strict_as<ast::ApplicationExpr>();
-                    return new ast::ApplicationExpr(*ret);
-                }
-            }
+            if (auto labelExpr =
+                    getPseudoFuncApplication(location, context, arg.get(), base, "labels_")) {
+                return labelExpr;
+            }
+        } else if (fname == "valueE") {
+            if (auto valueExpr =
+                    getPseudoFuncApplication(location, context, arg.get(), base, "values_")) {
+                return valueExpr;
+            }
+        } else { // it is position; replace itself
+            return std::move( arg.get() );
         }
     }
@@ -193,4 +233,5 @@
 
 void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
+    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
     ast::Pass<FindGenEnumArray>::run(translationUnit);
     ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
