File Annotation
Not logged in
8de5b49cdf 2010-11-09        kinaba: /**
4198578702 2010-11-07        kinaba:  * Authors: k.inaba
4198578702 2010-11-07        kinaba:  * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4198578702 2010-11-07        kinaba:  *
4198578702 2010-11-07        kinaba:  * Evaluator for Polemy programming language.
423f308350 2010-11-07        kinaba:  */
4198578702 2010-11-07        kinaba: module polemy.eval;
4198578702 2010-11-07        kinaba: import polemy._common;
3464a035ec 2010-11-20        kinaba: import polemy.failure;
423f308350 2010-11-07        kinaba: import polemy.ast;
3f5dc76a75 2010-11-07        kinaba: import polemy.parse;
b0d8d7875b 2010-11-08        kinaba: import polemy.value;
435fa085ec 2010-11-21        kinaba: import polemy.layer;
36c517dfc4 2010-11-23        kinaba: import polemy.value;
36c517dfc4 2010-11-23        kinaba: import polemy.valueconv;
423f308350 2010-11-07        kinaba: 
b97bd4f713 2010-11-23        kinaba: /// Objects for maitaining global environment and evaluation of expression on it
6ac127ddd0 2010-11-23        kinaba: class Evaluator
423f308350 2010-11-07        kinaba: {
6ac127ddd0 2010-11-23        kinaba: public:
b97bd4f713 2010-11-23        kinaba: 	/// Initialize evaluator with empty context
6ac127ddd0 2010-11-23        kinaba: 	this() { theContext = new Table; }
6ac127ddd0 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 	/// Evaluate the AST
6ac127ddd0 2010-11-23        kinaba: 	Value evalAST(AST e)
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		return macroAndEval(e, ValueLayer, theContext, OverwriteCtx)[0];
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 	/// Evaluate the string
6ac127ddd0 2010-11-23        kinaba: 	Value evalString(S,T...)(S str, T fn_ln_cn)
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		return evalAST(parseString(str,fn_ln_cn));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 	/// Evaluate the file
6ac127ddd0 2010-11-23        kinaba: 	Value evalFile(S,T...)(S filename, T ln_cn)
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		return evalAST(parseFile(filename,ln_cn));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 	/// Get the global context
6ac127ddd0 2010-11-23        kinaba: 	Table globalContext()
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		return theContext;
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: private:
6ac127ddd0 2010-11-23        kinaba: 	Table theContext;
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	enum : bool { CascadeCtx=false, OverwriteCtx=true };
ba11f1d551 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		// dynamic-overload-resolution-pattern: modify here
6ac127ddd0 2010-11-23        kinaba: 		enum funName = "eval";
6ac127ddd0 2010-11-23        kinaba: 		alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 		// dynamic-overload-resolution-pattern: dispatch
6ac127ddd0 2010-11-23        kinaba: 		alias typeof(__traits(getOverloads, this, funName)) ovTypes;
6ac127ddd0 2010-11-23        kinaba: 		alias staticMap!(firstParam, ovTypes)              fstTypes;
6ac127ddd0 2010-11-23        kinaba: 		alias DerivedToFront!(fstTypes)             fstTypes_sorted;
6ac127ddd0 2010-11-23        kinaba: 		foreach(i, T; fstTypes_sorted)
6ac127ddd0 2010-11-23        kinaba: 			static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] )
6ac127ddd0 2010-11-23        kinaba: 				return __traits(getOverloads, this, funName)[i](_x, params[1..$]);
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 		// dynamic-overload-resolution-pattern: default behavior
6ac127ddd0 2010-11-23        kinaba: 		assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined"));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) )
b97bd4f713 2010-11-23        kinaba: 			return ast2table(e, (AST e){return eval(e,lay,ctx);});
153a14cec0 2010-11-24        kinaba: 		if( isUserDefinedLayer(lay) )
153a14cec0 2010-11-24        kinaba: 			return lift(new StrValue(e.data), lay, ctx, e.pos);
153a14cec0 2010-11-24        kinaba: 		return new StrValue(e.data);
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) )
b97bd4f713 2010-11-23        kinaba: 			return ast2table(e, (AST e){return eval(e,lay,ctx);});
153a14cec0 2010-11-24        kinaba: 		if( isUserDefinedLayer(lay) )
153a14cec0 2010-11-24        kinaba: 			return lift(new IntValue(e.data), lay, ctx, e.pos);
153a14cec0 2010-11-24        kinaba: 		return new IntValue(e.data);
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) )
ba11f1d551 2010-11-23        kinaba: 			if( isMacroLayer(lay) && ctx.has(e.name,MacroLayer) )
6ac127ddd0 2010-11-23        kinaba: 				return ctx.get(e.name, MacroLayer, e.pos);
b97bd4f713 2010-11-23        kinaba: 			else
b97bd4f713 2010-11-23        kinaba: 				return ast2table(e, (AST e){return eval(e,lay,ctx);});
153a14cec0 2010-11-24        kinaba: 		if( isUserDefinedLayer(lay) && !ctx.has(e.name, lay) )
153a14cec0 2010-11-24        kinaba: 			return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos);
153a14cec0 2010-11-24        kinaba: 		return ctx.get(e.name, lay, e.pos);
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
a5fe6233c1 2010-11-21        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		Value f = eval( e.fun, lay, ctx );
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) ) {
ba11f1d551 2010-11-23        kinaba: 			auto ff = cast(FunValue)f;
ba11f1d551 2010-11-23        kinaba: 			if( ff !is null && isMacroLayer(lay) )
ba11f1d551 2010-11-23        kinaba: 				return invokeFunction(ff, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun));
b97bd4f713 2010-11-23        kinaba: 			else
b97bd4f713 2010-11-23        kinaba: 				return ast2table(e, (AST e){return eval(e,lay,ctx);});
ba11f1d551 2010-11-23        kinaba: 		}
2134cd44cc 2010-11-23        kinaba: 		return invokeFunction(f, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) )
ba11f1d551 2010-11-23        kinaba: 		{
ba11f1d551 2010-11-23        kinaba: 			// need this for correct scoping (outer scope macro variables must be hidden!)
ba11f1d551 2010-11-23        kinaba: 			Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet);
ba11f1d551 2010-11-23        kinaba: 			foreach(p; e.params)
207cea338a 2010-11-26        kinaba: 				newCtx.set(p.name, NoopLayer, null);
ba11f1d551 2010-11-23        kinaba: 			return ast2table(e, (AST e){return eval(e,lay,newCtx);});
ba11f1d551 2010-11-23        kinaba: 		}
6ac127ddd0 2010-11-23        kinaba: 		else
6ac127ddd0 2010-11-23        kinaba: 			return createNewFunction(e, ctx);
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
6ac127ddd0 2010-11-23        kinaba: 	{
b97bd4f713 2010-11-23        kinaba: 		if( isNoLayerChangeLayer(lay) )
b97bd4f713 2010-11-23        kinaba: 			return ast2table(e, (AST e){return eval(e,lay,ctx);});
6ac127ddd0 2010-11-23        kinaba: 		else
6ac127ddd0 2010-11-23        kinaba: 			return eval(e.expr, e.layer, ctx);
a5fe6233c1 2010-11-21        kinaba: 	}
a5fe6233c1 2010-11-21        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
a5fe6233c1 2010-11-21        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.NotPropagateSet);
ba11f1d551 2010-11-23        kinaba: 		if( isASTLayer(lay) )
ba11f1d551 2010-11-23        kinaba: 			return ast2table(e, (AST ee){
153a14cec0 2010-11-24        kinaba: 				// need this for correct scoping (outer scope macro variables must be hidden!)
f8684f4d69 2010-11-26        kinaba: 				if(e.name!="_" && ee is e.expr)
207cea338a 2010-11-26        kinaba: 					newCtx.set(e.name, NoopLayer, null);
ba11f1d551 2010-11-23        kinaba: 				return eval(ee,lay,newCtx);
ba11f1d551 2010-11-23        kinaba: 			});
b97bd4f713 2010-11-23        kinaba: 		else
b97bd4f713 2010-11-23        kinaba: 		{
ba11f1d551 2010-11-23        kinaba: 			Value ri = eval(e.init, lay, newCtx);
f8684f4d69 2010-11-26        kinaba: 			if(e.name!="_")
f8684f4d69 2010-11-26        kinaba: 				newCtx.set(e.name, e.layer.empty ? lay : e.layer, ri);
ba11f1d551 2010-11-23        kinaba: 			return eval(e.expr, lay, newCtx, OverwriteCtx);
ba11f1d551 2010-11-23        kinaba: 		}
ba11f1d551 2010-11-23        kinaba: 	}
ba11f1d551 2010-11-23        kinaba: 
ba11f1d551 2010-11-23        kinaba: private:
ba11f1d551 2010-11-23        kinaba: 	// little little bit incremental macro defining version.
ba11f1d551 2010-11-23        kinaba: 	// enables @macro foo(x)=... in ... foo ..., only at the top level of the
ba11f1d551 2010-11-23        kinaba: 	// interpreter and functions. better than nothing :P
ba11f1d551 2010-11-23        kinaba: 	Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
ba11f1d551 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		assert( !isASTLayer(lay) );
ba11f1d551 2010-11-23        kinaba: 
ba11f1d551 2010-11-23        kinaba: 		AST decodeAST(Value v, LexPosition pos)
ba11f1d551 2010-11-23        kinaba: 		{
ba11f1d551 2010-11-23        kinaba: 			// [TODO] more informative error message
ba11f1d551 2010-11-23        kinaba: 			return polemy2d!(AST)(v, pos);
ba11f1d551 2010-11-23        kinaba: 		}
ba11f1d551 2010-11-23        kinaba: 
ba11f1d551 2010-11-23        kinaba: 		if(auto e = cast(Let)e_)
ba11f1d551 2010-11-23        kinaba: 		{
ba11f1d551 2010-11-23        kinaba: 			AST   ai = decodeAST(eval(e.init, RawMacroLayer, ctx), e.init.pos);
ba11f1d551 2010-11-23        kinaba: 			Value vi = eval(ai, lay, ctx);
ba11f1d551 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			if( !overwriteCtx )
b97bd4f713 2010-11-23        kinaba: 				ctx = new Table(ctx, Table.Kind.NotPropagateSet);
ba11f1d551 2010-11-23        kinaba: 			string theLayer = e.layer.empty ? lay : e.layer;
ba11f1d551 2010-11-23        kinaba: 			ctx.set(e.name, theLayer, vi);
ba11f1d551 2010-11-23        kinaba: 
ba11f1d551 2010-11-23        kinaba: 			auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx );
ba11f1d551 2010-11-23        kinaba: 			AST  a = new Let(e.pos, e.name, e.layer, ai, ave[1]);
ba11f1d551 2010-11-23        kinaba: 			return tuple(ave[0], a);
ba11f1d551 2010-11-23        kinaba: 		}
ba11f1d551 2010-11-23        kinaba: 		else
ba11f1d551 2010-11-23        kinaba: 		{
ba11f1d551 2010-11-23        kinaba: 			AST   a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.pos);
ba11f1d551 2010-11-23        kinaba: 			Value v = eval(a, lay, ctx);
ba11f1d551 2010-11-23        kinaba: 			return tuple(v, a);
f86026acb8 2010-11-21        kinaba: 		}
6ac127ddd0 2010-11-23        kinaba: 	}
3f6f41b558 2010-11-20        kinaba: 
6ac127ddd0 2010-11-23        kinaba: private:
2134cd44cc 2010-11-23        kinaba: 	string getNameIfPossible(AST e)
2134cd44cc 2010-11-23        kinaba: 	{
2134cd44cc 2010-11-23        kinaba: 		if(auto v = cast(Var)e)
2134cd44cc 2010-11-23        kinaba: 			return v.name;
2134cd44cc 2010-11-23        kinaba: 		return "";
2134cd44cc 2010-11-23        kinaba: 	}
2134cd44cc 2010-11-23        kinaba: 
2134cd44cc 2010-11-23        kinaba: 	Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos, string callstackmsg)
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		if(auto f = cast(FunValue)_f)
6ac127ddd0 2010-11-23        kinaba: 		{
6ac127ddd0 2010-11-23        kinaba: 			Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
6ac127ddd0 2010-11-23        kinaba: 			foreach(i,p; f.params())
6ac127ddd0 2010-11-23        kinaba: 				if( p.layers.empty )
ba11f1d551 2010-11-23        kinaba: 					newCtx.set(p.name, isMacroLayer(lay)?MacroLayer:lay, eval(args[i], lay, ctx));
6ac127ddd0 2010-11-23        kinaba: 				else
6ac127ddd0 2010-11-23        kinaba: 					foreach(argLay; p.layers)
6ac127ddd0 2010-11-23        kinaba: 						newCtx.set(p.name, argLay, eval(args[i], argLay, ctx));
2134cd44cc 2010-11-23        kinaba: 			scope _ = new PushCallStack(pos, callstackmsg);
ba11f1d551 2010-11-23        kinaba: 			return f.invoke(isMacroLayer(lay)?MacroLayer:lay, newCtx, pos);
6ac127ddd0 2010-11-23        kinaba: 		}
6ac127ddd0 2010-11-23        kinaba: 		throw genex!RuntimeException(pos, text("tried to call non-function: ",_f));
3995a5eb6a 2010-11-21        kinaba: 	}
3995a5eb6a 2010-11-21        kinaba: 
2134cd44cc 2010-11-23        kinaba: 	Value lift(Value v, Layer lay, Table ctx, LexPosition pos)
6ac127ddd0 2010-11-23        kinaba: 	{
ba11f1d551 2010-11-23        kinaba: 		assert( !isASTLayer(lay), "lift to the @macro layer should never happen" );
b97bd4f713 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 		// functions are automatically lifterd
6ac127ddd0 2010-11-23        kinaba: 		if( cast(FunValue) v )
6ac127ddd0 2010-11-23        kinaba: 			return v;
6ac127ddd0 2010-11-23        kinaba: 
207cea338a 2010-11-26        kinaba: 		if( !ctx.has(lay, LiftLayer) )
2134cd44cc 2010-11-23        kinaba: 			throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" );
2134cd44cc 2010-11-23        kinaba: 
2134cd44cc 2010-11-23        kinaba: 		// similar to invokeFunction, but with only one argument bound to ValueLayer
207cea338a 2010-11-26        kinaba: 		auto _f = ctx.get(lay, LiftLayer, pos);
2134cd44cc 2010-11-23        kinaba: 		if(auto f = cast(FunValue)_f)
1c01f44f52 2010-11-13        kinaba: 		{
6ac127ddd0 2010-11-23        kinaba: 			Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
6ac127ddd0 2010-11-23        kinaba: 			auto ps = f.params();
6ac127ddd0 2010-11-23        kinaba: 			if( ps.length != 1 )
2134cd44cc 2010-11-23        kinaba: 				throw genex!RuntimeException(pos,
2134cd44cc 2010-11-23        kinaba: 					text("lift function for", lay, " must take exactly one argument of ", ValueLayer));
6ac127ddd0 2010-11-23        kinaba: 			if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
3f6f41b558 2010-11-20        kinaba: 			{
6ac127ddd0 2010-11-23        kinaba: 				newCtx.set(ps[0].name, ValueLayer, v);
2134cd44cc 2010-11-23        kinaba: 				scope _ = new PushCallStack(pos, lay);
b97bd4f713 2010-11-23        kinaba: 				return f.invoke(ValueLayer, newCtx, pos);
1c01f44f52 2010-11-13        kinaba: 			}
3f6f41b558 2010-11-20        kinaba: 			else
2134cd44cc 2010-11-23        kinaba: 				throw genex!RuntimeException(pos,
2134cd44cc 2010-11-23        kinaba: 					text("lift function for", lay, " must take exactly one argument of ", ValueLayer));
6ac127ddd0 2010-11-23        kinaba: 		}
2134cd44cc 2010-11-23        kinaba: 		throw genex!RuntimeException(pos,
2134cd44cc 2010-11-23        kinaba: 			text("non-function ", _f, " is registered as the lift function for ", lay));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 	Value createNewFunction(Fun e, Table ctx)
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		class UserDefinedFunValue : FunValue
1c01f44f52 2010-11-13        kinaba: 		{
20be503cae 2010-11-24        kinaba: 			Fun   ast;
20be503cae 2010-11-24        kinaba: 			Table defCtx;
6ac127ddd0 2010-11-23        kinaba: 			override const(Parameter[]) params() { return ast.params; }
20be503cae 2010-11-24        kinaba: 			override Table definitionContext()   { return defCtx; }
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: 			this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; }
153a14cec0 2010-11-24        kinaba: 			override string toString() const
153a14cec0 2010-11-24        kinaba: 				{ return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); }
20be503cae 2010-11-24        kinaba: 			override int opCmp(Object rhs) {
20be503cae 2010-11-24        kinaba: 				if(auto r = cast(UserDefinedFunValue)rhs) {
b993a8ad16 2010-11-24        kinaba: 					if(auto c = typeid(void*).compare(cast(void*)ast, cast(void*)r.ast))
b993a8ad16 2010-11-24        kinaba: 						return c;
b993a8ad16 2010-11-24        kinaba: 					if(auto c = typeid(void*).compare(cast(void*)defCtx, cast(void*)r.defCtx))
b993a8ad16 2010-11-24        kinaba: 						return c;
b993a8ad16 2010-11-24        kinaba: 					return 0;// [TODO] avoid using pointer value...
20be503cae 2010-11-24        kinaba: 				}
153a14cec0 2010-11-24        kinaba: 				if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r));
20be503cae 2010-11-24        kinaba: 				throw genex!RuntimeException("comparison with value and something other");
20be503cae 2010-11-24        kinaba: 			}
b993a8ad16 2010-11-24        kinaba: 			override hash_t toHash() {
b993a8ad16 2010-11-24        kinaba: 				return (cast(hash_t)cast(void*)ast) + (cast(hash_t)cast(void*)defCtx);
b993a8ad16 2010-11-24        kinaba: 			}
20be503cae 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 			AST macroCache;
b993a8ad16 2010-11-24        kinaba: 			static class MemokeyType
b993a8ad16 2010-11-24        kinaba: 			{
b993a8ad16 2010-11-24        kinaba: 				void* a; Layer b; Tuple!(string,Layer,Value)[] c;
b993a8ad16 2010-11-24        kinaba: 				hash_t toHash() {
b993a8ad16 2010-11-24        kinaba: 					hash_t h = structuralHash(a) + structuralHash(b);
b993a8ad16 2010-11-24        kinaba: 					foreach(e; c)
b993a8ad16 2010-11-24        kinaba: 						h += structuralHash(e[0])+structuralHash(e[1])+structuralHash(e[2]);
b993a8ad16 2010-11-24        kinaba: 					return h;
b993a8ad16 2010-11-24        kinaba: 				}
b993a8ad16 2010-11-24        kinaba: 				mixin SimpleToString;
b993a8ad16 2010-11-24        kinaba: 				mixin SimpleConstructor;
b993a8ad16 2010-11-24        kinaba: 				mixin SimpleCompareWithoutToHash;
b993a8ad16 2010-11-24        kinaba: 			}
b993a8ad16 2010-11-24        kinaba: 			static Tuple!(Value,int)[MemokeyType] memo;
b993a8ad16 2010-11-24        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			override Value invoke(Layer lay, Table ctx, LexPosition pos)
3f6f41b558 2010-11-20        kinaba: 			{
ba11f1d551 2010-11-23        kinaba: 				if( isASTLayer(lay) )
6ac127ddd0 2010-11-23        kinaba: 					return eval(ast.funbody, lay, ctx);
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				auto nonMemoizedRun = (){
b993a8ad16 2010-11-24        kinaba: 					if( macroCache is null )
b993a8ad16 2010-11-24        kinaba: 					{
b993a8ad16 2010-11-24        kinaba: 						auto va = macroAndEval(e.funbody, lay, ctx);
b993a8ad16 2010-11-24        kinaba: 						macroCache = va[1];
b993a8ad16 2010-11-24        kinaba: 						return va[0];
b993a8ad16 2010-11-24        kinaba: 					}
b993a8ad16 2010-11-24        kinaba: 					else
b993a8ad16 2010-11-24        kinaba: 						return eval(macroCache, lay, ctx);
b993a8ad16 2010-11-24        kinaba: 				};
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				if( !isUserDefinedLayer(lay) )
b993a8ad16 2010-11-24        kinaba: 					return nonMemoizedRun();
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx.direct_entries());
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				if(auto p = memokey in memo)
ba11f1d551 2010-11-23        kinaba: 				{
b993a8ad16 2010-11-24        kinaba: 					(*p)[1] ++;
b993a8ad16 2010-11-24        kinaba: 					return (*p)[0];
2134cd44cc 2010-11-23        kinaba: 				}
ba11f1d551 2010-11-23        kinaba: 				else
b993a8ad16 2010-11-24        kinaba: 					memo[memokey] = tuple(lift(new UndefinedValue, lay, ctx, pos), 0);
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				Value r = nonMemoizedRun();
b993a8ad16 2010-11-24        kinaba: 
b993a8ad16 2010-11-24        kinaba: 				int touched = memo[memokey][1];
b993a8ad16 2010-11-24        kinaba: 				memo[memokey] = tuple(r, 12345678);
b993a8ad16 2010-11-24        kinaba: 				//if(touched) {DBG("rerun :: ",r);r = nonMemoizedRun();} // twice!!
b993a8ad16 2010-11-24        kinaba: 				return r;
3f6f41b558 2010-11-20        kinaba: 			}
6ac127ddd0 2010-11-23        kinaba: 		}
6ac127ddd0 2010-11-23        kinaba: 		return new UserDefinedFunValue(e,ctx);
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: public:
b97bd4f713 2010-11-23        kinaba: 	/// Add primitive function to the global context
b97bd4f713 2010-11-23        kinaba: 	void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg)
6ac127ddd0 2010-11-23        kinaba: 	{
6ac127ddd0 2010-11-23        kinaba: 		class NativeFunValue : FunValue
1c01f44f52 2010-11-13        kinaba: 		{
6ac127ddd0 2010-11-23        kinaba: 			override const(Parameter[]) params() { return params_data; }
b97bd4f713 2010-11-23        kinaba: 			override Table definitionContext()   { return theContext; }
b97bd4f713 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
b97bd4f713 2010-11-23        kinaba: 			override int opCmp(Object rhs) {
b97bd4f713 2010-11-23        kinaba: 				if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg);
b97bd4f713 2010-11-23        kinaba: 				if(auto r = cast(Value)rhs)          return typeid(this).opCmp(typeid(r));
153a14cec0 2010-11-24        kinaba: 				throw genex!RuntimeException("comparison with value and something other");
b97bd4f713 2010-11-23        kinaba: 			}
b993a8ad16 2010-11-24        kinaba: 			override hash_t toHash() const {
b993a8ad16 2010-11-24        kinaba: 				return typeid(dg).getHash(&dg);
b993a8ad16 2010-11-24        kinaba: 			}
b97bd4f713 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			R delegate(T) dg;
b97bd4f713 2010-11-23        kinaba: 			Parameter[] params_data;
b97bd4f713 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			this(R delegate(T) dg)
b97bd4f713 2010-11-23        kinaba: 			{
b97bd4f713 2010-11-23        kinaba: 				this.dg = dg;
6ac127ddd0 2010-11-23        kinaba: 				foreach(i, Ti; T)
6ac127ddd0 2010-11-23        kinaba: 					params_data ~= new Parameter(text(i), []);
6ac127ddd0 2010-11-23        kinaba: 			}
b97bd4f713 2010-11-23        kinaba: 
b97bd4f713 2010-11-23        kinaba: 			override Value invoke(Layer lay, Table ctx, LexPosition pos)
6ac127ddd0 2010-11-23        kinaba: 			{
b97bd4f713 2010-11-23        kinaba: 				if( lay != defLay )
153a14cec0 2010-11-24        kinaba: 					throw genex!RuntimeException(pos,
153a14cec0 2010-11-24        kinaba: 						text("only ", defLay, " layer can call native function: ", name));
6ac127ddd0 2010-11-23        kinaba: 				T typed_args;
6ac127ddd0 2010-11-23        kinaba: 				foreach(i, Ti; T) {
b97bd4f713 2010-11-23        kinaba: 					typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer, pos);
6ac127ddd0 2010-11-23        kinaba: 					if( typed_args[i] is null )
153a14cec0 2010-11-24        kinaba: 						throw genex!RuntimeException(pos,
153a14cec0 2010-11-24        kinaba: 							sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name));
6ac127ddd0 2010-11-23        kinaba: 				}
6ac127ddd0 2010-11-23        kinaba: 				try {
6ac127ddd0 2010-11-23        kinaba: 					return dg(typed_args);
6ac127ddd0 2010-11-23        kinaba: 				} catch( RuntimeException e ) {
6ac127ddd0 2010-11-23        kinaba: 					throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
6ac127ddd0 2010-11-23        kinaba: 				}
6ac127ddd0 2010-11-23        kinaba: 			}
1c01f44f52 2010-11-13        kinaba: 		}
b97bd4f713 2010-11-23        kinaba: 		theContext.set(name, defLay, new NativeFunValue(dg));
6ac127ddd0 2010-11-23        kinaba: 	}
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: version(unittest) import polemy.runtime;
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) );
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( r, new IntValue(BigInt(21+21*21)) );
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) );
6ac127ddd0 2010-11-23        kinaba: 	assert_nothrow( e.globalContext.get("x",ValueLayer) );
6ac127ddd0 2010-11-23        kinaba: 	assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) );
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( r, new IntValue(BigInt(21+21*21)) );
ba11f1d551 2010-11-23        kinaba: 	assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(21+21*21) );
6ac127ddd0 2010-11-23        kinaba: 	assert_nothrow( e.globalContext.get("x",ValueLayer) );
6ac127ddd0 2010-11-23        kinaba: 	assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
ba11f1d551 2010-11-23        kinaba: 	assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(1) );
ba11f1d551 2010-11-23        kinaba: 	assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(2) );
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.evalString(`@a x=1; @b x=2; @a(x)`), new IntValue(BigInt(1)) );
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.evalString(`@a x=1; @b x=2; @b(x)`), new IntValue(BigInt(2)) );
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.evalString(`let x=1; let _ = (@a x=2;2); x`), new IntValue(BigInt(1)) );
6ac127ddd0 2010-11-23        kinaba: 	e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	assert_throw!Throwable( e.evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.evalString(`
6ac127ddd0 2010-11-23        kinaba: 		@@s(x){x};
6ac127ddd0 2010-11-23        kinaba: 		@s "+" = fun(x, y) {@value(
6ac127ddd0 2010-11-23        kinaba: 			@s(x) - @s(y)
6ac127ddd0 2010-11-23        kinaba: 		)};
6ac127ddd0 2010-11-23        kinaba: 		@s(1 + 2)
6ac127ddd0 2010-11-23        kinaba: 	`), new IntValue(BigInt(-1)) );
6ac127ddd0 2010-11-23        kinaba: }
6ac127ddd0 2010-11-23        kinaba: 
6ac127ddd0 2010-11-23        kinaba: unittest
6ac127ddd0 2010-11-23        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	assert_eq( e.evalString(`
6ac127ddd0 2010-11-23        kinaba: @@3(x){x};
6ac127ddd0 2010-11-23        kinaba: def incr(x) { x+1 };
3ae09b8cbf 2010-11-24        kinaba: @ 3 incr(x) {@value( if @ 3(x)+1< 3 then @3(x)+1 else 0 )};
6ac127ddd0 2010-11-23        kinaba: def fb(n @value @3) { @3(n) };
6ac127ddd0 2010-11-23        kinaba: fb(incr(incr(incr(0))))
6ac127ddd0 2010-11-23        kinaba: 	`), new IntValue(BigInt(0)) );
5e407d7cf8 2010-11-08        kinaba: }
5e407d7cf8 2010-11-08        kinaba: 
5e407d7cf8 2010-11-08        kinaba: unittest
5e407d7cf8 2010-11-08        kinaba: {
6ac127ddd0 2010-11-23        kinaba: 	auto e = new Evaluator;
6ac127ddd0 2010-11-23        kinaba: 	enrollRuntimeLibrary(e);
6ac127ddd0 2010-11-23        kinaba: 	assert_nothrow( e.evalString(`
6ac127ddd0 2010-11-23        kinaba: @macro twice(x) { x; x };
6ac127ddd0 2010-11-23        kinaba: def main() { twice(1) };
6ac127ddd0 2010-11-23        kinaba: main()
6ac127ddd0 2010-11-23        kinaba: 	`) );
5e407d7cf8 2010-11-08        kinaba: }
f9c31f3cd8 2010-11-24        kinaba: unittest
f9c31f3cd8 2010-11-24        kinaba: {
f9c31f3cd8 2010-11-24        kinaba: 	auto e = new Evaluator;
f9c31f3cd8 2010-11-24        kinaba: 	enrollRuntimeLibrary(e);
f9c31f3cd8 2010-11-24        kinaba: 	assert_nothrow( e.evalString(`case 1`) );
f9c31f3cd8 2010-11-24        kinaba: 	assert_nothrow( e.evalString(`case 1 when 1: 2`) );
f8684f4d69 2010-11-26        kinaba: 
f8684f4d69 2010-11-26        kinaba: 	// this is a shorthand for
f8684f4d69 2010-11-26        kinaba: 	//   @macro x = fun(){} in @macro(x)
f8684f4d69 2010-11-26        kinaba: 	// so it is ok to fail, but it is really incovenient on REPL
f8684f4d69 2010-11-26        kinaba: 	assert_nothrow( e.evalString(`@macro x=fun(){}`) );
f9c31f3cd8 2010-11-24        kinaba: }
f9c31f3cd8 2010-11-24        kinaba: 
3995a5eb6a 2010-11-21        kinaba: /*
423f308350 2010-11-07        kinaba: unittest
423f308350 2010-11-07        kinaba: {
2459e9a821 2010-11-09        kinaba: 	assert_eq( evalString(`var fac = fun(x){
633e700889 2010-11-07        kinaba: 		if(x)
633e700889 2010-11-07        kinaba: 			{ x*fac(x-1); }
633e700889 2010-11-07        kinaba: 		else
633e700889 2010-11-07        kinaba: 			{ 1; };
633e700889 2010-11-07        kinaba: 	};
2459e9a821 2010-11-09        kinaba: 	fac(10);`).val, new IntValue(BigInt(10*9*8*5040)));
2459e9a821 2010-11-09        kinaba: 	assert_eq( evalString(`var fib = fun(x){
172a537bea 2010-11-07        kinaba: 		if(x<2)
172a537bea 2010-11-07        kinaba: 			{ 1; }
172a537bea 2010-11-07        kinaba: 		else
172a537bea 2010-11-07        kinaba: 			{ fib(x-1) + fib(x-2); };
172a537bea 2010-11-07        kinaba: 	};
8e3db9ef20 2010-11-20        kinaba: 	fib(5);`).val, new IntValue(BigInt(8)));
7465fcdd7f 2010-11-09        kinaba: }
7465fcdd7f 2010-11-09        kinaba: unittest
7465fcdd7f 2010-11-09        kinaba: {
c368edbcb1 2010-11-13        kinaba: 	assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) );
060f267779 2010-11-20        kinaba: 	// there was a bug that declaration in the first line of function definition
060f267779 2010-11-20        kinaba: 	// cannot be recursive
060f267779 2010-11-20        kinaba: 	assert_nothrow( evalString(`def foo() {
060f267779 2010-11-20        kinaba:   def bar(y) { if(y<1) {0} else {bar(0)} };
060f267779 2010-11-20        kinaba:   bar(1)
060f267779 2010-11-20        kinaba: }; foo()`) );
423f308350 2010-11-07        kinaba: }
3995a5eb6a 2010-11-21        kinaba: */