Diff
Not logged in

Differences From Artifact [8d6e708eceba536a]:

To Artifact [10da2d7378e56ec4]:


21 public: 21 public: 22 /// Initialize evaluator with empty context 22 /// Initialize evaluator with empty context 23 this() { theContext = new Table; } 23 this() { theContext = new Table; } 24 24 25 /// Evaluate the AST 25 /// Evaluate the AST 26 Value evalAST(AST e) 26 Value evalAST(AST e) 27 { 27 { 28 AST[void*] mandeCache; < 29 return macroAndEval(e, ValueLayer, theContext, OverwriteCtx, man | 28 return macroAndEval(e, ValueLayer, theContext, OverwriteCtx); 30 } 29 } 31 30 32 /// Evaluate the string 31 /// Evaluate the string 33 Value evalString(S,T...)(S str, T fn_ln_cn) 32 Value evalString(S,T...)(S str, T fn_ln_cn) 34 { 33 { 35 return evalAST(parseString(str,fn_ln_cn)); 34 return evalAST(parseString(str,fn_ln_cn)); 36 } 35 } ................................................................................................................................................................................ 48 } 47 } 49 48 50 private: 49 private: 51 Table theContext; 50 Table theContext; 52 51 53 enum : bool { CascadeCtx=false, OverwriteCtx=true }; 52 enum : bool { CascadeCtx=false, OverwriteCtx=true }; 54 53 55 Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) | 54 LayerEval getLayerEvaluator(Layer lay) 56 { 55 { 57 // dynamic-overload-resolution-pattern: modify here | 56 if( lay == ValueLayer ) 58 enum funName = "eval"; | 57 return new ValueLayerEval; 59 alias TypeTuple!(e,lay,ctx,overwriteCtx) params; | 58 if( lay == RawMacroLayer ) 60 < > 59 return new RawMacroLayerEval; 61 // dynamic-overload-resolution-pattern: dispatch | 60 if( lay == MacroLayer ) 62 alias typeof(__traits(getOverloads, this, funName)) ovTypes; | 61 return new MacroLayerEval; 63 alias staticMap!(firstParam, ovTypes) fstTypes; | 62 return new UserDefinedLayerEval(lay); 64 alias DerivedToFront!(fstTypes) fstTypes_sorted; < 65 foreach(i, T; fstTypes_sorted) < 66 static if( is(T == typeof(params[0])) ) {} else if( auto < 67 return __traits(getOverloads, this, funName)[i]( < 68 < 69 // dynamic-overload-resolution-pattern: default behavior < 70 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not < 71 } 63 } 72 64 73 Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) | 65 abstract class LayerEval 74 { < 75 if( isASTLayer(lay) ) < 76 return ast2table(e, (AST e){return eval(e,lay,ctx);}); < 77 if( isUserDefinedLayer(lay) ) < 78 return lift(new StrValue(e.data), lay, ctx, e.pos); < 79 return new StrValue(e.data); < 80 } < 81 < 82 Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) < 83 { 66 { 84 if( isASTLayer(lay) ) | 67 /// Concrete layers should implement these 85 return ast2table(e, (AST e){return eval(e,lay,ctx);}); | 68 Layer currentLayer(); 86 if( isUserDefinedLayer(lay) ) | 69 Value eval_( Die e, Table ctx, bool ctxMod );/// 87 return lift(new IntValue(e.data), lay, ctx, e.pos); | 70 Value eval_( Str e, Table ctx, bool ctxMod );/// 88 return new IntValue(e.data); | 71 Value eval_( Int e, Table ctx, bool ctxMod );/// > 72 Value eval_( Var e, Table ctx, bool ctxMod );/// > 73 Value eval_( Lay e, Table ctx, bool ctxMod );/// > 74 Value eval_( Let e, Table ctx, bool ctxMod );/// > 75 Value eval_( App e, Table ctx, bool ctxMod );/// > 76 Value eval_( Fun e, Table ctx, bool ctxMod );/// 89 } | 77 > 78 /// dynamic-overload-resolution > 79 Value eval( AST e, Table ctx, bool ctxMod ) 90 | 80 { 91 Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) < > 81 enum funName = "eval_"; // modify here t > 82 alias TypeTuple!(e,ctx,ctxMod) params; // modify here t 92 { | 83 93 if( isASTLayer(lay) ) < 94 if( isMacroLayer(lay) && ctx.has(e.name,MacroLayer) ) < 95 return ctx.get(e.name, MacroLayer, e.pos); < > 84 alias typeof(__traits(getOverloads, this, funName)) ovTy > 85 alias staticMap!(firstParam, ovTypes) fstTy > 86 alias DerivedToFront!(fstTypes) fstTypes_sor > 87 foreach(i, T; fstTypes_sorted) > 88 static if( is(T == typeof(params[0])) ) {} else > 89 return __traits(getOverloads, this, funN > 90 > 91 // modify here to customize the default behavior > 92 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] > 93 } > 94 > 95 /// > 96 Value invokeFunction(Value _f, AST[] args, Table ctx, LexPositio > 97 { > 98 if(auto f = cast(FunValue)_f) > 99 { > 100 Table newCtx = new Table(f.definitionContext(), > 101 foreach(i,p; f.params()) > 102 if( p.layers.empty ) { > 103 Value v = this.eval(args[i], ctx > 104 if(v is null) v = ast2table(args > 105 newCtx.set(p.name, currentLayer( > 106 } 96 else | 107 else 97 return ast2table(e, (AST e){return eval(e,lay,ct < 98 if( isUserDefinedLayer(lay) && !ctx.has(e.name, lay) ) < 99 return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx < 100 return ctx.get(e.name, lay, e.pos); < > 108 foreach(argLay; p.layers) { > 109 Layer ll = argLay; > 110 if( isMacroLayer(argLay) > 111 ll = RawMacroLay > 112 Value v = getLayerEvalua > 113 if(v is null) v = ast2ta > 114 newCtx.set(p.name, argLa 101 } | 115 } > 116 scope _ = new PushCallStack(pos, callstackmsg); > 117 return f.invoke(currentLayer(), newCtx, pos); 102 | 118 } 103 Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) < > 119 throw genex!RuntimeException(pos, text("tried to call no > 120 } 104 { | 121 105 Value f = eval( e.fun, lay, ctx ); < 106 if( isASTLayer(lay) ) { < > 122 /// > 123 Value lift(Value v, Table ctx, LexPosition pos) > 124 { > 125 Layer lay = currentLayer(); > 126 > 127 // functions are automatically lifterd > 128 if( cast(FunValue) v ) > 129 return v; > 130 > 131 if( !ctx.has(lay, LiftLayer) ) > 132 throw genex!RuntimeException(pos, "lift function > 133 > 134 // similar to invokeFunction, but with only one argument > 135 auto _f = ctx.get(lay, LiftLayer, pos); 107 auto ff = cast(FunValue)f; | 136 if(auto f = cast(FunValue)_f) 108 if( ff !is null && isMacroLayer(lay) ) < 109 return invokeFunction(ff, e.args, lay, ctx, e.po < > 137 { > 138 Table newCtx = new Table(f.definitionContext(), > 139 auto ps = f.params(); > 140 if( ps.length != 1 ) > 141 throw genex!RuntimeException(pos, > 142 text("lift function for", lay, " > 143 if( ps[0].layers.length==0 || ps[0].layers.lengt > 144 { > 145 newCtx.set(ps[0].name, ValueLayer, v); > 146 scope _ = new PushCallStack(pos, lay); > 147 return f.invoke(ValueLayer, newCtx, pos) > 148 } 110 else | 149 else 111 return ast2table(e, (AST e){return eval(e,lay,ct < > 150 throw genex!RuntimeException(pos, > 151 text("lift function for", lay, " 112 } | 152 } 113 return invokeFunction(f, e.args, lay, ctx, e.pos, getNameIfPossi < > 153 throw genex!RuntimeException(pos, > 154 text("non-function ", _f, " is registered as the > 155 } 114 } 156 } 115 157 116 Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) | 158 /// Evaluator for standard @value semantics 117 { < 118 if( isASTLayer(lay) ) < 119 { < 120 // need this for correct scoping (outer scope macro vari < 121 Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet < 122 foreach(p; e.params) < 123 newCtx.set(p.name, NoopLayer, null); < 124 return ast2table(e, (AST e){return eval(e,lay,newCtx);}) < 125 } < 126 else < 127 return createNewFunction(e, ctx); < 128 } < 129 < 130 Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) < > 159 class ValueLayerEval : LayerEval 131 { 160 { 132 if( isNoLayerChangeLayer(lay) ) | 161 override Layer currentLayer() 133 return ast2table(e, (AST e){return eval(e,lay,ctx);}); < > 162 { 134 else | 163 return ValueLayer; 135 return eval(e.expr, e.layer, ctx); < 136 } | 164 } > 165 override Value eval_( Die e, Table ctx, bool ctxMod ) 137 | 166 { 138 Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) | 167 throw genex!RuntimeException(e.pos, "undefined case"); > 168 } > 169 override Value eval_( Str e, Table ctx, bool ctxMod ) 139 { | 170 { 140 Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.No < 141 if( isASTLayer(lay) ) < > 171 return new StrValue(e.data); > 172 } > 173 override Value eval_( Int e, Table ctx, bool ctxMod ) > 174 { > 175 return new IntValue(e.data); > 176 } > 177 override Value eval_( Var e, Table ctx, bool ctxMod ) > 178 { > 179 return ctx.get(e.name, currentLayer(), e.pos); > 180 } > 181 override Value eval_( Lay e, Table ctx, bool ctxMod ) > 182 { > 183 auto le = getLayerEvaluator(e.layer); > 184 auto v = le.eval(e.expr,ctx,CascadeCtx); > 185 if( (v is null) && (cast(MacroLayerEval)le !is null) ) 142 return ast2table(e, (AST ee){ | 186 return ast2table(e.expr); 143 // need this for correct scoping (outer scope ma < 144 if(e.name!="_" && ee is e.expr) < 145 newCtx.set(e.name, NoopLayer, null); < 146 return eval(ee,lay,newCtx); < 147 }); < 148 else | 187 else > 188 return v; > 189 } > 190 override Value eval_( Let e, Table ctx, bool ctxMod ) 149 { | 191 { 150 Value ri = eval(e.init, lay, newCtx); < > 192 Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind. > 193 Value ri = this.eval(e.init, newCtx, CascadeCtx); 151 if(e.name!="_") 194 if(e.name!="_") 152 newCtx.set(e.name, e.layer.empty ? lay : e.layer | 195 newCtx.set(e.name, e.layer.empty ? currentLayer( 153 return eval(e.expr, lay, newCtx, OverwriteCtx); | 196 return this.eval(e.expr, newCtx, OverwriteCtx); > 197 } > 198 override Value eval_( App e, Table ctx, bool ctxMod ) > 199 { > 200 Value f = this.eval( e.fun, ctx, CascadeCtx ); > 201 return this.invokeFunction(f, e.args, ctx, e.pos, getNam > 202 } > 203 override Value eval_( Fun e, Table ctx, bool ctxMod ) > 204 { > 205 return createNewFunction(e, ctx); 154 } 206 } 155 } 207 } 156 208 157 Value eval( Die e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) | 209 /// Evaluator for user-defined layer > 210 class UserDefinedLayerEval : ValueLayerEval 158 { 211 { 159 if( isMacroLayer(lay) ) | 212 Layer layerID; 160 return ast2table(e, (AST e){return eval(e,lay,ctx);}); | 213 mixin SimpleConstructor; 161 if( isUserDefinedLayer(lay) ) < > 214 > 215 override Layer currentLayer() > 216 { > 217 return layerID; > 218 } > 219 override Value eval_( Die e, Table ctx, bool ctxMod ) > 220 { 162 return new UndefinedValue; 221 return new UndefinedValue; 163 throw genex!RuntimeException(e.pos, "undefined case"); < > 222 } > 223 override Value eval_( Str e, Table ctx, bool ctxMod ) > 224 { > 225 return this.lift(new StrValue(e.data), ctx, e.pos); > 226 } > 227 override Value eval_( Int e, Table ctx, bool ctxMod ) > 228 { > 229 return this.lift(new IntValue(e.data), ctx, e.pos); > 230 } > 231 override Value eval_( Var e, Table ctx, bool ctxMod ) > 232 { > 233 if( ctx.has(e.name, currentLayer()) ) > 234 return ctx.get(e.name, currentLayer()); > 235 return this.lift(ctx.get(e.name, ValueLayer, e.pos), ctx > 236 } 164 } 237 } 165 238 166 private: | 239 // Convention!! 167 // little little bit incremental macro defining version. | 240 // returns null if never used macro-like feature 168 // enables @macro foo(x)=... in ... foo ..., only at the top level of th | 241 class MacroLayerEval : LayerEval 169 // interpreter and functions. better than nothing :P < 170 Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overw < 171 , ref AST[void*] mandeCache) // [TODO] avoid assuming non-moving < 172 { 242 { 173 assert( !isASTLayer(lay) ); | 243 override Layer currentLayer() 174 | 244 { 175 AST decodeAST(Value v, LexPosition pos) | 245 return MacroLayer; > 246 } > 247 override Value eval_( Die e, Table ctx, bool ctxMod ) > 248 { > 249 return null; > 250 } > 251 override Value eval_( Str e, Table ctx, bool ctxMod ) > 252 { > 253 return null; > 254 } > 255 override Value eval_( Int e, Table ctx, bool ctxMod ) > 256 { > 257 return null; > 258 } > 259 override Value eval_( Var e, Table ctx, bool ctxMod ) > 260 { > 261 if( ctx.has(e.name, currentLayer()) ) > 262 return ctx.get(e.name, currentLayer(), e.pos); > 263 else > 264 return null; > 265 } > 266 override Value eval_( Lay e, Table ctx, bool ctxMod ) 176 { 267 { 177 // [TODO] more informative error message | 268 auto le = getLayerEvaluator(e.layer); 178 return polemy2d!(AST)(v, pos); | 269 return le.eval(e.expr,ctx,CascadeCtx); 179 } 270 } 180 < 181 if(auto e = cast(Let)e_) < > 271 override Value eval_( Let e, Table ctx, bool ctxMod ) 182 { 272 { 183 void* key = cast(void*)e.init; < 184 AST ai; < 185 if(auto p = key in mandeCache) < 186 ai = *p; < 187 else { < 188 ai = decodeAST(eval(e.init, RawMacroLayer, ctx), < 189 mandeCache[key] = ai; < 190 } < 191 Value vi = eval(ai, lay, ctx); < 192 < 193 if( !overwriteCtx ) < 194 ctx = new Table(ctx, Table.Kind.NotPropagateSet) | 273 Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind. 195 string theLayer = e.layer.empty ? lay : e.layer; < > 274 Value ai = this.eval(e.init, newCtx, CascadeCtx); 196 ctx.set(e.name, theLayer, vi); | 275 newCtx.set(e.name, NoopLayer, null); 197 < 198 auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx, < 199 AST a = new Let(e.pos, e.name, e.layer, ai, ave[1]); < > 276 Value ae = this.eval(e.expr, newCtx, OverwriteCtx); > 277 if( ai is null && ae is null ) 200 return tuple(ave[0], a); | 278 return null; > 279 if( ai is null ) ai = ast2table(e.init); > 280 if( ae is null ) ae = ast2table(e.expr); > 281 return ast2table(e, delegate Value (AST _){ > 282 if(_ is e.init) { return ai; } > 283 if(_ is e.expr) { return ae; } > 284 assert(false); > 285 }); 201 } 286 } 202 else | 287 override Value eval_( App e, Table ctx, bool ctxMod ) 203 { 288 { 204 void* key = cast(void*)e_; | 289 Value f = this.eval( e.fun, ctx, CascadeCtx ); 205 AST a; | 290 if(auto ff = cast(FunValue)f) 206 if(auto p = key in mandeCache) | 291 return this.invokeFunction(ff, e.args, ctx, e.po 207 a = *p; < 208 else { 292 else { 209 a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.p | 293 bool allNull = (f is null); 210 mandeCache[key] = a; | 294 Value[] vas; > 295 foreach(a; e.args) { > 296 Value va = this.eval(a, ctx, CascadeCtx) > 297 if(va !is null) allNull = false; > 298 vas ~= va; > 299 } > 300 if( allNull ) > 301 return null; > 302 return ast2table(e, delegate Value (AST _){ > 303 if(_ is e.fun) return (f is null ? ast2t > 304 foreach(i,a; e.args) if(_ is a) return ( > 305 assert(false); > 306 }); 211 } 307 } 212 Value v = eval(a, lay, ctx, overwriteCtx); < > 308 } > 309 override Value eval_( Fun e, Table ctx, bool ctxMod ) > 310 { > 311 Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet > 312 foreach(p; e.params) > 313 newCtx.set(p.name, NoopLayer, null); > 314 Value af = this.eval(e.funbody, newCtx, CascadeCtx); > 315 if( af is null ) 213 return tuple(v, a); | 316 return null; > 317 return ast2table(e, (AST _){if(_ is e.funbody)return af; > 318 } > 319 } > 320 > 321 class RawMacroLayerEval : MacroLayerEval > 322 { > 323 override Value eval_( Lay e, Table ctx, bool ctxMod ) > 324 { > 325 Value ae = this.eval(e.expr, ctx, CascadeCtx); > 326 return ae is null ? null > 327 : ast2table(e, delegate Value (AST _){if(_ is e.e > 328 } > 329 } > 330 > 331 private: > 332 Value macroAndEval( AST e_, Layer lay, Table ctx, bool ctxMod ) > 333 { > 334 assert( !isASTLayer(lay) ); > 335 if(auto e = cast(Let)e_) > 336 { > 337 Value vai = getLayerEvaluator(RawMacroLayer).eval(e.init > 338 AST ai = (vai is null ? e.init : polemy2d!(AST)(vai, e.p > 339 > 340 if( !ctxMod ) > 341 ctx = new Table(ctx, Table.Kind.NotPropagateSet) > 342 > 343 Value vi = getLayerEvaluator(lay).eval(ai, ctx, CascadeC > 344 string theLayer = e.layer.empty ? lay : e.layer; > 345 ctx.set(e.name, theLayer, vi); > 346 > 347 return macroAndEval( e.expr, lay, ctx, OverwriteCtx ); > 348 } > 349 else > 350 { > 351 Value va = getLayerEvaluator(RawMacroLayer).eval(e_, ctx > 352 AST a = (va is null ? e_ : polemy2d!(AST)(va, e_.pos)); > 353 return getLayerEvaluator(lay).eval(a, ctx, ctxMod); 214 } 354 } 215 } 355 } 216 356 217 private: 357 private: 218 string getNameIfPossible(AST e) 358 string getNameIfPossible(AST e) 219 { 359 { 220 if(auto v = cast(Var)e) 360 if(auto v = cast(Var)e) 221 return v.name; 361 return v.name; 222 return ""; 362 return ""; 223 } 363 } 224 364 225 Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosi < 226 { < 227 if(auto f = cast(FunValue)_f) < 228 { < 229 Table newCtx = new Table(f.definitionContext(), Table.Ki < 230 foreach(i,p; f.params()) < 231 if( p.layers.empty ) < 232 newCtx.set(p.name, isMacroLayer(lay)?Mac < 233 else < 234 foreach(argLay; p.layers) < 235 if( lay!=MacroLayer && isMacroLa < 236 newCtx.set(p.name, argLa < 237 else < 238 newCtx.set(p.name, argLa < 239 scope _ = new PushCallStack(pos, callstackmsg); < 240 return f.invoke(isMacroLayer(lay)?MacroLayer:lay, newCtx < 241 } < 242 throw genex!RuntimeException(pos, text("tried to call non-functi < 243 } < 244 < 245 Value lift(Value v, Layer lay, Table ctx, LexPosition pos) < 246 { < 247 assert( !isASTLayer(lay), "lift to the @macro layer should never < 248 < 249 // functions are automatically lifterd < 250 if( cast(FunValue) v ) < 251 return v; < 252 < 253 if( !ctx.has(lay, LiftLayer) ) < 254 throw genex!RuntimeException(pos, "lift function for "~l < 255 < 256 // similar to invokeFunction, but with only one argument bound t < 257 auto _f = ctx.get(lay, LiftLayer, pos); < 258 if(auto f = cast(FunValue)_f) < 259 { < 260 Table newCtx = new Table(f.definitionContext(), Table.Ki < 261 auto ps = f.params(); < 262 if( ps.length != 1 ) < 263 throw genex!RuntimeException(pos, < 264 text("lift function for", lay, " must ta < 265 if( ps[0].layers.length==0 || ps[0].layers.length==1 && < 266 { < 267 newCtx.set(ps[0].name, ValueLayer, v); < 268 scope _ = new PushCallStack(pos, lay); < 269 return f.invoke(ValueLayer, newCtx, pos); < 270 } < 271 else < 272 throw genex!RuntimeException(pos, < 273 text("lift function for", lay, " must ta < 274 } < 275 throw genex!RuntimeException(pos, < 276 text("non-function ", _f, " is registered as the lift fu < 277 } < 278 < 279 Value createNewFunction(Fun e, Table ctx) 365 Value createNewFunction(Fun e, Table ctx) 280 { 366 { 281 class UserDefinedFunValue : FunValue 367 class UserDefinedFunValue : FunValue 282 { 368 { 283 Fun ast; 369 Fun ast; 284 Table defCtx; 370 Table defCtx; 285 override const(Parameter[]) params() { return ast.params 371 override const(Parameter[]) params() { return ast.params ................................................................................................................................................................................ 318 mixin SimpleConstructor; 404 mixin SimpleConstructor; 319 mixin SimpleCompareWithoutToHash; 405 mixin SimpleCompareWithoutToHash; 320 } 406 } 321 static Tuple!(Value,int)[MemokeyType] memo; 407 static Tuple!(Value,int)[MemokeyType] memo; 322 408 323 override Value invoke(Layer lay, Table ctx, LexPosition 409 override Value invoke(Layer lay, Table ctx, LexPosition 324 { 410 { 325 if( isASTLayer(lay) ) | 411 if( isASTLayer(lay) ) { 326 return eval(ast.funbody, lay, ctx); | 412 Value v = getLayerEvaluator(lay).eval(as > 413 if( v is null ) v = ast2table(ast.funbod > 414 return v; 327 | 415 } > 416 return macroAndEval(ast.funbody, lay, ctx, Casca > 417 /* 328 auto nonMemoizedRun = (){ 418 auto nonMemoizedRun = (){ 329 if( macroCache is null ) 419 if( macroCache is null ) 330 { 420 { 331 auto va = macroAndEval(e.funbody 421 auto va = macroAndEval(e.funbody 332 macroCache = va[1]; 422 macroCache = va[1]; 333 return va[0]; 423 return va[0]; 334 } 424 } ................................................................................................................................................................................ 351 441 352 Value r = nonMemoizedRun(); 442 Value r = nonMemoizedRun(); 353 443 354 int touched = memo[memokey][1]; 444 int touched = memo[memokey][1]; 355 memo[memokey] = tuple(r, 12345678); 445 memo[memokey] = tuple(r, 12345678); 356 //if(touched) {DBG("rerun :: ",r);r = nonMemoize 446 //if(touched) {DBG("rerun :: ",r);r = nonMemoize 357 return r; 447 return r; > 448 */ 358 } 449 } 359 } 450 } 360 return new UserDefinedFunValue(e,ctx); 451 return new UserDefinedFunValue(e,ctx); 361 } 452 } 362 453 363 public: 454 public: 364 /// Add primitive function to the global context 455 /// Add primitive function to the global context