Diff
Not logged in

Differences From Artifact [b119954d6ce43301]:

To Artifact [5a9949a1eb8839b1]:


8 8 import polemy._common; 9 9 import polemy.failure; 10 10 import polemy.ast; 11 11 import polemy.parse; 12 12 import polemy.value; 13 13 import polemy.layer; 14 14 15 +/// Objects for maitaining global environment and evaluation of expression on it 15 16 class Evaluator 16 17 { 17 18 public: 19 + /// Initialize evaluator with empty context 18 20 this() { theContext = new Table; } 19 21 22 + /// Evaluate the AST 20 23 Value evalAST(AST e) 21 24 { 22 25 return eval(e, ValueLayer, theContext, OverwriteCtx); 23 26 } 24 27 28 + /// Evaluate the string 25 29 Value evalString(S,T...)(S str, T fn_ln_cn) 26 30 { 27 31 return evalAST(parseString(str,fn_ln_cn)); 28 32 } 29 33 34 + /// Evaluate the file 30 35 Value evalFile(S,T...)(S filename, T ln_cn) 31 36 { 32 37 return evalAST(parseFile(filename,ln_cn)); 33 38 } 34 39 40 + /// Get the global context 35 41 Table globalContext() 36 42 { 37 43 return theContext; 38 44 } 39 45 40 46 private: 41 47 Table theContext; 42 48 43 -private: 44 49 enum : bool { CascadeCtx=false, OverwriteCtx=true }; 45 - 46 50 Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 47 51 { 48 52 // dynamic-overload-resolution-pattern: modify here 49 53 enum funName = "eval"; 50 54 alias TypeTuple!(e,lay,ctx,overwriteCtx) params; 51 55 52 56 // dynamic-overload-resolution-pattern: dispatch ................................................................................ 57 61 static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 58 62 return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 59 63 60 64 // dynamic-overload-resolution-pattern: default behavior 61 65 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 62 66 } 63 67 64 -private: 65 68 Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 66 69 { 67 - Value v = new StrValue(e.data); 68 - if( lay==RawMacroLayer || lay==MacroLayer ) 69 - { 70 - auto ast = new Table; 71 - ast.set("pos", ValueLayer, fromPos(e.pos)); 72 - ast.set("is", ValueLayer, new StrValue("str")); 73 - ast.set("data", ValueLayer, v); 74 - return ast; 75 - } 70 + if( isMacroishLayer(lay) ) 71 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 76 72 if( lay==ValueLayer ) 77 - return v; 78 - return lift(v, lay, ctx, e.pos); 73 + return new StrValue(e.data); 74 + return lift(new StrValue(e.data), lay, ctx, e.pos); 79 75 } 80 76 81 77 Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 82 78 { 83 - Value v = new IntValue(e.data); 84 - if( lay==RawMacroLayer || lay==MacroLayer ) 85 - { 86 - auto ast = new Table; 87 - ast.set("pos", ValueLayer, fromPos(e.pos)); 88 - ast.set("is", ValueLayer, new StrValue("int")); 89 - ast.set("data", ValueLayer, v); 90 - return ast; 91 - } 79 + if( isMacroishLayer(lay) ) 80 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 92 81 if( lay==ValueLayer ) 93 - return v; 94 - return lift(v, lay, ctx, e.pos); 82 + return new IntValue(e.data); 83 + return lift(new IntValue(e.data), lay, ctx, e.pos); 95 84 } 96 85 97 86 Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 98 87 { 99 - if( lay==RawMacroLayer || lay==MacroLayer ) 100 - { 88 + if( isMacroishLayer(lay) ) 101 89 if( ctx.has(e.name,MacroLayer) ) 102 90 return ctx.get(e.name, MacroLayer, e.pos); 103 - auto ast = new Table; 104 - ast.set("pos", ValueLayer, fromPos(e.pos)); 105 - ast.set("is", ValueLayer, new StrValue("var")); 106 - ast.set("name", ValueLayer, new StrValue(e.name)); 107 - return ast; 108 - } 91 + else 92 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 109 93 if( lay==ValueLayer || ctx.has(e.name, lay) ) 110 94 return ctx.get(e.name, lay, e.pos); 111 95 return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); 112 96 } 113 97 114 98 Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 115 99 { 116 100 Value f = eval( e.fun, lay, ctx ); 117 - if( lay==RawMacroLayer || lay==MacroLayer ) 118 - { 101 + if( isMacroishLayer(lay) ) 119 102 if( auto ff = cast(FunValue)f ) 120 103 return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos); 121 - Table ast = new Table; 122 - ast.set("pos", ValueLayer, fromPos(e.pos)); 123 - ast.set("is", ValueLayer, new StrValue("app")); 124 - ast.set("fun", ValueLayer, f); 125 - Table args = new Table; 126 - foreach_reverse(a; e.args) 127 - args = makeCons(eval(a, lay, ctx), args); 128 - ast.set("args", ValueLayer, args); 129 - return ast; 130 - } 131 - else 132 - { 133 - return invokeFunction(f, e.args, lay, ctx, e.pos); 134 - } 104 + else 105 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 106 + return invokeFunction(f, e.args, lay, ctx, e.pos); 135 107 } 136 108 137 109 Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 138 110 { 139 - if( lay==RawMacroLayer || lay==MacroLayer ) 140 - { 141 - Table t = new Table; 142 - t.set("pos", ValueLayer, fromPos(e.pos)); 143 - t.set("is", ValueLayer, new StrValue("fun")); 144 - t.set("funbody", ValueLayer, eval(e.funbody,lay,ctx)); 145 - Table params = new Table; 146 - foreach_reverse(p; e.params) 147 - { 148 - Table lays = new Table; 149 - foreach_reverse(l; p.layers) 150 - lays = makeCons(new StrValue(l), lays); 151 - Table kv = new Table; 152 - kv.set("name", ValueLayer, new StrValue(p.name)); 153 - kv.set("layers", ValueLayer, lays); 154 - Table cons = new Table; 155 - params = makeCons(kv, params); 156 - } 157 - t.set("params", ValueLayer, params); 158 - return t; 159 - } 111 + if( isMacroishLayer(lay) ) 112 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 160 113 else 161 - { 162 114 return createNewFunction(e, ctx); 163 - } 164 115 } 165 116 166 117 Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 167 118 { 168 - if( lay == RawMacroLayer ) 169 - { 170 - Value r = eval(e.expr, lay, ctx); 171 - auto ast = new Table; // todo: pos 172 - ast.set("pos", ValueLayer, fromPos(e.pos)); 173 - ast.set("is", ValueLayer, new StrValue("lay")); 174 - ast.set("layer", ValueLayer, new StrValue(e.layer)); 175 - ast.set("expr", ValueLayer, r); 176 - return ast; 177 - } 119 + if( isNoLayerChangeLayer(lay) ) 120 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 178 121 else 179 122 return eval(e.expr, e.layer, ctx); 180 123 } 181 124 182 125 Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 183 126 { 184 127 // todo @macro let 185 - if( lay==RawMacroLayer || lay==MacroLayer ) 186 - { 187 - auto ast = new Table; // todo: pos 188 - ast.set("pos", ValueLayer, fromPos(e.pos)); 189 - ast.set("is", ValueLayer, new StrValue("let")); 190 - ast.set("name", ValueLayer, new StrValue(e.name)); 191 - ast.set("layer", ValueLayer, new StrValue(e.layer)); 192 - ast.set("init", ValueLayer, eval(e.init, lay, ctx)); 193 - ast.set("expr", ValueLayer, eval(e.expr, lay, ctx)); 194 - return ast; 195 - } 128 + if( isMacroishLayer(lay) ) 129 + return ast2table(e, (AST e){return eval(e,lay,ctx);}); 196 130 else 197 131 { 198 132 if( !overwriteCtx ) 199 133 ctx = new Table(ctx, Table.Kind.NotPropagateSet); 200 134 Value ri = eval(e.init, lay, ctx); 201 - string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer; 135 + string theLayer = e.layer.empty ? lay : e.layer; // neutral layer 202 136 ctx.set(e.name, theLayer, ri); 203 137 return eval(e.expr, lay, ctx, OverwriteCtx); 204 138 } 205 139 } 206 140 207 141 private: 208 142 Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null) ................................................................................ 212 146 Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 213 147 foreach(i,p; f.params()) 214 148 if( p.layers.empty ) 215 149 newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx)); 216 150 else 217 151 foreach(argLay; p.layers) 218 152 newCtx.set(p.name, argLay, eval(args[i], argLay, ctx)); 219 - return f.invoke(pos, lay, newCtx); 153 + return f.invoke(lay==RawMacroLayer ? MacroLayer : lay, newCtx, pos); 220 154 } 221 155 throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 222 156 } 223 157 224 158 Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null) 225 159 { 160 + assert( !isMacroishLayer(lay), "lift to the @macro layer should not happen" ); 161 + 226 162 // functions are automatically lifterd 227 163 if( cast(FunValue) v ) 228 164 return v; 229 165 230 166 // similar to invoke Function, but with only one argument bound to ValueLayer 231 167 if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos)) 232 168 { ................................................................................ 233 169 Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 234 170 auto ps = f.params(); 235 171 if( ps.length != 1 ) 236 172 throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 237 173 if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 238 174 { 239 175 newCtx.set(ps[0].name, ValueLayer, v); 240 - return f.invoke(pos, ValueLayer, newCtx); 176 + return f.invoke(ValueLayer, newCtx, pos); 241 177 } 242 178 else 243 179 throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 244 180 } 245 181 throw genex!RuntimeException(pos, "tried to call non-function"); 246 182 } 247 183 ................................................................................ 273 209 if(auto i = this.ast.opCmp(rhs.ast)) 274 210 return i; 275 211 return this.defCtx.opCmp(rhs.defCtx); 276 212 } 277 213 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 278 214 } 279 215 280 - override Value invoke(LexPosition pos, Layer lay, Table ctx) 216 + override Value invoke(Layer lay, Table ctx, LexPosition pos) 281 217 { 282 218 if( lay == MacroLayer ) 283 219 return eval(ast.funbody, lay, ctx); 284 - auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx)); 285 - return eval(macroed, lay, ctx); 220 + if( afterMacroAST is null ) 221 + afterMacroAST = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx)); 222 + return eval(afterMacroAST, lay, ctx); 286 223 } 224 + 225 + AST afterMacroAST; 287 226 } 288 227 return new UserDefinedFunValue(e,ctx); 289 228 } 290 229 291 230 public: 292 - /// TODO: move up 293 - /// TDOO: to other layers? 294 - void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg) 231 + /// Add primitive function to the global context 232 + void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg) 295 233 { 296 234 class NativeFunValue : FunValue 297 235 { 298 - Parameter[] params_data; 299 - override string toString() { return sprintf!"(native:%x)"(dg.funcptr); } 300 236 override const(Parameter[]) params() { return params_data; } 301 - override Table definitionContext() { return new Table; } // todo: cache 302 - this(){ 237 + override Table definitionContext() { return theContext; } 238 + 239 + override string toString() { return sprintf!"(native:%x)"(dg.funcptr); } 240 + override int opCmp(Object rhs) { 241 + if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg); 242 + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 243 + throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other"); 244 + } 245 + mixin SimpleToHash; 246 + 247 + R delegate(T) dg; 248 + Parameter[] params_data; 249 + 250 + this(R delegate(T) dg) 251 + { 252 + this.dg = dg; 303 253 foreach(i, Ti; T) 304 254 params_data ~= new Parameter(text(i), []); 305 255 } 306 - override Value invoke(LexPosition pos, Layer lay, Table ctx) 256 + 257 + override Value invoke(Layer lay, Table ctx, LexPosition pos) 307 258 { 308 - if( lay != ValueLayer ) 309 - throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function"); 259 + if( lay != defLay ) 260 + throw genex!RuntimeException(pos, text("only ", defLay, " layer can call native function: ", name)); 310 261 T typed_args; 311 262 foreach(i, Ti; T) { 312 - typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer); 263 + typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer, pos); 313 264 if( typed_args[i] is null ) 314 - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 265 + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name)); 315 266 } 316 267 try { 317 268 return dg(typed_args); 318 269 } catch( RuntimeException e ) { 319 270 throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 320 271 } 321 272 } 322 273 } 323 - theContext.set(name, lay, new NativeFunValue); 274 + theContext.set(name, defLay, new NativeFunValue(dg)); 324 275 } 325 276 } 326 277 327 278 version(unittest) import polemy.runtime; 328 279 unittest 329 280 { 330 281 auto e = new Evaluator;