Index: .poseidon
==================================================================
--- .poseidon
+++ .poseidon
@@ -31,14 +31,16 @@
 				<name>d2stacktrace\dbghelp.d</name>
 				<name>d2stacktrace\stacktrace.d</name>
 				<name>main.d</name>
 				<name>polemy\_common.d</name>
 				<name>polemy\ast.d</name>
+				<name>polemy\eval.d</name>
 				<name>polemy\lex.d</name>
 				<name>polemy\parse.d</name>
-				<name>polemy\tricks.d</name>
 				<name>polemy\value.d</name>
+				<name>tricks\test.d</name>
+				<name>tricks\tricks.d</name>
 			</source>
 			<interface />
 			<resource />
 			<othersDMD />
 			<others>

Index: build.bat
==================================================================
--- build.bat
+++ build.bat
@@ -1,6 +1,6 @@
 @setlocal ENABLEDELAYEDEXPANSION
 @set ARGS=
-@for %%I in (main.d polemy\*.d) do @set ARGS=!ARGS! %%I
+@for %%I in (main.d polemy\*.d tricks\*.d) do @set ARGS=!ARGS! %%I
 @if not exist bin mkdir bin
 @echo dmd -ofbin\polemy.exe -O -release -inline %ARGS%
 @dmd -ofbin\polemy.exe -O -release -inline %ARGS%

Index: d2stacktrace/stacktrace.d
==================================================================
--- d2stacktrace/stacktrace.d
+++ d2stacktrace/stacktrace.d
@@ -238,11 +238,11 @@
 	static Throwable.TraceInfo TraceHandler(void* ptr){
 		// modified by k.inaba to avoid a throw inside std.demangle.demangle
 		// not quite thread safe
 		Runtime.traceHandler(&core.runtime.defaultTraceHandler);
 		scope(exit) Runtime.traceHandler(&TraceHandler);
-	  
+
 		StackTrace trace = new StackTrace();
 		return trace.GetCallstack();
 	}
 	
 public:
@@ -341,11 +341,11 @@
 					memcpy(symName.ptr,Symbol.Name.ptr,symName.length);
 					string symString = "";
 					if(symName[0] == 'D')
 						symString = "_";
 					symString ~= symName;
-					
+
 					string demangeledName = demangle(symString);
 					lineStr ~= demangeledName;
 
 					DWORD zeichen = 0;
 					if(Dbghelp.SymGetLineFromAddr64(hProcess,stackframe.AddrPC.Offset,&zeichen,&Line) == TRUE){

Index: polemy/_common.d
==================================================================
--- polemy/_common.d
+++ polemy/_common.d
@@ -9,6 +9,7 @@
 public import std.range;
 public import std.algorithm;
 public import std.conv : to;
 public import std.bigint;
 public import std.exception;
-public import polemy.tricks;
+public import tricks.tricks;
+public import tricks.test;

Index: polemy/ast.d
==================================================================
--- polemy/ast.d
+++ polemy/ast.d
@@ -1,6 +1,6 @@
-/**
+/**
  * Authors: k.inaba
  * License: NYSL 0.9982 http://www.kmonos.net/nysl/
  *
  * Syntax tree for Polemy programming language.
  */

Index: polemy/eval.d
==================================================================
--- polemy/eval.d
+++ polemy/eval.d
@@ -1,6 +1,6 @@
-/**
+/**
  * Authors: k.inaba
  * License: NYSL 0.9982 http://www.kmonos.net/nysl/
  *
  * Evaluator for Polemy programming language.
  */
@@ -11,146 +11,123 @@
 import polemy.parse;
 import polemy.value;
 import std.typecons;
 import std.stdio;
 
-Context createGlobalContext()
-{
-	auto ctx = new Context;
-	ctx.add("+", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+Table createGlobalContext()
+{
+	auto ctx = new Table;
+	// [TODO] autogenerate these typechecks
+	ctx.set("+", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("+ takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "+ takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(x.data+y.data);
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot add non-integers");
 	}));
-	ctx.add("-", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("-", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("- takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "- takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(x.data-y.data);
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot subtract non-integers");
 	}));
-	ctx.add("*", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("*", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("* takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "* takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(x.data*y.data);
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot multiply non-integers");
 	}));
-	ctx.add("/", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("/", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("/ takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "/ takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(x.data/y.data);
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot divide non-integers");
 	}));
-	ctx.add("<", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("<", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("< takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "< takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(BigInt(to!int(x.data < y.data)));
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot compare non-integers");
 	}));
-	ctx.add(">", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set(">", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 2 )
-			throw new PolemyRuntimeException("> takes two arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "> takes two arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 			if( auto y = cast(IntValue)args[1] )
 				return new IntValue(BigInt(to!int(x.data>y.data)));
-		throw new PolemyRuntimeException("cannot add non-integers ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "cannot compare non-integers");
 	}));
-	ctx.add("print", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("print", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		foreach(a; args)
 			write(a);
 		writeln("");
-		return new UndefinedValue;
+		return new IntValue(BigInt(178));
 	}));
-	ctx.add("if", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
+	ctx.set("if", "@val", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 		if( args.length != 3 )
-			throw new PolemyRuntimeException("if takes three arguments!! ["~to!string(pos)~"]");
+			throw new RuntimeException(pos, "if takes three arguments!!");
 		if( auto x = cast(IntValue)args[0] )
 		if( auto ft = cast(FunValue)args[1] )
 		if( auto fe = cast(FunValue)args[2] )
 			return (x.data == 0 ? fe : ft).call(pos,[]);
-		throw new PolemyRuntimeException("type mismatch in if ["~to!string(pos)~"]");
+		throw new RuntimeException(pos, "type mismatch in if");
 	}));
 	return ctx;
 }
 
-Tuple!(Value,"val",Context,"ctx") evalString(T...)(T params)
+/// Entry point of this module
+
+Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
 {
-	return eval( parserFromString(params).parseProgram() );
+	return eval( polemy.parse.parseString(str, fn_ln_cn) );
 }
 
-Tuple!(Value,"val",Context,"ctx") evalFile(T...)(T params)
+Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filenae, T ln_cn)
 {
-	return eval( parserFromFile(params).parseProgram() );
+	return eval( polemy.parse.parseFile(filename, ln_cn) );
 }
 
-Tuple!(Value,"val",Context,"ctx") eval(Program prog)
+Tuple!(Value,"val",Table,"ctx") eval(AST e)
 {
-	Context ctx = createGlobalContext();
-	return typeof(return)(eval(prog, ctx), ctx);
+	Table ctx = createGlobalContext();
+	return typeof(return)(eval(e, ctx), ctx);
 }
 
-Value eval(Program prog, Context ctx)
-{
-	Value v = new UndefinedValue;
-	foreach(s; prog)
-		v = eval(s, ctx);
-	return v;
-}
-
-Value eval(Statement _s, Context ctx)
+Value eval(AST _e, Table ctx, bool splitCtx = true)
 {
-	if( auto s = cast(DeclStatement)_s )
-	{
-		auto v = eval(s.expr, ctx);
-		ctx.add(s.var, v);
-		return v;
-	}
-	else
-	if( auto s = cast(ExprStatement)_s )
-	{
-		return eval(s.expr, ctx);
-	}
-	throw new PolemyRuntimeException(sprintf!"Unknown Kind of Statement %s at [%s]"(typeid(_s), _s.pos));
-}
-
-Value eval(Expression _e, Context ctx)
-{
-	if( auto e = cast(StrLiteralExpression)_e )
+	if( auto e = cast(StrLiteral)_e )
 	{
 		return new StrValue(e.data);
 	}
 	else
-	if( auto e = cast(IntLiteralExpression)_e )
+	if( auto e = cast(IntLiteral)_e )
 	{
 		return new IntValue(e.data);
 	}
-	else
-	if( auto e = cast(VarExpression)_e )
-	{
-		return ctx[e.var];
-	}
-	else
-	if( auto e = cast(AssignExpression)_e )
-	{
-		if( auto ev = cast(VarExpression)e.lhs )
-		{
-			Value r = eval(e.rhs, ctx);
-			ctx[ev.var] = r;
-			return r;
-		}
-		throw new PolemyRuntimeException(sprintf!"Lhs of assignment must be a variable: %s"(e.pos));
-	}
+	else
+	if( auto e = cast(VarExpression)_e )
+	{
+		return ctx.get(e.var, "@val", e.pos);
+	}
+	else
+	if( auto e = cast(LetExpression)_e )
+	{
+		// for letrec, we need this, but should avoid overwriting????
+		// ctx.set(e.var, "@val", new UndefinedValue, e.pos);
+		Value v = eval(e.init, ctx, true);
+		ctx.set(e.var, "@val", v, e.pos);
+		return eval(e.expr, ctx);
+	}
 	else
 	if( auto e = cast(FuncallExpression)_e )
 	{
 		Value _f = eval(e.fun, ctx);
 		if( auto f = cast(FunValue)_f ) {
@@ -157,74 +134,65 @@
 			Value[] args;
 			foreach(a; e.args)
 				args ~= eval(a, ctx);
 			return f.call(e.pos, args);
 		} else
-			throw new PolemyRuntimeException(sprintf!"Non-funcion is applied at [%s]"(e.pos));
+			throw new RuntimeException(e.pos, "Non-funcion is applied");
 	}
 	else
-	if( auto e = cast(FunLiteralExpression)_e )
+	if( auto e = cast(FunLiteral)_e )
 	{
 		return new FunValue(delegate Value(immutable LexPosition pos, Value[] args){
 			if( e.params.length != args.length )
-				throw new PolemyRuntimeException(sprintf!"Argument Number Mismatch (%d required but %d given) at [%s]"
-					(e.params.length, args.length, e.pos));
-			Context ctxNeo = new Context(ctx);
+				throw new RuntimeException(e.pos, sprintf!"Argument Number Mismatch (%d required but %d given)"
+					(e.params.length, args.length));
+			Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet);
 			foreach(i,p; e.params)
-				ctxNeo.add(p, args[i]);
+				ctxNeo.set(p, "@val", args[i]);
 			return eval(e.funbody, ctxNeo);
 		});
 	}
-	throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s at [%s]"(typeid(_e), _e.pos));
+	throw new RuntimeException(_e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(_e)));
 }
-
+
 unittest
-{
-	auto r = evalString(`var x = 21; x = x + x*x;`);
-	assert( r.val == new IntValue(BigInt(21+21*21)) );
-	assert( r.ctx["x"] == new IntValue(BigInt(21+21*21)) );
-	assert( !collectException(r.ctx["x"]) );
-	assert( collectException(r.ctx["y"]) );
+{
+	auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
+	assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
+	assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21)) );
+	assert_nothrow( r.ctx.get("x","@val") );
+	assert_throw!RuntimeException( r.ctx.get("y","@val") );
 }
+unittest
+{
+	auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
+	assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
+	assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21+21*21)) );
+	assert_nothrow( r.ctx.get("x","@val") );
+	assert_throw!RuntimeException( r.ctx.get("y","@val") );
+}
 unittest
 {
-	assert( collectException(evalString(`var x = 21; x = x + x*y;`)) );
-	assert( collectException(evalString(`x=1;`)) );
+	assert_nothrow( evalString(`print("Hello, world!");`) );
+	assert_nothrow( evalString(`print(fun(){});`) );
 }
 unittest
 {
-	auto r = evalString(`var x = fun(a){1+a;}(2);`);
-	assert( r.ctx["x"] == new IntValue(BigInt(3)) );
-	assert( r.val == new IntValue(BigInt(3)) );
-}
-unittest
-{
-	auto r = evalString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); f();`);
-	assert( r.ctx["x"] == new IntValue(BigInt(4)) );
-	assert( r.val == new IntValue(BigInt(4)) );
-}
-unittest
-{
-	evalString(`print("Hello, world!");`);
-	evalString(`print(fun(){});`);
-}
-unittest
-{
-	evalString(`var fac = fun(x){
+	assert_nothrow( evalString(`var fac = fun(x){
 		1;
 	};
-	print(fac(3));`);
-	evalString(`var fac = fun(x){
+	print(fac(3));`));
+	assert_nothrow( evalString(`var fac = fun(x){
 		if(x)
 			{ x*fac(x-1); }
 		else
 			{ 1; };
 	};
-	print(fac(10));`);
-	evalString(`var fib = fun(x){
+	print(fac(10));`));
+	assert_nothrow( evalString(`var fib = fun(x){
 		if(x<2)
 			{ 1; }
 		else
 			{ fib(x-1) + fib(x-2); };
 	};
-	print(fib(10));`);
+	print(fib(10));`));
 }

Index: polemy/lex.d
==================================================================
--- polemy/lex.d
+++ polemy/lex.d
@@ -13,27 +13,25 @@
 
 class LexException : Exception
 {
 	const LexPosition pos;
 
-	private this( const LexPosition pos, string msg )
-		{ super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
-};
-
+	this( const LexPosition pos, string msg, string file="", int line=0 )
+		{ super(sprintf!"[%s] %s"(pos, msg), file, line); this.pos = pos; }
+};
+
 /// Represents a position in a source code
 
 class LexPosition
 {
 	immutable string filename; /// name of the source file
 	immutable int    lineno;   /// 1-origin
 	immutable int    column;   /// 1-origin
-
+
+	mixin SimpleClass;
 	override string toString() const
 		{ return sprintf!"%s:%d:%d"(filename, lineno, column); }
-
-	mixin SimpleConstructor;
-	mixin SimpleCompare;
 
 	static immutable LexPosition dummy;
 	static this(){ dummy = new immutable(LexPosition)("<unnamed>",0,0); }
 }
 
@@ -61,13 +59,11 @@
 {
 	immutable LexPosition pos;    /// Position where the token occurred in the source
 	immutable string      str;    /// The token string itself
 	immutable bool        quoted; /// Was it a "quoted" token or unquoted?
 
-	mixin SimpleConstructor;
-	mixin SimpleCompare;
-	mixin SimpleToString;
+	mixin SimpleClass;
 }
 
 unittest
 {
 	auto p = new immutable(LexPosition)("hello.cpp", 123, 45);

Index: polemy/parse.d
==================================================================
--- polemy/parse.d
+++ polemy/parse.d
@@ -20,11 +20,11 @@
 }
 
 private auto createException(Lexer)(Lexer lex, string msg)
 	{ return new ParseException(lex.empty?null:lex.front.pos, msg); }
 
-/// Entry point of this module
+/// Entry points of this module
 
 auto parseString(S, T...)(S str, T fn_ln_cn)
 	{ return parserFromString(str, fn_ln_cn).parse(); }
 
 auto parseFile(S, T...)(S filename,T ln_cn)

DELETED polemy/tricks.d
Index: polemy/tricks.d
==================================================================
--- polemy/tricks.d
+++ polemy/tricks.d
@@ -1,283 +0,0 @@
-/**
- * Authors: k.inaba
- * License: NYSL 0.9982 http://www.kmonos.net/nysl/
- *
- * Common tricks and utilities for programming in D.
- */
-module polemy.tricks;
-import std.array      : appender;
-import std.format     : formattedWrite;
-import core.exception : onAssertErrorMsg, AssertError;
-
-/// Simple Wrapper for std.format.doFormat
-
-string sprintf(string fmt, T...)(T params)
-{
-	auto writer = appender!string();
-	formattedWrite(writer, fmt, params);
-	return writer.data;
-}
-
-unittest
-{
-	assert( sprintf!"%s == %d"("1+2", 3)   == "1+2 == 3" );
-	assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" );
-}
-
-/// Unittest helper that asserts an expression must throw something
-
-void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
-{
-	try {
-		t();
-	} catch(ExceptionType) {
-		return;
-	} catch(Throwable e) {
-		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
-	}
-	onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption");
-}
-
-/// Unittest helper that asserts an expression must not throw anything
-
-void assert_nothrow(T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
-{
-	try {
-		t();
-	} catch(Throwable e) {
-		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
-	}
-}
-
-unittest
-{
-	auto error = {throw new Error("hello");};
-	auto nothing = (){};
-	auto assertError = {assert(0);};
-
-	assert_nothrow          ( assert_nothrow(nothing()) );
-	assert_throw!AssertError( assert_nothrow(error()) );
-	assert_throw!AssertError( assert_nothrow(assertError()) );
-
-	assert_nothrow          ( assert_throw!Error(error()) );
-	assert_throw!AssertError( assert_throw!Error(nothing()) );
-	assert_nothrow          ( assert_throw!Error(assertError()) );
-	assert_throw!AssertError( assert_throw!AssertError(error()) );
-}
-
-/// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >=
-
-template assertOp(string op)
-{
-	void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="")
-	{
-		try {
-			if( mixin("a"~op~"b") ) return;
-		} catch(Throwable e) {
-			onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
-		}
-		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b));
-	}
-}
-
-alias assertOp!(`==`) assert_eq;
-alias assertOp!(`!=`) assert_ne;
-alias assertOp!(`<`)  assert_lt;
-alias assertOp!(`<=`) assert_le;
-alias assertOp!(`>`)  assert_gt;
-alias assertOp!(`>=`) assert_ge;
-
-unittest
-{
-	assert_nothrow( assert_eq(1, 1) );
-	assert_nothrow( assert_ne(1, 0) );
-	assert_nothrow( assert_lt(0, 1) );
-	assert_nothrow( assert_le(0, 1) );
-	assert_nothrow( assert_le(0, 0) );
-	assert_nothrow( assert_gt(1, 0) );
-	assert_nothrow( assert_ge(1, 0) );
-	assert_nothrow( assert_ge(0, 0) );
-
-	assert_throw!AssertError( assert_eq(1, 0) );
-	assert_throw!AssertError( assert_ne(1, 1) );
-	assert_throw!AssertError( assert_lt(1, 1) );
-	assert_throw!AssertError( assert_lt(1, 0) );
-	assert_throw!AssertError( assert_le(1, 0) );
-	assert_throw!AssertError( assert_gt(0, 0) );
-	assert_throw!AssertError( assert_gt(0, 1) );
-	assert_throw!AssertError( assert_ge(0, 1) );
-
-	class Temp { bool opEquals(int x){return x/x==x;} }
-	assert_throw!AssertError( assert_eq(new Temp, 0) );
-	assert_nothrow          ( assert_eq(new Temp, 1) );
-	assert_throw!AssertError( assert_eq(new Temp, 2) );
-}
-
-/* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */
-
-/// Mixing-in the bean constructor for a class
-
-/*mixin*/
-template SimpleConstructor()
-{
-	static if( is(typeof(super) == Object) || super.tupleof.length==0 )
-		this( typeof(this.tupleof) params )
-		{
-			static if(this.tupleof.length>0)
-				this.tupleof = params;
-		}
-	else
-		this( typeof(super.tupleof) ps, typeof(this.tupleof) params )
-		{
-			// including (only) the direct super class members
-			// may not always be a desirable choice, but should work for many cases
-			super(ps);
-			static if(this.tupleof.length>0)
-				this.tupleof = params;
-		}
-}
-
-unittest
-{
-	class Temp
-	{
-		int x;
-		string y;
-		mixin SimpleConstructor;
-	}
-	assert_eq( (new Temp(1,"foo")).x, 1 );
-	assert_eq( (new Temp(1,"foo")).y, "foo" );
-	assert( !__traits(compiles, new Temp) );
-	assert( !__traits(compiles, new Temp(1)) );
-	assert( !__traits(compiles, new Temp("foo",1)) );
-
-	class Tomp : Temp
-	{
-		real z;
-		mixin SimpleConstructor;
-	}
-	assert_eq( (new Tomp(1,"foo",2.5)).x, 1 );
-	assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" );
-	assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 );
-	assert( !__traits(compiles, new Tomp(3.14)) );
-
-	// shiyo- desu. Don't use in this way.
-	//   Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
-	//   but it fails because Tomp takes (int,string,real).
-	assert( !__traits(compiles, {
-		class Tamp : Tomp
-		{
-			mixin SimpleConstructor;
-		}
-	}) );
-}
-
-/// Mixing-in the MOST-DERIVED-member-wise comparator for a class
-
-/*mixin*/
-template SimpleCompare()
-{
-	override bool opEquals(Object rhs_) const
-	{
-		if( auto rhs = cast(typeof(this))rhs_ )
-		{
-			foreach(i,_; this.tupleof)
-				if( this.tupleof[i] != rhs.tupleof[i] )
-					return false;
-			return true;
-		}
-		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
-	}
-
-	override hash_t toHash() const
-	{
-		hash_t h = 0;
-		foreach(mem; this.tupleof)
-			h += typeid(mem).getHash(&mem);
-		return h;
-	}
-
-	override int opCmp(Object rhs_) const
-	{
-		if( auto rhs = cast(typeof(this))rhs_ )
-		{
-			foreach(i,_; this.tupleof)
-				if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]))
-					return c;
-			return 0;
-		}
-		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
-	}
-}
-
-unittest
-{
-	class Temp
-	{
-		int x;
-		string y;
-		mixin SimpleConstructor;
-		mixin SimpleCompare;
-	}
-	assert_eq( new Temp(1,"foo"), new Temp(1,"foo") );
-	assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash );
-	assert_ne( new Temp(1,"foo"), new Temp(2,"foo") );
-	assert_ne( new Temp(1,"foo"), new Temp(1,"bar") );
-	assert_gt( new Temp(1,"foo"), new Temp(1,"bar") );
-	assert_lt( new Temp(1,"foo"), new Temp(2,"bar") );
-	assert_ge( new Temp(1,"foo"), new Temp(1,"foo") );
-
-	class TempDummy
-	{
-		int x;
-		string y;
-		mixin SimpleConstructor;
-		mixin SimpleCompare;
-	}
-	assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") );
-	assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") );
-}
-
-/// Mixing-in a simple toString method
-
-/*mixin*/
-template SimpleToString()
-{
-	override string toString()
-	{
-		string str = sprintf!"%s("(typeof(this).stringof);
-		foreach(i,mem; this.tupleof)
-		{
-			if(i) str ~= ",";
-			static if( is(typeof(mem) == std.bigint.BigInt) )
-				str ~= std.bigint.toDecimalString(mem);
-			else
-				str ~= sprintf!"%s"(mem);
-		}
-		return str ~ ")";
-	}
-}
-
-version(unittest) import std.bigint;
-unittest
-{
-	class Temp
-	{
-		int x;
-		string y;
-		BigInt z;
-		mixin SimpleConstructor;
-		mixin SimpleToString;
-	}
-	assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" );
-}
-
-/// Everything is in
-
-/*mixin*/
-template SimpleClass()
-{
-	mixin SimpleConstructor;
-	mixin SimpleCompare;
-	mixin SimpleToString;
-}

Index: polemy/value.d
==================================================================
--- polemy/value.d
+++ polemy/value.d
@@ -1,6 +1,6 @@
-/**
+/**
  * Authors: k.inaba
  * License: NYSL 0.9982 http://www.kmonos.net/nysl/
  *
  * Runtime data structures for Polemy programming language.
  */
@@ -13,12 +13,11 @@
 class RuntimeException : Exception
 {
 	const LexPosition pos;
 
 	this( const LexPosition pos, string msg )
-		{ super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
-	this( string msg ) { super(msg); this.pos = null; }
+		{ super(sprintf!"%s at [%s]"(msg, pos)); this.pos = pos; }
 }
 
 /// Runtime values of Polemy
 
 abstract class Value
@@ -65,22 +64,23 @@
 	enum Kind {PropagateSet, NotPropagateSet};
 
 	this( Table proto=null, Kind k = Kind.PropagateSet )
 		{ this.prototype = proto; this.kind = k; }
 
-	void set(string i, Layer lay, Value v)
+	void set(string i, Layer lay, Value v, in LexPosition pos=null)
 	{
-		if( !setIfExist(i, lay, v) )
-			data[i][lay] = v;
+		if( setIfExist(i, lay, v) )
+			return;
+		data[i][lay] = v;
 	}
 
-	Value get(string i, Layer lay)
+	Value get(string i, Layer lay, in LexPosition pos=null)
 	{
 		if( i in data )
 			return data[i][lay];
 		if( prototype is null )
-			throw new RuntimeException(sprintf!"variable %s not found"(i));
+			throw new RuntimeException(pos, sprintf!"variable %s not found"(i));
 		return prototype.get(i, lay);
 	}
 
 private:
 	Table                prototype;

ADDED   tricks/test.d
Index: tricks/test.d
==================================================================
--- tricks/test.d
+++ tricks/test.d
@@ -0,0 +1,98 @@
+/**
+ * Authors: k.inaba
+ * License: NYSL 0.9982 http://www.kmonos.net/nysl/
+ *
+ * Unittest helpers.
+ */
+module tricks.test;
+import std.conv : to;
+import core.exception;
+
+/// Unittest helper that asserts an expression must throw something
+
+void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
+{
+	try
+		{ t(); }
+	catch(ExceptionType)
+		{ return; }
+	catch(Throwable e)
+		{ onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.toString()~"]"); }
+	onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption");
+}
+
+/// Unittest helper that asserts an expression must not throw anything
+
+auto assert_nothrow(T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
+{
+	try
+		{ return t(); }
+	catch(Throwable e)
+		{ onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.toString()~"]"); }
+	assert(false);
+}
+
+unittest
+{
+	auto error = {throw new Error("hello");};
+	auto nothing = (){};
+	auto assertError = {assert(0);};
+
+	assert_nothrow          ( assert_nothrow(nothing()) );
+	assert_throw!AssertError( assert_nothrow(error()) );
+	assert_throw!AssertError( assert_nothrow(assertError()) );
+
+	assert_nothrow          ( assert_throw!Error(error()) );
+	assert_throw!AssertError( assert_throw!Error(nothing()) );
+	assert_nothrow          ( assert_throw!Error(assertError()) );
+	assert_throw!AssertError( assert_throw!AssertError(error()) );
+}
+
+/// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >=
+
+template assertOp(string op)
+{
+	void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="")
+	{
+		try
+			{ if( mixin("a"~op~"b") ) return; }
+		catch(Throwable e)
+			{ onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.toString()~"]"); }
+		onAssertErrorMsg(fn, ln, msg.length ? msg : to!string(a)~" !"~op~to!string(b));
+	}
+}
+
+alias assertOp!(`==`) assert_eq;
+alias assertOp!(`!=`) assert_ne;
+alias assertOp!(`<`)  assert_lt;
+alias assertOp!(`<=`) assert_le;
+alias assertOp!(`>`)  assert_gt;
+alias assertOp!(`>=`) assert_ge;
+
+unittest
+{
+	assert_nothrow( assert_eq(1, 1) );
+	assert_nothrow( assert_ne(1, 0) );
+	assert_nothrow( assert_lt(0, 1) );
+	assert_nothrow( assert_le(0, 1) );
+	assert_nothrow( assert_le(0, 0) );
+	assert_nothrow( assert_gt(1, 0) );
+	assert_nothrow( assert_ge(1, 0) );
+	assert_nothrow( assert_ge(0, 0) );
+
+	assert_throw!AssertError( assert_eq(1, 0) );
+	assert_throw!AssertError( assert_ne(1, 1) );
+	assert_throw!AssertError( assert_lt(1, 1) );
+	assert_throw!AssertError( assert_lt(1, 0) );
+	assert_throw!AssertError( assert_le(1, 0) );
+	assert_throw!AssertError( assert_gt(0, 0) );
+	assert_throw!AssertError( assert_gt(0, 1) );
+	assert_throw!AssertError( assert_ge(0, 1) );
+
+	class Temp { bool opEquals(int x){return x/x==x;} }
+	assert_throw!AssertError( assert_eq(new Temp, 0) );
+	assert_nothrow          ( assert_eq(new Temp, 1) );
+	assert_throw!AssertError( assert_eq(new Temp, 2) );
+}
+
+/* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */

ADDED   tricks/tricks.d
Index: tricks/tricks.d
==================================================================
--- tricks/tricks.d
+++ tricks/tricks.d
@@ -0,0 +1,210 @@
+/**
+ * Authors: k.inaba
+ * License: NYSL 0.9982 http://www.kmonos.net/nysl/
+ *
+ * Common tricks and utilities for programming in D.
+ */
+module tricks.tricks;
+import tricks.test;
+import std.array      : appender;
+import std.format     : formattedWrite;
+import core.exception : AssertError;
+
+/// Simple Wrapper for std.format.doFormat
+
+string sprintf(string fmt, T...)(T params)
+{
+	auto writer = appender!string();
+	formattedWrite(writer, fmt, params);
+	return writer.data;
+}
+
+unittest
+{
+	assert( sprintf!"%s == %d"("1+2", 3)   == "1+2 == 3" );
+	assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" );
+}
+
+/// Create an exception with automatically completed filename and lineno information
+
+auto genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)
+{
+	static if( T.length > 0 && is(T[$-1] : Throwable) )
+		return new ExceptionType(params[0..$-1], fn, ln, params[$-1]);
+	else
+		return new ExceptionType(params, fn, ln);
+}
+
+unittest
+{
+	assert_ne( genex!Exception("msg").file, "" );
+	assert_ne( genex!Exception("msg").line, 0 );
+	assert_ne( genex!Exception("msg",new Exception("bar")).next, Exception.init );
+}
+
+/// Mixing-in the bean constructor for a class
+
+/*mixin*/
+template SimpleConstructor()
+{
+	static if( is(typeof(super) == Object) || super.tupleof.length==0 )
+		this( typeof(this.tupleof) params )
+		{
+			static if(this.tupleof.length>0)
+				this.tupleof = params;
+		}
+	else
+		this( typeof(super.tupleof) ps, typeof(this.tupleof) params )
+		{
+			// including (only) the direct super class members
+			// may not always be a desirable choice, but should work for many cases
+			super(ps);
+			static if(this.tupleof.length>0)
+				this.tupleof = params;
+		}
+}
+
+unittest
+{
+	class Temp
+	{
+		int x;
+		string y;
+		mixin SimpleConstructor;
+	}
+	assert_eq( (new Temp(1,"foo")).x, 1 );
+	assert_eq( (new Temp(1,"foo")).y, "foo" );
+	assert( !__traits(compiles, new Temp) );
+	assert( !__traits(compiles, new Temp(1)) );
+	assert( !__traits(compiles, new Temp("foo",1)) );
+
+	class Tomp : Temp
+	{
+		real z;
+		mixin SimpleConstructor;
+	}
+	assert_eq( (new Tomp(1,"foo",2.5)).x, 1 );
+	assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" );
+	assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 );
+	assert( !__traits(compiles, new Tomp(3.14)) );
+
+	// shiyo- desu. Don't use in this way.
+	//   Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
+	//   but it fails because Tomp takes (int,string,real).
+	assert( !__traits(compiles, {
+		class Tamp : Tomp
+		{
+			mixin SimpleConstructor;
+		}
+	}) );
+}
+
+/// Mixing-in the MOST-DERIVED-member-wise comparator for a class
+
+/*mixin*/
+template SimpleCompare()
+{
+	override bool opEquals(Object rhs_) const
+	{
+		if( auto rhs = cast(typeof(this))rhs_ )
+		{
+			foreach(i,_; this.tupleof)
+				if( this.tupleof[i] != rhs.tupleof[i] )
+					return false;
+			return true;
+		}
+		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
+	}
+
+	override hash_t toHash() const
+	{
+		hash_t h = 0;
+		foreach(mem; this.tupleof)
+			h += typeid(mem).getHash(&mem);
+		return h;
+	}
+
+	override int opCmp(Object rhs_) const
+	{
+		if( auto rhs = cast(typeof(this))rhs_ )
+		{
+			foreach(i,_; this.tupleof)
+				if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]))
+					return c;
+			return 0;
+		}
+		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
+	}
+}
+
+unittest
+{
+	class Temp
+	{
+		int x;
+		string y;
+		mixin SimpleConstructor;
+		mixin SimpleCompare;
+	}
+	assert_eq( new Temp(1,"foo"), new Temp(1,"foo") );
+	assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash );
+	assert_ne( new Temp(1,"foo"), new Temp(2,"foo") );
+	assert_ne( new Temp(1,"foo"), new Temp(1,"bar") );
+	assert_gt( new Temp(1,"foo"), new Temp(1,"bar") );
+	assert_lt( new Temp(1,"foo"), new Temp(2,"bar") );
+	assert_ge( new Temp(1,"foo"), new Temp(1,"foo") );
+
+	class TempDummy
+	{
+		int x;
+		string y;
+		mixin SimpleConstructor;
+		mixin SimpleCompare;
+	}
+	assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") );
+	assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") );
+}
+
+/// Mixing-in a simple toString method
+
+/*mixin*/
+template SimpleToString()
+{
+	override string toString()
+	{
+		string str = sprintf!"%s("(typeof(this).stringof);
+		foreach(i,mem; this.tupleof)
+		{
+			if(i) str ~= ",";
+			static if( is(typeof(mem) == std.bigint.BigInt) )
+				str ~= std.bigint.toDecimalString(mem);
+			else
+				str ~= sprintf!"%s"(mem);
+		}
+		return str ~ ")";
+	}
+}
+
+version(unittest) import std.bigint;
+unittest
+{
+	class Temp
+	{
+		int x;
+		string y;
+		BigInt z;
+		mixin SimpleConstructor;
+		mixin SimpleToString;
+	}
+	assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" );
+}
+
+/// Everything is in
+
+/*mixin*/
+template SimpleClass()
+{
+	mixin SimpleConstructor;
+	mixin SimpleCompare;
+	mixin SimpleToString;
+}