Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision 9d6e7fa948fdd351c0915596d485db84188965be)
+++ src/Common/Eval.cc	(revision d7aa12cdc492280c782bdc2eda1f42fba8598ec9)
@@ -17,8 +17,11 @@
 
 #include "Common/PassVisitor.h"
+#include "AST/Pass.hpp"
 #include "InitTweak/InitTweak.h"
 #include "SynTree/Expression.h"
 
-struct Eval : public WithShortCircuiting {
+//-------------------------------------------------------------
+// Old AST
+struct EvalOld : public WithShortCircuiting {
 	long long int value = 0;
 	bool valid = true;
@@ -80,6 +83,68 @@
 };
 
+//-------------------------------------------------------------
+// New AST
+struct EvalNew : public ast::WithShortCircuiting {
+	long long int value = 0;
+	bool valid = true;
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+	void postvisit( const ast::Node * ) { valid = false; }
+
+	void postvisit( const ast::ConstantExpr * expr ) {
+		value = expr->intValue();
+	}
+
+	void postvisit( const ast::CastExpr * expr ) {
+		auto arg = eval(expr->arg);
+		valid = arg.second;
+		value = arg.first;
+		// TODO: perform type conversion on value if valid
+	}
+
+	void postvisit( const ast::VariableExpr * expr ) {
+		if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
+			if ( const ast::EnumDecl * decl = inst->base ) {
+				if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
+					return;
+				}
+			}
+		}
+		valid = false;
+	}
+
+	void postvisit( const ast::ApplicationExpr * expr ) {
+		const ast::DeclWithType * function = InitTweak::getFunction(expr);
+		if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; }
+		const std::string & fname = function->name;
+		assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
+		std::pair<long long int, bool> arg1, arg2;
+		arg1 = eval(expr->args.front());
+		valid = valid && arg1.second;
+		if ( ! valid ) return;
+		if ( expr->args.size() == 2 ) {
+			arg2 = eval(expr->args.back());
+			valid = valid && arg2.second;
+			if ( ! valid ) return;
+		}
+		if (fname == "?+?") {
+			value = arg1.first + arg2.first;
+		} else if (fname == "?-?") {
+			value = arg1.first - arg2.first;
+		} else if (fname == "?*?") {
+			value = arg1.first * arg2.first;
+		} else if (fname == "?/?") {
+			value = arg1.first / arg2.first;
+		} else if (fname == "?%?") {
+			value = arg1.first % arg2.first;
+		} else {
+			valid = false;
+		}
+		// TODO: implement other intrinsic functions
+	}
+};
+
 std::pair<long long int, bool> eval(Expression * expr) {
-	PassVisitor<Eval> ev;
+	PassVisitor<EvalOld> ev;
 	if (expr) {
 		expr->accept(ev);
@@ -91,6 +156,11 @@
 
 std::pair<long long int, bool> eval(const ast::Expr * expr) {
-	#warning not implemented
-	return { 0, false };
+	ast::Pass<EvalNew> ev;
+	if (expr) {
+		expr->accept(ev);
+		return std::make_pair(ev.pass.value, ev.pass.valid);
+	} else {
+		return std::make_pair(0, false);
+	}
 }
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 9d6e7fa948fdd351c0915596d485db84188965be)
+++ src/InitTweak/InitTweak.cc	(revision d7aa12cdc492280c782bdc2eda1f42fba8598ec9)
@@ -346,4 +346,5 @@
 	namespace {
 		DeclarationWithType * getCalledFunction( Expression * expr );
+		const ast::DeclWithType * getCalledFunction( const ast::Expr * expr );
 
 		template<typename CallExpr>
@@ -355,4 +356,14 @@
 			return getCalledFunction( expr->get_args().front() );
 		}
+
+		template<typename CallExpr>
+		const ast::DeclWithType * handleDerefCalledFunction( const CallExpr * expr ) {
+			// (*f)(x) => should get "f"
+			std::string name = getFunctionName( expr );
+			assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
+			assertf( ! expr->args.empty(), "Cannot get called function from dereference with no arguments" );
+			return getCalledFunction( expr->args.front() );
+		}
+
 
 		DeclarationWithType * getCalledFunction( Expression * expr ) {
@@ -375,4 +386,24 @@
 			return nullptr;
 		}
+
+		const ast::DeclWithType * getCalledFunction( const ast::Expr * expr ) {
+			assert( expr );
+			if ( const ast::VariableExpr * varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) {
+				return varExpr->var;
+			} else if ( const ast::MemberExpr * memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) {
+				return memberExpr->member;
+			} else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
+				return getCalledFunction( castExpr->arg );
+			} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * >( expr ) ) {
+				return handleDerefCalledFunction( untypedExpr );
+			} else if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * > ( expr ) ) {
+				return handleDerefCalledFunction( appExpr );
+			} else if ( const ast::AddressExpr * addrExpr = dynamic_cast< const ast::AddressExpr * >( expr ) ) {
+				return getCalledFunction( addrExpr->arg );
+			} else if ( const ast::CommaExpr * commaExpr = dynamic_cast< const ast::CommaExpr * >( expr ) ) {
+				return getCalledFunction( commaExpr->arg2 );
+			}
+			return nullptr;
+		}
 	}
 
@@ -382,4 +413,13 @@
 		} else if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * > ( expr ) ) {
 			return getCalledFunction( untyped->get_function() );
+		}
+		assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
+	}
+
+	const ast::DeclWithType * getFunction( const ast::Expr * expr ) {
+		if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr ) ) {
+			return getCalledFunction( appExpr->func );
+		} else if ( const ast::UntypedExpr * untyped = dynamic_cast< const ast::UntypedExpr * > ( expr ) ) {
+			return getCalledFunction( untyped->func );
 		}
 		assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
@@ -492,4 +532,5 @@
 	namespace {
 		std::string funcName( Expression * func );
+		std::string funcName( const ast::Expr * func );
 
 		template<typename CallExpr>
@@ -500,4 +541,13 @@
 			assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
 			return funcName( expr->get_args().front() );
+		}
+
+		template<typename CallExpr>
+		std::string handleDerefName( const CallExpr * expr ) {
+			// (*f)(x) => should get name "f"
+			std::string name = getFunctionName( expr );
+			assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
+			assertf( ! expr->args.empty(), "Cannot get function name from dereference with no arguments" );
+			return funcName( expr->args.front() );
 		}
 
@@ -523,4 +573,26 @@
 			}
 		}
+
+		std::string funcName( const ast::Expr * func ) {
+			if ( const ast::NameExpr * nameExpr = dynamic_cast< const ast::NameExpr * >( func ) ) {
+				return nameExpr->name;
+			} else if ( const ast::VariableExpr * varExpr = dynamic_cast< const ast::VariableExpr * >( func ) ) {
+				return varExpr->var->name;
+			}	else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( func ) ) {
+				return funcName( castExpr->arg );
+			} else if ( const ast::MemberExpr * memberExpr = dynamic_cast< const ast::MemberExpr * >( func ) ) {
+				return memberExpr->member->name;
+			} else if ( const ast::UntypedMemberExpr * memberExpr = dynamic_cast< const ast::UntypedMemberExpr * > ( func ) ) {
+				return funcName( memberExpr->member );
+			} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * >( func ) ) {
+				return handleDerefName( untypedExpr );
+			} else if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( func ) ) {
+				return handleDerefName( appExpr );
+			} else if ( const ast::ConstructorExpr * ctorExpr = dynamic_cast< const ast::ConstructorExpr * >( func ) ) {
+				return funcName( getCallArg( ctorExpr->callExpr, 0 ) );
+			} else {
+				assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
+			}
+		}
 	}
 
@@ -533,4 +605,18 @@
 		} else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {
 			return funcName( untypedExpr->get_function() );
+		} else {
+			std::cerr << expr << std::endl;
+			assertf( false, "Unexpected expression type passed to getFunctionName" );
+		}
+	}
+
+	std::string getFunctionName( const ast::Expr * expr ) {
+		// there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
+		// return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
+		// can't possibly do anything reasonable.
+		if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr ) ) {
+			return funcName( appExpr->func );
+		} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * > ( expr ) ) {
+			return funcName( untypedExpr->func );
 		} else {
 			std::cerr << expr << std::endl;
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision 9d6e7fa948fdd351c0915596d485db84188965be)
+++ src/InitTweak/InitTweak.h	(revision d7aa12cdc492280c782bdc2eda1f42fba8598ec9)
@@ -79,4 +79,5 @@
 	/// returns the name of the function being called
 	std::string getFunctionName( Expression * expr );
+	std::string getFunctionName( const ast::Expr * expr );
 
 	/// returns the argument to a call expression in position N indexed from 0
