Index: polemy/ast.d ================================================================== --- polemy/ast.d +++ polemy/ast.d @@ -91,10 +91,14 @@ AST funbody; mixin SimpleClass; } +/// List of AST Types + +alias TypeTuple!(Int,Str,Var,Lay,Let,App,Fun) ListOfASTTypes; + /// Handy Generator for AST nodes. To use this, mixin EasyAst; /*mixin*/ template EasyAST() { Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -100,14 +100,14 @@ Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { Value f = eval( e.fun, lay, ctx ); if( isMacroishLayer(lay) ) if( auto ff = cast(FunValue)f ) - return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos); + return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos, getNameIfPossible(e.fun)); else return ast2table(e, (AST e){return eval(e,lay,ctx);}); - return invokeFunction(f, e.args, lay, ctx, e.pos); + return invokeFunction(f, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun)); } Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { if( isMacroishLayer(lay) ) @@ -139,11 +139,18 @@ return eval(e.expr, lay, ctx, OverwriteCtx); } } private: - Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null) + string getNameIfPossible(AST e) + { + if(auto v = cast(Var)e) + return v.name; + return ""; + } + + Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos, string callstackmsg) { if(auto f = cast(FunValue)_f) { Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); foreach(i,p; f.params()) @@ -150,39 +157,48 @@ if( p.layers.empty ) newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx)); else foreach(argLay; p.layers) newCtx.set(p.name, argLay, eval(args[i], argLay, ctx)); + scope _ = new PushCallStack(pos, callstackmsg); return f.invoke(lay==RawMacroLayer ? MacroLayer : lay, newCtx, pos); } throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); } - Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null) + Value lift(Value v, Layer lay, Table ctx, LexPosition pos) { - assert( !isMacroishLayer(lay), "lift to the @macro layer should not happen" ); + assert( !isMacroishLayer(lay), "lift to the @macro layer should never happen" ); // functions are automatically lifterd if( cast(FunValue) v ) return v; - // similar to invoke Function, but with only one argument bound to ValueLayer - if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos)) + if( !ctx.has(lay, SystemLayer) ) + throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); + + // similar to invokeFunction, but with only one argument bound to ValueLayer + auto _f = ctx.get(lay, SystemLayer, pos); + if(auto f = cast(FunValue)_f) { Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); auto ps = f.params(); if( ps.length != 1 ) - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); + throw genex!RuntimeException(pos, + text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) { newCtx.set(ps[0].name, ValueLayer, v); + scope _ = new PushCallStack(pos, lay); return f.invoke(ValueLayer, newCtx, pos); } else - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); + throw genex!RuntimeException(pos, + text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); } - throw genex!RuntimeException(pos, "tried to call non-function"); + throw genex!RuntimeException(pos, + text("non-function ", _f, " is registered as the lift function for ", lay)); } Value createNewFunction(Fun e, Table ctx) { class UserDefinedFunValue : FunValue @@ -217,13 +233,17 @@ override Value invoke(Layer lay, Table ctx, LexPosition pos) { if( lay == MacroLayer ) return eval(ast.funbody, lay, ctx); - if( afterMacroAST is null ) - afterMacroAST = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx)); - return eval(afterMacroAST, lay, ctx); + try { + if( afterMacroAST is null ) + afterMacroAST = polemy2d!(AST)(eval(e.funbody, RawMacroLayer, ctx), pos); + return eval(afterMacroAST, lay, ctx); + } catch( RuntimeException e ) { + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line, e.next) : e; + } } AST afterMacroAST; } return new UserDefinedFunValue(e,ctx); Index: polemy/failure.d ================================================================== --- polemy/failure.d +++ polemy/failure.d @@ -19,14 +19,11 @@ immutable int lineno; /// 1-origin immutable int column; /// 1-origin mixin SimpleClass; override string toString() const - { - return sprintf!("%s:%d:%d")(filename, lineno, column); - } - + { return sprintf!("%s:%d:%d")(filename, lineno, column); } static LexPosition dummy; static this(){ dummy = new LexPosition("",0,0); } } unittest @@ -52,17 +49,52 @@ template ExceptionWithPosition() { LexPosition pos; this( LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null ) { - if(pos is null) - super(sprintf!("[??] %s")(msg), file, line, next); - else - super(sprintf!("[%s] %s")(pos, msg), file, line, next); + string fullmsg = pos is null ? sprintf!("\n[??] %s")(msg) + : sprintf!("\n[%s] %s")(pos, msg); + for(int i=0; i",">="], -// ["|"], -// ["^"], -// ["&"], -// ["<<", ">>", "<<<", ">>>"], + ["|"], + ["^"], + ["&"], + ["<<", ">>", "<<<", ">>>"], ["+","-"], ["~"], ["*","/","%"], -// ["^^","**"], + ["^^","**"], [".",".?"] ]; AST E(size_t level) { Index: polemy/runtime.d ================================================================== --- polemy/runtime.d +++ polemy/runtime.d @@ -1,50 +1,70 @@ + /** * Authors: k.inaba * License: NYSL 0.9982 http://www.kmonos.net/nysl/ * * Runtime library for Polemy programming language. */ module polemy.runtime; import polemy._common; import polemy.layer; +import polemy.failure; import polemy.value; import polemy.eval; import std.stdio; /// enroll the native implementations of primitive functions void enrollRuntimeLibrary( Evaluator e ) { - e.addPrimitive("+", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ); - e.addPrimitive("-", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ); - e.addPrimitive("*", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ); - e.addPrimitive("/", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} ); - e.addPrimitive("%", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ); - e.addPrimitive("~", ValueLayer, (Value lhs, Value rhs){return new StrValue(lhs.toString ~ rhs.toString);} ); - e.addPrimitive("||", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data!=0 || rhs.data!=0);} ); - e.addPrimitive("&&", ValueLayer, (IntValue lhs, IntValue rhs){return new IntValue(lhs.data!=0 && rhs.data!=0);} ); + // arithmetic operations + e.addPrimitive("+", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ); + e.addPrimitive("-", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ); + e.addPrimitive("*", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ); + e.addPrimitive("/", ValueLayer, + (IntValue lhs, IntValue rhs){ + if( rhs.data == 0 ) + throw genex!RuntimeException("division by 0"); + return new IntValue(lhs.data / rhs.data); + }); + e.addPrimitive("%", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ); + e.addPrimitive("||", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data!=0 || rhs.data!=0);} ); + e.addPrimitive("&&", ValueLayer, + (IntValue lhs, IntValue rhs){return new IntValue(lhs.data!=0 && rhs.data!=0);} ); + // string operation(s) + e.addPrimitive("~", ValueLayer, + (Value lhs, Value rhs){return new StrValue(lhs.toString ~ rhs.toString);} ); + // comparison e.addPrimitive("<", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs < rhs);} ); e.addPrimitive(">", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs > rhs);} ); e.addPrimitive("<=", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs <= rhs);} ); e.addPrimitive(">=", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs >= rhs);} ); e.addPrimitive("==", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs == rhs);} ); e.addPrimitive("!=", ValueLayer, (Value lhs, Value rhs){return new IntValue(lhs != rhs);} ); - e.addPrimitive("print", ValueLayer, (Value a){ - writeln(a); - return new IntValue(0); - }); + // control flow e.addPrimitive("if", ValueLayer, (IntValue x, FunValue ft, FunValue fe){ auto toRun = (x.data==0 ? fe : ft); - // [TODO] fill positional information return toRun.invoke(ValueLayer, toRun.definitionContext(), null); }); - e.addPrimitive("_isint", ValueLayer, (Value v){return new IntValue(cast(IntValue)v !is null);} ); - e.addPrimitive("_isstr", ValueLayer, (Value v){return new IntValue(cast(StrValue)v !is null);} ); - e.addPrimitive("_isfun", ValueLayer, (Value v){return new IntValue(cast(FunValue)v !is null);} ); - e.addPrimitive("_isundefined", ValueLayer, (Value v){return new IntValue(cast(UndefinedValue)v !is null);} ); - e.addPrimitive("_istable", ValueLayer, (Value v){return new IntValue(cast(Table)v !is null);} ); + // type test + e.addPrimitive("_isint", ValueLayer, + (Value v){return new IntValue(cast(IntValue)v !is null);} ); + e.addPrimitive("_isstr", ValueLayer, + (Value v){return new IntValue(cast(StrValue)v !is null);} ); + e.addPrimitive("_isfun", ValueLayer, + (Value v){return new IntValue(cast(FunValue)v !is null);} ); + e.addPrimitive("_isundefined", ValueLayer, + (Value v){return new IntValue(cast(UndefinedValue)v !is null);} ); + e.addPrimitive("_istable", ValueLayer, + (Value v){return new IntValue(cast(Table)v !is null);} ); + // table e.addPrimitive(".", ValueLayer, (Table t, StrValue s){ return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndefinedValue); }); e.addPrimitive(".?", ValueLayer, (Table t, StrValue s){ return new IntValue(t.has(s.data, ValueLayer)); @@ -55,6 +75,8 @@ return t2; }); e.addPrimitive("{}", ValueLayer, (){ return new Table; }); + // IO + e.addPrimitive("print", ValueLayer, (Value a){ writeln(a); return new IntValue(0); }); } Index: polemy/value.d ================================================================== --- polemy/value.d +++ polemy/value.d @@ -77,31 +77,25 @@ /// But extended with the notion of "Layer" class Table : Value { enum Kind {PropagateSet, NotPropagateSet}; - bool kill = false; // to refactor this( Table proto=null, Kind k = Kind.PropagateSet ) { this.prototype = proto; this.kind = k; } - void set(string i, Layer lay, Value v, LexPosition pos=null) + void set(string i, Layer lay, Value v) { if( setIfExist(i, lay, v) ) return; data[i][lay] = v; } bool has(string i, Layer lay) const { - if( i in data ) { - if( lay !in data[i] ) - return false; - if(kill) - return false; - return true; - } + if( i in data ) + return !!(lay in data[i]); if( prototype is null ) return false; return prototype.has(i, lay); } @@ -108,17 +102,15 @@ Value get(string i, Layer lay, LexPosition pos=null) { if( i in data ) { // [TODO] consider forwarding to proto also in this case if( lay !in data[i] ) - throw genex!RuntimeException(pos, sprintf!"'%s' is not set in layer %s"(i,lay)); - if(kill) - throw genex!RuntimeException(pos, sprintf!"'%s' is killed in macro"(i)); + throw genex!RuntimeException(pos, sprintf!"'%s' is not set in %s layer"(i,lay)); return data[i][lay]; } if( prototype is null ) - throw new RuntimeException(pos, sprintf!"'%s' not found"(i)); + throw genex!RuntimeException(pos, sprintf!"'%s' not found in %s layer"(i,lay)); return prototype.get(i, lay, pos); } T access(T,S...)( Layer lay, string path, S rest ) { @@ -156,15 +148,54 @@ result ~= " / "; result ~= prototype.toStringWithoutParen(); } return result; } - - string toString() const + + string toString() { + if( isList() ) + return text(toList()); return "{" ~ toStringWithoutParen() ~ "}"; } + +public: + /// Is this an empty table? + bool empty() + { + return data.length==0 && (prototype is null || prototype.empty); + } + + /// Can be seen as a cons-list? + bool isList() + { + Table t = this; + while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) + if(auto tt = cast(Table)t.get("cdr", ValueLayer)) + t = tt; + else + return false; + return t.empty; + } + + /// Regard table as a cons-list and convert to an array + Value[] toList() + { + Value[] result; + Table t = this; + while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) + { + result ~= t.get("car", ValueLayer); + if(auto tt = cast(Table)t.get("cdr", ValueLayer)) + t = tt; + else + throw genex!RuntimeException("this table is not a cons-list"); + } + if( t.empty ) + return result; + throw genex!RuntimeException("this table is not a cons-list"); + } private: Table prototype; Kind kind; Value[Layer][string] data; @@ -187,36 +218,36 @@ Table c0 = new Table; Table c01 = new Table(c0, Table.Kind.NotPropagateSet); Table c012 = new Table(c01, Table.Kind.PropagateSet); Table c013 = new Table(c01, Table.Kind.PropagateSet); - assert_nothrow( c012.set("x", ValueLayer, new IntValue(BigInt(12))) ); + assert_nothrow( c012.set("x", ValueLayer, new IntValue(12)) ); assert_throw!RuntimeException( c013.get("x", ValueLayer) ); - assert_nothrow( c013.set("x", ValueLayer, new IntValue(BigInt(13))) ); - assert_eq( c013.get("x", ValueLayer), new IntValue(BigInt(13)) ); - assert_eq( c012.get("x", ValueLayer), new IntValue(BigInt(12)) ); + assert_nothrow( c013.set("x", ValueLayer, new IntValue(13)) ); + assert_eq( c013.get("x", ValueLayer), new IntValue(13) ); + assert_eq( c012.get("x", ValueLayer), new IntValue(12) ); assert_throw!RuntimeException( c01.get("x", ValueLayer) ); - assert_nothrow( c01.set("y", ValueLayer, new IntValue(BigInt(1))) ); - assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(1)) ); - assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(1)) ); - assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(1)) ); + assert_nothrow( c01.set("y", ValueLayer, new IntValue(1)) ); + assert_eq( c013.get("y", ValueLayer), new IntValue(1) ); + assert_eq( c012.get("y", ValueLayer), new IntValue(1) ); + assert_eq( c01.get("y", ValueLayer), new IntValue(1) ); + + assert_nothrow( c0.set("z", ValueLayer, new IntValue(0)) ); + assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c012.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); - assert_nothrow( c0.set("z", ValueLayer, new IntValue(BigInt(0))) ); - assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); + assert_nothrow( c012.set("y", ValueLayer, new IntValue(444)) ); + assert_eq( c013.get("y", ValueLayer), new IntValue(444) ); + assert_eq( c012.get("y", ValueLayer), new IntValue(444) ); + assert_eq( c01.get("y", ValueLayer), new IntValue(444) ); - assert_nothrow( c012.set("y", ValueLayer, new IntValue(BigInt(444))) ); - assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(444)) ); - assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(444)) ); - assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(444)) ); - - assert_nothrow( c012.set("z", ValueLayer, new IntValue(BigInt(555))) ); - assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(555)) ); - assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); + assert_nothrow( c012.set("z", ValueLayer, new IntValue(555)) ); + assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c012.get("z", ValueLayer), new IntValue(555) ); + assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); // [TODO] define the semantics and test @layers } Index: polemy/valueconv.d ================================================================== --- polemy/valueconv.d +++ polemy/valueconv.d @@ -12,132 +12,97 @@ import polemy.value; import std.string; LexPosition extractPos( Table t ) { - Layer theLayer = ValueLayer; - if(auto tt = t.access!Table(theLayer, "pos")) + if(auto tt = t.access!Table(ValueLayer, "pos")) { - auto fn = tt.access!StrValue(theLayer, "filename"); - auto ln = tt.access!IntValue(theLayer, "lineno"); - auto cl = tt.access!IntValue(theLayer, "column"); + auto fn = tt.access!StrValue(ValueLayer, "filename"); + auto ln = tt.access!IntValue(ValueLayer, "lineno"); + auto cl = tt.access!IntValue(ValueLayer, "column"); if(fn !is null && ln !is null && cl !is null) return new LexPosition(fn.data,cast(int)ln.data.toInt,cast(int)cl.data.toInt); } return null; } -Value[] tableAsConsList( Layer theLayer, Table t ) -{ - Value[] result; - while(t) - if(auto v = t.access!Value(theLayer, "car")) - { - result ~= v; - t = t.access!Table(theLayer, "cdr"); - } - else - break; - return result; -} +/// Experimental!! Convert Polemy value to D Value -AST[] tableToASTList( Layer theLayer, Table t ) +T polemy2d(T)(Value _v, LexPosition callpos=null) { - AST[] result; - foreach(v; tableAsConsList(theLayer, t)) - if(auto t = cast(Table)v) - result ~= tableToAST(theLayer,t); - else - throw genex!RuntimeException(cast(LexPosition)null, "Invalid AST (non-table in cons-list)"); - return result; -} + static if(is(T==BigInt)) + { + if(auto v = cast(IntValue)_v) + return v.data; + } + else + static if(isIntegral!(T)) + { + if(auto v = cast(IntValue)_v) + return cast(T) v.data.toLong(); + } + else + static if(is(T==string)) + { + if(auto v = cast(StrValue)_v) + return v.data; + } + else + static if(is(T S : S[])) + { + if(auto t = cast(Table)_v) + { + S[] result; + foreach(e; t.toList()) + result ~= polemy2d!(S)(e, callpos); + return result; + } + } + else + static if(is(T == AST)) + { + if(auto t = cast(Table)_v) + { + LexPosition pos = extractPos(t); -AST tableToAST( Layer theLayer, Value vvvv ) -{ - Table t = cast(Table)vvvv; - if( t is null ) - throw genex!RuntimeException(cast(LexPosition)null, "Invalid AST (not a table)"); + StrValue typ = cast(StrValue) t.access!StrValue(ValueLayer, "is"); + if( typ is null ) + throw genex!RuntimeException(text(`Invalid AST (no "is" field): `, _v)); - auto nodeType = t.access!StrValue(theLayer, "is"); - if( nodeType is null ) - throw genex!RuntimeException(cast(LexPosition)null, "Invalid AST {is:(not string)}"); - auto pos = extractPos(t); - switch(nodeType.data) + foreach(AT; ListOfASTTypes) + if(typ.data == typeid(AT).name.split(".")[$-1].tolower()) + { + typeof(AT.tupleof) mems; + foreach(i,m; mems) + { + string name = AT.tupleof[i].stringof.split(".")[$-1]; + Value vm = t.access!Value(ValueLayer, name); + if( vm is null ) + throw genex!RuntimeException(callpos, + text(`Invalid AST (no "`,name,`" field) for "`, typ, `" node: `, _v)); + mems[i] = polemy2d!(typeof(m))(vm, callpos); + } + return new AT(pos,mems); + } + throw genex!RuntimeException(callpos, text(`Invalid AST (unknown "is" field): `, typ)); + } + throw genex!RuntimeException(callpos, text(`Invalid AST (not a table): `, _v)); + } + else + static if(is(T == class)) { - case "int": - if(auto v = t.access!IntValue(theLayer, "data")) - return new Int(pos, v.data); - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"int", data:(not int)}`); - case "str": - if(auto v = t.access!StrValue(theLayer, "data")) - return new Str(pos, v.data); - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"str", data:(not string)}`); - case "var": - if(auto v = t.access!StrValue(theLayer, "name")) - return new Var(pos, v.data); - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"var", name:(not string)}`); - case "lay": - if(auto v = t.access!StrValue(theLayer, "layer")) - if(auto e = t.access!Table(theLayer, "expr")) - return new Lay(pos, v.data, tableToAST(theLayer,e)); - else - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"lay", expr:(not table)}`); - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"lay", layer:(not string)}`); - case "let": - if(auto n = t.access!StrValue(theLayer, "name")) - if(auto e = t.access!Table(theLayer, "init")) - if(auto b = t.access!Table(theLayer, "expr")) + if(auto t = cast(Table)_v) { - string nn = n.data; - auto ee = tableToAST(theLayer, e); - auto bb = tableToAST(theLayer, b); - Layer lay=""; - if(auto l = t.access!StrValue(theLayer, "layer")) - lay = l.data; - return new Let(pos, nn, lay, ee, bb); + typeof(T.tupleof) mems; + foreach(i,m; mems) + mems[i] = polemy2d!(typeof(m))(t.get(T.tupleof[i].stringof.split(".")[$-1], ValueLayer), callpos); + return new T(mems); } - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"let", name:"???", init:"???", expr:"???"}`); - case "app": - if(auto f = t.access!Table(theLayer, "fun")) - if(auto a = t.access!Table(theLayer, "args")) - return new App(pos, tableToAST(theLayer,f), tableToASTList(theLayer,a)); - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"app", fun:???, args:???}`); - case "fun": - if(auto p = t.access!Table(theLayer, "params")) - if(auto b = t.access!Table(theLayer, "funbody")) - { - Parameter[] ps; - foreach(v; tableAsConsList(theLayer, p)) - { - if(auto tt = cast(Table)v) - if(auto ss = tt.access!StrValue(theLayer, "name")) - if(auto ll = tt.access!Table(theLayer, "layers")) - { - Layer[] ls; - foreach(lll; tableAsConsList(theLayer, ll)) - if(auto l = cast(StrValue)lll) - ls ~= l.data; - else - throw genex!RuntimeException(cast(LexPosition)null, sprintf!`Invalid AST {bad fun params %s}`(lll)); - ps ~= new Parameter(ss.data, ls); - continue; - } - else - { - Layer[] emp; - ps ~= new Parameter(ss.data, emp); - continue; - } - throw genex!RuntimeException(cast(LexPosition)null, sprintf!`Invalid AST {bad fun params %s}`(v)); - } - auto bb = tableToAST(theLayer, b); - return new Fun(pos,ps,bb); - } - throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"fun", param:???, body:???}`); - default: - throw genex!RuntimeException(cast(LexPosition)null, sprintf!`Invalid AST {is: "%s"} unknown`(nodeType.data)); } + else + static assert(false, "unknown type <"~T.stringof~"> during polemy2d decoding"); + throw genex!RuntimeException(callpos, text("Cannot convert ",_v," to ",T.stringof)); } /// Cons of two pairs Table makeCons(Value a, Value d) @@ -146,11 +111,11 @@ t.set("car", ValueLayer, a); t.set("cdr", ValueLayer, d); return t; } -/// Experimental!!! Convert D value (except AST) to Polemy Value +/// Experimental!! Convert D value (except AST) to Polemy Value Value d2polemy(T)(T e) { return ast2table(e, delegate Value(AST){ assert(false); }); } @@ -182,13 +147,13 @@ auto t = new Table; t.set("pos", ValueLayer, ast2table(e.pos,rec)); t.set("is" , ValueLayer, new StrValue(typeid(e).name.split(".")[$-1].tolower())); foreach(i,m; e.tupleof) static if(is(typeof(m) : AST)) - t.set(e.tupleof[i].stringof[2..$], ValueLayer, rec(m)); + t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, rec(m)); else - t.set(e.tupleof[i].stringof[2..$], ValueLayer, ast2table(m,rec)); + t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, ast2table(m,rec)); return t; } else static if(is(T == class)) {