Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 544deb9e858ecd53a7b4d97ac4ac077c84729e37)
+++ src/Validate/Autogen.cpp	(revision c75b30ae4d3f97678f27275a033614f675b7fdaf)
@@ -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 544deb9e858ecd53a7b4d97ac4ac077c84729e37)
+++ src/Validate/ReplacePseudoFunc.cpp	(revision c75b30ae4d3f97678f27275a033614f675b7fdaf)
@@ -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);
