Artifact Content
Not logged in

Artifact 9a9618fb0277f9667ee0044c0c000d52da2e40f1


     1  /**
     2   * Authors: k.inaba
     3   * License: NYSL 0.9982 http://www.kmonos.net/nysl/
     4   *
     5   * Evaluator for Polemy programming language.
     6   */
     7  module polemy.eval;
     8  import polemy._common;
     9  import polemy.failure;
    10  import polemy.ast;
    11  import polemy.parse;
    12  import polemy.value;
    13  import polemy.layer;
    14  import std.typecons;
    15  import std.stdio;
    16  
    17  ///
    18  Table createGlobalContext()
    19  {
    20  	auto ctx = new Table;
    21  	ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ));
    22  	ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ));
    23  	ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ));
    24  	ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} ));
    25  	ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ));
    26  	ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} ));
    27  	ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} ));
    28  	ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} ));
    29  	ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} ));
    30  	ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} ));
    31  	ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} ));
    32  	ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} ));
    33  	ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} ));
    34  	ctx.set("print", ValueLayer, native( (Value a){
    35  		writeln(a);
    36  		return new IntValue(BigInt(0));
    37  	}));
    38  	ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){
    39  		auto toRun = (x.data==0 ? fe : ft);
    40  		// [TODO] fill positional information
    41  		return toRun.invoke(null, ValueLayer, toRun.definitionContext());
    42  //		return toRun.invoke(pos, lay, toRun.definitionContext());
    43  	}));
    44  	ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} ));
    45  	ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} ));
    46  	ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} ));
    47  	ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} ));
    48  	ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} ));
    49  	ctx.set(".", ValueLayer, native( (Table t, StrValue s){
    50  		return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue);
    51  	}) );
    52  	ctx.set(".?", ValueLayer, native( (Table t, StrValue s){
    53  		return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0));
    54  	}) );
    55  	ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){
    56  		auto t2 = new Table(t, Table.Kind.NotPropagateSet);
    57  		t2.set(s.data, ValueLayer, v);
    58  		return t2;
    59  	}) );
    60  	ctx.set("{}", ValueLayer, native( (){
    61  		return new Table;
    62  	}) );
    63  	return ctx;
    64  }
    65  
    66  /// Entry point of this module
    67  
    68  Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
    69  {
    70  	return eval( polemy.parse.parseString(str, fn_ln_cn) );
    71  }
    72  
    73  /// Entry point of this module
    74  
    75  Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn)
    76  {
    77  	return eval( polemy.parse.parseFile(filename, ln_cn) );
    78  }
    79  
    80  /// Entry point of this module
    81  
    82  Tuple!(Value,"val",Table,"ctx") eval(AST e)
    83  {
    84  	Table ctx = createGlobalContext();
    85  	return typeof(return)(eval(e, ctx, false, ValueLayer), ctx);
    86  }
    87  
    88  Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false)
    89  {
    90  	if(auto f = cast(FunValue)_f)
    91  	{
    92  		Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
    93  		foreach(i,p; f.params())
    94  			if( p.layers.empty )
    95  				if(lay==MacroLayer)
    96  					ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro));
    97  				else
    98  					ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay));
    99  			else
   100  				foreach(argLay; p.layers)
   101  					if(argLay==MacroLayer)
   102  						ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro));
   103  					else
   104  						ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay));
   105  		return f.invoke(pos, lay, ctx);
   106  	}
   107  	throw genex!RuntimeException(pos, "tried to call non-function");
   108  }
   109  
   110  Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx)
   111  {
   112  	// functions are automatically lifterd
   113  	if( cast(FunValue) v )
   114  		return v;
   115  	
   116  	// similar to invoke Function, but with only one argument bound to ValueLayer
   117  	Value _f = callerCtx.get(lay, SystemLayer, pos);
   118  	if(auto f = cast(FunValue)_f)
   119  	{
   120  		Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
   121  		auto ps = f.params();
   122  		if( ps.length != 1 )
   123  			throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
   124  		if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
   125  		{
   126  			ctx.set(ps[0].name, ValueLayer, v);
   127  			return f.invoke(pos, ValueLayer, ctx);
   128  		}
   129  		else
   130  			throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
   131  	}
   132  	throw genex!RuntimeException(pos, "tried to call non-function");
   133  }
   134  
   135  /// Entry point of this module
   136  /// If splitCtx = true, then inner variable declaration do not overwrite ctx.
   137  /// lay is the layer ID for evaluation (standard value semantics uses ValueLayer).
   138  
   139  Value eval(AST e, Table ctx, bool splitCtx, Layer lay)
   140  {
   141  	return e.match(
   142  		(StrLiteral e)
   143  		{
   144  			Value v = new StrValue(e.data);
   145  			if( lay == ValueLayer )
   146  				return v;
   147  			else
   148  				return lift(e.pos,v,lay,ctx);
   149  		},
   150  		(IntLiteral e)
   151  		{
   152  			Value v = new IntValue(e.data);
   153  			if( lay == ValueLayer )
   154  				return v;
   155  			else // rise
   156  				return lift(e.pos,v,lay,ctx);
   157  		},
   158  		(VarExpression e)
   159  		{
   160  			if( lay == ValueLayer )
   161  				return ctx.get(e.name, lay, e.pos);
   162  			if( ctx.has(e.name, lay, e.pos) )
   163  				return ctx.get(e.name, lay, e.pos);
   164  			else
   165  				return lift(e.pos, ctx.get(e.name, ValueLayer, e.pos), lay, ctx);
   166  		},
   167  		(LayExpression e)
   168  		{
   169  			if( e.layer == MacroLayer )
   170  				return macroEval(e.expr, ctx, false);
   171  			else
   172  				return eval(e.expr, ctx, true, e.layer);
   173  		},
   174  		(LetExpression e)
   175  		{
   176  			// for letrec, we need this, but should avoid overwriting????
   177  			// ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos);
   178  			if(splitCtx)
   179  				ctx = new Table(ctx, Table.Kind.NotPropagateSet);
   180  			Value v = eval(e.init, ctx, true, lay);
   181  			ctx.set(e.name, (e.layer.length ? e.layer : lay), v, e.pos);
   182  			return eval(e.expr, ctx, false, lay);
   183  		},
   184  		(FuncallExpression e)
   185  		{
   186  			return invokeFunction(e.pos, eval(e.fun, ctx, true, lay), e.args, ctx, lay);
   187  		},
   188  		(FunLiteral e)
   189  		{
   190  			return new UserDefinedFunValue(e, ctx);
   191  		},
   192  		delegate Value (AST e)
   193  		{
   194  			throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
   195  		}
   196  	);
   197  }
   198  
   199  // [TODO] Optimization
   200  Value macroEval(AST e, Table ctx, bool AlwaysMacro)
   201  {
   202  	Layer theLayer = ValueLayer;
   203  
   204  	Table makeCons(Value a, Value d)
   205  	{
   206  		Table t = new Table;
   207  		t.set("car", theLayer, a);
   208  		t.set("cdr", theLayer, d);
   209  		return t;
   210  	}
   211  
   212  	Table pos = new Table;
   213  	if( e.pos !is null ) {
   214  		pos.set("filename", theLayer, new StrValue(e.pos.filename));
   215  		pos.set("lineno",   theLayer, new IntValue(BigInt(e.pos.lineno)));
   216  		pos.set("column",   theLayer, new IntValue(BigInt(e.pos.column)));
   217  	} else {
   218  		pos.set("filename", theLayer, new StrValue("nullpos"));
   219  		pos.set("lineno",   theLayer, new IntValue(BigInt(0)));
   220  		pos.set("column",   theLayer, new IntValue(BigInt(0)));
   221  	}
   222  
   223  	return e.match(
   224  		(StrLiteral e)
   225  		{
   226  			Table t = new Table;
   227  			t.set("pos",  theLayer, pos);
   228  			t.set("is",   theLayer, new StrValue("str"));
   229  			t.set("data", theLayer, new StrValue(e.data));
   230  			return t;
   231  		},
   232  		(IntLiteral e)
   233  		{
   234  			Table t = new Table;
   235  			t.set("pos",  theLayer, pos);
   236  			t.set("is",   theLayer, new StrValue("int"));
   237  			t.set("data", theLayer, new IntValue(e.data));
   238  			return t;
   239  		},
   240  		(VarExpression e)
   241  		{
   242  			if( ctx.has(e.name, MacroLayer, e.pos) )
   243  				return ctx.get(e.name, MacroLayer, e.pos);
   244  			else {
   245  				Table t = new Table;
   246  				t.set("pos",  theLayer, pos);
   247  				t.set("is",   theLayer, new StrValue("var"));
   248  				t.set("name", theLayer, new StrValue(e.name));
   249  				return cast(Value)t;
   250  			}
   251  		},
   252  		(LayExpression e)
   253  		{
   254  			if( AlwaysMacro )
   255  			{
   256  				Table t = new Table;
   257  				t.set("pos",   theLayer, pos);
   258  				t.set("is",    theLayer, new StrValue("lay"));
   259  				t.set("layer", theLayer, new StrValue(e.layer));
   260  				t.set("expr",  theLayer, macroEval(e.expr,ctx,AlwaysMacro));
   261  				return cast(Value)t;
   262  			}
   263  			else
   264  			{
   265  				if( e.layer == MacroLayer )
   266  					return macroEval(e.expr, ctx, false);
   267  				else
   268  					return eval(e.expr, ctx, true, e.layer);
   269  			}
   270  		},
   271  		(LetExpression e)
   272  		{
   273  			Table t = new Table;
   274  			t.set("pos",  theLayer, pos);
   275  			t.set("is",   theLayer, new StrValue("let"));
   276  			t.set("name", theLayer, new StrValue(e.name));
   277  			t.set("init", theLayer, macroEval(e.init,ctx,AlwaysMacro));
   278  			t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
   279  			return t;
   280  		},
   281  		(FuncallExpression e)
   282  		{
   283  			Value _f = macroEval(e.fun,ctx,AlwaysMacro);
   284  
   285  			if( auto f = cast(FunValue)_f )
   286  				return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro);
   287  
   288  			Table t = new Table;
   289  			t.set("pos",  theLayer, pos);
   290  			t.set("is",   theLayer, new StrValue("app"));
   291  			t.set("fun",  theLayer, _f);
   292  			Table args = new Table;
   293  			foreach_reverse(a; e.args) {
   294  				Table cons = new Table;
   295  				cons.set("car",theLayer,macroEval(a,ctx,AlwaysMacro));
   296  				cons.set("cdr",theLayer,args);
   297  				args = cons;
   298  			}
   299  			t.set("args", theLayer, args);
   300  			return cast(Value)t;
   301  		},
   302  		(FunLiteral e)
   303  		{
   304  			Table t = new Table;
   305  			t.set("pos",   theLayer, pos);
   306  			t.set("is",    theLayer, new StrValue("fun"));
   307  			t.set("funbody",  theLayer, macroEval(e.funbody,ctx,AlwaysMacro));
   308  			Table params = new Table;
   309  			foreach_reverse(p; e.params)
   310  			{
   311  				Table lays = new Table;
   312  				foreach_reverse(lay; p.layers)
   313  					lays = makeCons(new StrValue(lay), lays);
   314  				Table kv = new Table;
   315  				kv.set("name", theLayer, new StrValue(p.name));
   316  				kv.set("layers", theLayer, lays);
   317  				Table cons = new Table;
   318  				params = makeCons(kv, params);
   319  			}
   320  			t.set("params", theLayer, params);
   321  			return t;
   322  		},
   323  		delegate Value (AST e)
   324  		{
   325  			throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
   326  		}
   327  	);
   328  }
   329  
   330  unittest
   331  {
   332  	auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
   333  	assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
   334  	assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) );
   335  	assert_nothrow( r.ctx.get("x",ValueLayer) );
   336  	assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
   337  }
   338  unittest
   339  {
   340  	auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
   341  	assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
   342  	assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
   343  	assert_nothrow( r.ctx.get("x",ValueLayer) );
   344  	assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
   345  }
   346  unittest
   347  {
   348  	assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) ); 
   349  	assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) ); 
   350  }
   351  unittest
   352  {
   353  	assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt(1)) );
   354  	assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt(2)) );
   355  	assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValue(BigInt(1)) );
   356  	assert_throw!Throwable( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
   357  }
   358  /*
   359  unittest
   360  {
   361  	assert_eq( evalString(`var fac = fun(x){
   362  		if(x)
   363  			{ x*fac(x-1); }
   364  		else
   365  			{ 1; };
   366  	};
   367  	fac(10);`).val, new IntValue(BigInt(10*9*8*5040)));
   368  	assert_eq( evalString(`var fib = fun(x){
   369  		if(x<2)
   370  			{ 1; }
   371  		else
   372  			{ fib(x-1) + fib(x-2); };
   373  	};
   374  	fib(5);`).val, new IntValue(BigInt(8)));
   375  }
   376  
   377  unittest
   378  {
   379  	assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) );
   380  	assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) );
   381  	assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) );
   382  	assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) );
   383  }
   384  
   385  unittest
   386  {
   387  	assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) );
   388  	// there was a bug that declaration in the first line of function definition
   389  	// cannot be recursive
   390  	assert_nothrow( evalString(`def foo() {
   391    def bar(y) { if(y<1) {0} else {bar(0)} };
   392    bar(1)
   393  }; foo()`) );
   394  }
   395  */