Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -10,64 +10,55 @@ import polemy.ast; import polemy.parse; import polemy.value; import std.typecons; import std.stdio; + +// [todo] move to value.d + +FunValue nativef(Value delegate(immutable LexPosition pos, Layer lay, Value[] args) dg) +{ + return new FunValue(dg); +} + +FunValue native(R,T...)(R delegate (T) dg) +{ + return nativef( delegate Value(immutable LexPosition pos, Layer lay, Value[] args) { + if( lay != "@v" ) + throw genex!RuntimeException(pos, "only @v layer can call native function"); + if( T.length != args.length ) + throw genex!RuntimeException(pos, "argument number mismatch!"); + T typed_args; + foreach(i, Ti; T) + { + typed_args[i] = cast(Ti) args[i]; + if( typed_args[i] is null ) + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i)); + } + try { + return dg(typed_args); + } catch( RuntimeException e ) { + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; + } + }); +} /// Table createGlobalContext() { auto ctx = new Table; - // [TODO] autogenerate these typechecks - ctx.set("+", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot add non-integers"); - })); - ctx.set("-", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot subtract non-integers"); - })); - ctx.set("*", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot multiply non-integers"); - })); - ctx.set("/", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot divide non-integers"); - })); - ctx.set("<", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot compare non-integers"); - })); - ctx.set(">", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 2 ) - throw genex!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 genex!RuntimeException(pos, "cannot compare non-integers"); - })); + ctx.set("+", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} )); + ctx.set("-", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} )); + ctx.set("*", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} )); + ctx.set("/", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} )); + ctx.set("%", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} )); + ctx.set("<", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data < rhs.data ? 1: 0));} )); + ctx.set(">", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data > rhs.data ? 1: 0));} )); + ctx.set("<=", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data <= rhs.data ? 1: 0));} )); + ctx.set(">=", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data >= rhs.data ? 1: 0));} )); + ctx.set("==", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data == rhs.data ? 1: 0));} )); + ctx.set("!=", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt(lhs.data != rhs.data ? 1: 0));} )); ctx.set("print", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ foreach(a; args) write(a); writeln(""); return new IntValue(BigInt(178)); @@ -107,36 +98,36 @@ } /// Entry point of this module /// If splitCtx = true, then inner variable declaration do not overwrite ctx. /// lay is the layer ID for evaluation (standard value semantics uses "@v"). -import std.typetuple; + Value eval(AST e, Table ctx, bool splitCtx, Layer lay) { return e.match( (StrLiteral e) { Value v = new StrValue(e.data); if( lay == "@v" ) return v; - else + else // rise return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); }, (IntLiteral e) { Value v = new IntValue(e.data); if( lay == "@v" ) return v; - else // are these "@v"s appropriate??? + else // rise return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); }, (VarExpression e) { try { return ctx.get(e.var, lay, e.pos); } catch( RuntimeException ) { - // rise + // rise from @v return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [ctx.get(e.var, "@v", e.pos)] ); } }, @@ -164,11 +155,12 @@ return f.call(e.pos, lay, args); } throw genex!RuntimeException(e.pos, "Non-funcion is applied"); }, (FunLiteral e) - { + { + // funvalue need not be rised return new FunValue(delegate Value(immutable LexPosition pos, string lay, Value[] args){ if( e.params.length != args.length ) throw genex!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);