Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Convert.cpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -704,58 +704,24 @@
 	}
 
-	bool isIntlikeConstantType(const ast::Type *t) {
-		if ( const ast::BasicType * basicType = dynamic_cast< const ast::BasicType * >( t ) ) {
-			if ( basicType->isInteger() ) {
-				return true;
-			}
-		} else if ( dynamic_cast< const ast::OneType * >( t ) ) {
-			return true;
-		} else if ( dynamic_cast< const ast::ZeroType * >( t ) ) {
-			return true;
-		} else if ( dynamic_cast< const ast::PointerType * >( t ) ) {
-			// null pointer constants, with zero int-values
-			return true;
-		}
-		return false;
-	}
-
-	bool isFloatlikeConstantType(const ast::Type *t) {
-		if ( const ast::BasicType * bty = dynamic_cast< const ast::BasicType * >( t ) ) {
-			if ( ! bty->isInteger() ) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	bool isStringlikeConstantType(const ast::Type *t) {
-		if ( const ast::ArrayType * aty = dynamic_cast< const ast::ArrayType * >( t ) ) {
-			if ( const ast::BasicType * bty = aty->base.as<ast::BasicType>() ) {
-			   if ( bty->kind == ast::BasicType::Kind::Char ) {
-				   return true;
-			   }
-			}
-		}
-		return false;
-	}
-
 	const ast::Expr * visit( const ast::ConstantExpr * node ) override final {
 		ConstantExpr *rslt = nullptr;
-		if (isIntlikeConstantType(node->result)) {
-			rslt = new ConstantExpr(Constant(
-				get<Type>().accept1(node->result),
+		switch ( node->kind ) {
+		case ast::ConstantExpr::Integer:
+			rslt = new ConstantExpr{Constant{
+				get<Type>().accept1( node->result ),
 				node->rep,
 				(unsigned long long) node->intValue()
-			));
-		} else if (isFloatlikeConstantType(node->result)) {
-			rslt = new ConstantExpr(Constant(
+			}};
+			break;
+		case ast::ConstantExpr::FloatingPoint:
+			rslt = new ConstantExpr{Constant{
 				get<Type>().accept1(node->result),
 				node->rep,
 				(double) node->floatValue()
-			));
-		} else if (isStringlikeConstantType(node->result)) {
-			rslt = new ConstantExpr(Constant::from_string(
-				node->rep
-			));
+			}};
+			break;
+		case ast::ConstantExpr::String:
+			rslt = new ConstantExpr{Constant::from_string( node->rep )};
+			break;
 		}
 		assert(rslt);
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Decl.cpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -72,8 +72,8 @@
 // --- EnumDecl
 
-bool EnumDecl::valueOf( Decl* enumerator, long long& value ) const {
+bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const {
 	if ( enumValues.empty() ) {
 		long long crntVal = 0;
-		for ( const Decl* member : members ) {
+		for ( const Decl * member : members ) {
 			const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
 			if ( field->init ) {
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Decl.hpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -287,5 +287,5 @@
 
 	/// gets the integer value for this enumerator, returning true iff value found
-	bool valueOf( Decl* enumerator, long long& value ) const;
+	bool valueOf( const Decl * enumerator, long long& value ) const;
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Expr.cpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -241,5 +241,6 @@
 			FixedLen, DynamicDim },
 		std::string{"\""} + s + "\"",
-		(unsigned long long)0 };
+		(unsigned long long)0,
+		ConstantExpr::String };
 }
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Expr.hpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -337,10 +337,12 @@
 public:
 	std::string rep;
+	enum Kind { Integer, FloatingPoint, String } kind;
 
 	ConstantExpr(
-		const CodeLocation & loc, const Type * ty, const std::string & r, unsigned long long v )
-	: Expr( loc, ty ), val( v ), rep( r ) {}
+		const CodeLocation & loc, const Type * ty, const std::string & r, unsigned long long v,
+		Kind k = Integer )
+	: Expr( loc, ty ), val( v ), rep( r ), kind( k ) {}
 	ConstantExpr( const CodeLocation & loc, const Type * ty, const std::string & r, double v )
-	: Expr( loc, ty ), val( v ), rep( r ) {}
+	: Expr( loc, ty ), val( v ), rep( r ), kind( FloatingPoint ) {}
 
 	/// Gets the value of this constant as an integer
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Pass.proto.hpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -109,4 +109,6 @@
 	};
 
+	/// "Short hand" to check if this is a valid previsit function
+	/// Mostly used to make the static_assert look (and print) prettier
 	template<typename pass_t, typename node_t>
 	struct is_valid_previsit {
@@ -117,4 +119,7 @@
 	};
 
+	/// Used by previsit implementation
+	/// We need to reassign the result to 'node', unless the function
+	/// returns void, then we just leave 'node' unchanged
 	template<bool is_void>
 	struct __assign;
@@ -134,4 +139,27 @@
 			node = pass.previsit( node );
 			assertf(node, "Previsit must not return NULL");
+		}
+	};
+
+	/// Used by postvisit implementation
+	/// We need to return the result unless the function
+	/// returns void, then we just return the original node
+	template<bool is_void>
+	struct __return;
+
+	template<>
+	struct __return<true> {
+		template<typename pass_t, typename node_t>
+		static inline const node_t * result( pass_t & pass, const node_t * & node ) {
+			pass.postvisit( node );
+			return node;
+		}
+	};
+
+	template<>
+	struct __return<false> {
+		template<typename pass_t, typename node_t>
+		static inline auto result( pass_t & pass, const node_t * & node ) {
+			return pass.postvisit( node );
 		}
 	};
@@ -174,5 +202,9 @@
 		decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
 	{
-		return pass.postvisit( node );
+		return __return<
+			std::is_void<
+				decltype( pass.postvisit( node ) )
+			>::value
+		>::result( pass, node );
 	}
 
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Print.cpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -59,4 +59,23 @@
 	}
 
+	/// call if mandatory field is missing
+	void undefined() {
+		os << "UNDEFINED";
+	}
+
+	/// call for fields that should be mandatory
+	void safe_print( const ast::Node * n ) {
+		if ( n ) n->accept( *this );
+		else undefined();
+	}
+
+	/// call to print short form. Incorporates features of safe_print()
+	void short_print( const ast::Node * n ) {
+		if ( ! n ) { undefined(); return; }
+		bool old_short = short_mode; short_mode = true;
+		n->accept( *this );
+		short_mode = old_short;
+	}
+
 
 	static const char* Names[];
@@ -99,4 +118,52 @@
 	}
 
+	void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
+		switch ( inferred.mode ) {
+		case ast::Expr::InferUnion::Empty: return;
+		case ast::Expr::InferUnion::Slots: {
+			os << indent << "with " << inferred.data.resnSlots.size() << " pending inference slots" 
+			   << std::endl;
+			return;
+		}
+		case ast::Expr::InferUnion::Params: {
+			os << indent << "with inferred parameters " << level << ":" << std::endl;
+			++indent;
+			for ( const auto & i : inferred.data.inferParams ) {
+				os << indent;
+				short_print( Decl::fromId( i.second.decl ) );
+				os << std::endl;
+				print( i.second.expr->inferred, level+1 );
+			}
+			--indent;
+			return;
+		}
+		}
+	}
+
+	void print( const ast::ParameterizedType::ForallList & forall ) {
+		if ( forall.empty() ) return;	
+		os << "forall" << std::endl;
+		++indent;
+		printAll( forall );
+		os << indent;
+		--indent;
+	}
+
+	void print( const std::vector<ptr<Attribute>> & attrs ) {
+		if ( attrs.empty() ) return;
+		os << "with attributes" << std::endl;
+		++indent;
+		printAll( attrs );
+		--indent;
+	}
+
+	void print( const std::vector<ptr<Expr>> & params ) {
+		if ( params.empty() ) return;
+		os << std::endl << indent << "... with parameters" << std::endl;
+		++indent;
+		printAll( params );
+		--indent;
+	}
+
 	void print( const ast::AggregateDecl * node ) {
 		os << node->typeString() << " " << node->name << ":";
@@ -155,4 +222,34 @@
 	}
 
+	void postprint( const ast::Expr * node ) {
+		print( node->inferred );
+
+		if ( node->env ) {
+			os << std::endl << indent << "... with environment:" << std::endl;
+			++indent;
+			node->env->accept( *this );
+			--indent;
+		}
+		
+		if ( node->extension ) {
+			os << std::endl << indent << "... with extension";
+		}
+	}
+
+	void preprint( const ast::Type * node ) {
+		print( node->qualifiers );
+	}
+
+	void preprint( const ast::ParameterizedType * node ) {
+		print( node->forall );
+		print( node->qualifiers );
+	}
+
+	void preprint( const ast::ReferenceToType * node ) {
+		print( node->forall );
+		print( node->attributes );
+		print( node->qualifiers );
+	}
+
 public:
 	virtual const ast::DeclWithType * visit( const ast::ObjectDecl * node ) {
@@ -168,5 +265,5 @@
 			node->type->accept( *this );
 		} else {
-			os << " untyped entity ";
+			os << "untyped entity";
 		} // if
 
@@ -214,5 +311,5 @@
 			node->type->accept( *this );
 		} else {
-			os << "untyped entity ";
+			os << "untyped entity";
 		} // if
 
@@ -291,5 +388,5 @@
 		++indent;
 		os << "Expression Statement:" << endl << indent;
-		node->expr->accept( *this );
+		safe_print( node->expr );
 		--indent;
 		return node;
@@ -326,5 +423,5 @@
 		os << indent+1;
 		++indent;
-		node->cond->accept( *this );
+		safe_print( node->cond );
 		--indent;
 
@@ -344,5 +441,5 @@
 		++indent;
 		os << indent;
-		node->thenPart->accept( *this );
+		safe_print( node->thenPart );
 		--indent;
 
@@ -418,48 +515,144 @@
 
 	virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) {
+		++indent;
+		os << "Application of" << std::endl << indent;
+		safe_print( node->func );
+		os << std::endl;
+		if ( ! node->args.empty() ) {
+			os << indent << "... to arguments" << std::endl;
+			printAll( node->args );
+		}
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::UntypedExpr * node ) {
+		++indent;
+		os << "Applying untyped:" << std::endl;
+		os << indent;
+		safe_print( node->func );
+		os << std::endl << indent-1 << "...to:" << std::endl;
+		printAll( node->args );
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::NameExpr * node ) {
+		os << "Name: " << node->name;
+		postprint( node );
+		
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::AddressExpr * node ) {
+		os << "Address of:" << std::endl;
+		++indent;
+		os << indent;
+		safe_print( node->arg );
+
+		--indent;
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::LabelAddressExpr * node ) {
+		os << "Address of label:" << node->arg;
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::CastExpr * node ) {
+		++indent;
+		os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << std::endl << indent;
+		safe_print( node->arg );
+		os << std::endl << indent-1 << "... to:";
+		if ( ! node->result ) {
+			os << " ";
+			undefined();
+		} else if ( node->result->isVoid() ) {
+			os << " nothing";
+		} else {
+			os << std::endl << indent;
+			node->result->accept( *this );
+		} // if
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::KeywordCastExpr * node ) {
+		++indent;
+		os << "Keyword Cast of:" << std::endl << indent;
+		safe_print( node->arg );
+		--indent;
+		os << std::endl << indent << "... to: " << node->targetString();
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::VirtualCastExpr * node ) {
+		++indent;
+		os << "Virtual Cast of:" << std::endl << indent;
+		safe_print( node->arg );
+		os << std::endl << indent-1 << "... to:";
+		if ( ! node->result ) {
+			os << " unknown";
+		} else {
+			os << std::endl << indent;
+			node->result->accept( *this );
+		}
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::UntypedMemberExpr * node ) {
+		++indent;
+		os << "Untyped Member Expression, with field: " << std::endl << indent;
+		safe_print( node->member );
+		os << indent-1 << "... from aggregate:" << std::endl << indent;
+		safe_print( node->aggregate );
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::MemberExpr * node ) {
+		++indent;
+		os << "Member Expression, with field:" << std::endl << indent;
+		safe_print( node->member );
+		os << std::endl << indent-1 << "... from aggregate:" << std::endl << indent;
+		safe_print( node->aggregate );
+		--indent;
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::VariableExpr * node ) {
+		os << "Variable Expression: ";
+		short_print( node->var );
+		postprint( node );
+
 		return node;
 	}
 
 	virtual const ast::Expr * visit( const ast::ConstantExpr * node ) {
+		os << "Constant Expression (" << node->rep;
+		if ( node->result ) {
+			os << ": ";
+			node->result->accept( *this );
+		}
+		os << ")";
+		postprint( node );
+
 		return node;
 	}
@@ -566,72 +759,202 @@
 
 	virtual const ast::Type * visit( const ast::VoidType * node ) {
+		preprint( node );
+		os << "void";
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::BasicType * node ) {
+		preprint( node );
+		os << ast::BasicType::typeNames[ node->kind ];
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::PointerType * node ) {
+		preprint( node );
+		if ( ! node->isArray() ) {
+			os << "pointer to ";
+		} else {
+			os << "decayed ";
+			if ( node->isStatic ) {
+				os << "static ";
+			}
+
+			if ( node->isVarLen ) {
+				os << "variable length array of ";
+			} else if ( node->dimension ) {
+				os << "array of ";
+				node->dimension->accept( *this );
+				os << " ";
+			}
+		}
+		safe_print( node->base );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::ArrayType * node ) {
+		preprint( node );
+		if ( node->isStatic ) {
+			os << "static ";
+		}
+
+		if ( node->isVarLen ) {
+			os << "variable length array of ";
+		} else if ( node->dimension ) {
+			os << "array of ";
+		} else {
+			os << "open array of ";
+		}
+
+		safe_print( node->base );
+
+		if ( node->dimension ) {
+			os << " with dimension of ";
+			node->dimension->accept( *this );
+		}
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::ReferenceType * node ) {
+		preprint( node );
+		os << "reference to ";
+		safe_print( node->base );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::QualifiedType * node ) {
+		preprint( node );
+		++indent;
+		os << "Qualified Type:" << std::endl << indent;
+		safe_print( node->parent );
+		os << std::endl << indent;
+		safe_print( node->child );
+		os << std::endl;
+		--indent;
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::FunctionType * node ) {
+		preprint( node );
+		
+		os << "function" << std::endl;
+		if ( ! node->params.empty() ) {
+			os << indent << "... with parameters" << std::endl;
+			++indent;
+			printAll( node->params );
+			if ( node->isVarArgs ) {
+				os << indent << "and a variable number of other arguments" << std::endl;
+			}
+			--indent;
+		} else if ( node->isVarArgs ) {
+			os << indent+1 << "accepting unspecified arguments" << std::endl;
+		}
+
+		os << indent << "... returning";
+		if ( node->returns.empty() ) {
+			os << " nothing" << std::endl;
+		} else {
+			os << std::endl;
+			++indent;
+			printAll( node->returns );
+			--indent;
+		}
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::StructInstType * node ) {
+		preprint( node );
+		os << "instance of struct " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::UnionInstType * node ) {
+		preprint( node );
+		os << "instance of union " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::EnumInstType * node ) {
+		preprint( node );
+		os << "instance of enum " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::TraitInstType * node ) {
+		preprint( node );
+		os << "instance of trait " << node->name;
+		print( node->params );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::TypeInstType * node ) {
+		preprint( node );
+		os << "instance of type " << node->name 
+		   << " (" << (node->kind == ast::TypeVar::Ftype ? "" : "not ") << "function type)";
+		print( node->params );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::TupleType * node ) {
+		preprint( node );
+		os << "tuple of types" << std::endl;
+		++indent;
+		printAll( node->types );
+		--indent;
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::TypeofType * node ) {
+		preprint( node );
+		if ( node->kind == ast::TypeofType::Basetypeof ) { os << "base-"; }
+		os << "type-of expression ";
+		safe_print( node->expr );
+
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::VarArgsType * node ) {
+		preprint( node );
+		os << "builtin var args pack";
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::ZeroType * node ) {
+		preprint( node );
+		os << "zero_t";
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::OneType * node ) {
+		preprint( node );
+		os << "one_t";
 		return node;
 	}
 
 	virtual const ast::Type * visit( const ast::GlobalScopeType * node ) {
+		preprint( node );
+		os << "Global Scope Type";
 		return node;
 	}
@@ -652,5 +975,5 @@
 	virtual const ast::Init * visit( const ast::SingleInit * node ) {
 		os << "Simple Initializer: ";
-		node->value->accept( *this );
+		safe_print( node->value );
 		return node;
 	}
@@ -715,5 +1038,5 @@
 			os << indent+1 << i.first << " -> ";
 			indent += 2;
-			i.second->accept( *this );
+			safe_print( i.second );
 			indent -= 2;
 			os << std::endl;
@@ -723,5 +1046,5 @@
 			os << indent+1 << i->first << " -> ";
 			indent += 2;
-			i->second->accept( *this );
+			safe_print( i->second );
 			indent -= 2;
 			os << std::endl;
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/AST/Type.hpp	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -308,8 +308,4 @@
 	virtual ReferenceToType * clone() const override = 0;
 	MUTATE_FRIEND
-
-protected:
-	/// Name for the kind of type this is
-	virtual std::string typeString() const = 0;
 };
 
@@ -333,6 +329,4 @@
 	StructInstType * clone() const override { return new StructInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "struct"; }
 };
 
@@ -356,6 +350,4 @@
 	UnionInstType * clone() const override { return new UnionInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "union"; }
 };
 
@@ -379,6 +371,4 @@
 	EnumInstType * clone() const override { return new EnumInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "enum"; }
 };
 
@@ -403,6 +393,4 @@
 	TraitInstType * clone() const override { return new TraitInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "trait"; }
 };
 
@@ -432,6 +420,4 @@
 	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "type"; }
 };
 
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/Common/Eval.cc	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -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/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/Common/PassVisitor.impl.h	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -23,21 +23,4 @@
 	assert( __return ); \
 	return __return;
-
-
-#define VISIT_BODY( node )          \
-	VISIT_START( node );          \
-	if( children_guard ) {        \
-		Visitor::visit( node ); \
-	}                             \
-	VISIT_END( node );            \
-
-
-#define MUTATE_BODY( type, node )    \
-	MUTATE_START( node );          \
-	if( children_guard ) {         \
-		Mutator::mutate( node ); \
-	}                              \
-	MUTATE_END( type, node );      \
-
 
 
@@ -2762,2 +2745,8 @@
 	MUTATE_END( TypeSubstitution, node );
 }
+
+#undef VISIT_START
+#undef VISIT_END
+
+#undef MUTATE_START
+#undef MUTATE_END
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/InitTweak/InitTweak.cc	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -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() );
@@ -434,16 +474,16 @@
 		}
 
-		// template<typename CallExpr>
-		// const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
-		// 	if( pos >= call->args.size() ) {
-		// 		assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
-		// 			pos, toString( call ).c_str() );
-		// 	}
-		// 	for ( const ast::Expr * arg : call->args ) {
-		// 		if ( pos == 0 ) return arg;
-		// 		--pos;
-		// 	}
-		// 	assert( false );
-		// }
+		template<typename CallExpr>
+		const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
+			if( pos >= call->args.size() ) {
+				assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
+					pos, toString( call ).c_str() );
+			}
+			for ( const ast::Expr * arg : call->args ) {
+				if ( pos == 0 ) return arg;
+				--pos;
+			}
+			assert( false );
+		}
 	}
 
@@ -466,30 +506,28 @@
 		}
 	}
+
 	const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ) {
-		(void)call;
-		(void)pos;
-		#warning unimplemented; needs to build AST/Expr.cpp
-		assertf(false, "unimplemented; needs to build AST/Expr.cpp");
-		// if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
-		// 	return callArg( app, pos );
-		// } else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) {
-		// 	return callArg( untyped, pos );
-		// } else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) {
-		// 	const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
-		// 	assertf( ! stmts.empty(), "TupleAssignExpr missing statements." );
-		// 	const ExprStmt * stmt = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back() );
-		// 	const TupleExpr * tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr );
-		// 	assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr.");
-		// 	return getCallArg( tuple->exprs.front(), pos );
-		// } else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) {
-		// 	return getCallArg( ctor->callExpr, pos );
-		// } else {
-		// 	assertf( false, "Unexpected expression type passed to getCallArg: %s",
-		// 		toString( call ).c_str() );
-		// }
+		if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
+			return callArg( app, pos );
+		} else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) {
+			return callArg( untyped, pos );
+		} else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) {
+			const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
+			assertf( ! stmts.empty(), "TupleAssignExpr missing statements." );
+			auto stmt  = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back().get() );
+			auto tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr.get() );
+			assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr.");
+			return getCallArg( tuple->exprs.front(), pos );
+		} else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) {
+			return getCallArg( ctor->callExpr, pos );
+		} else {
+			assertf( false, "Unexpected expression type passed to getCallArg: %s",
+				toString( call ).c_str() );
+		}
 	}
 
 	namespace {
 		std::string funcName( Expression * func );
+		std::string funcName( const ast::Expr * func );
 
 		template<typename CallExpr>
@@ -500,4 +538,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 +570,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() );
+			}
+		}
 	}
 
@@ -539,4 +608,18 @@
 	}
 
+	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;
+			assertf( false, "Unexpected expression type passed to getFunctionName" );
+		}
+	}
+
 	Type * getPointerBase( Type * type ) {
 		if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
@@ -551,14 +634,11 @@
 	}
 	const ast::Type* getPointerBase( const ast::Type* t ) {
-		(void)t;
-		#warning needs to build Type.cpp before inclusion
-		assertf(false, "needs to build Type.cpp before inclusion");
-		// if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
-		// 	return p->base;
-		// } else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) {
-		// 	return a->base;
-		// } else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) {
-		// 	return r->base;
-		// } else return nullptr;
+		if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
+			return p->base;
+		} else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) {
+			return a->base;
+		} else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) {
+			return r->base;
+		} else return nullptr;
 	}
 
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision f685679ccf556a852ac2dfac5c217d0fcf9ca7f1)
+++ src/InitTweak/InitTweak.h	(revision f1ec88a6b136c00098465416ce6f8b43bdba50ac)
@@ -58,4 +58,5 @@
 	/// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
 	DeclarationWithType * getFunction( Expression * expr );
+	const ast::DeclWithType * getFunction( const ast::Expr * expr );
 
 	/// Non-Null if expr is a call expression whose target function is intrinsic
@@ -78,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
