Check-in [b97bd4f713]
Not logged in
Overview
SHA1 Hash:b97bd4f71330654c51496a03e0c22101ef0691e5
Date: 2010-11-23 18:36:27
User: kinaba
Comment:automatic AST to table encoder
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified main.d from [e659b2cb410288fd] to [cbf6e2570b5a90b0].

10 10 import std.array; 11 11 import polemy.value; 12 12 import polemy.failure; 13 13 import polemy.layer; 14 14 import polemy.parse; 15 15 import polemy.ast; 16 16 import polemy.eval; 17 +import polemy.runtime; 17 18 18 19 enum VersionNoMajor = 0; 19 20 enum VersionNoMinor = 1; 20 21 enum VersionNoRev = 0; 21 22 22 23 /// Read-Eval-Print-Loop 23 24 ................................................................................ 24 25 class REPL 25 26 { 26 27 Evaluator ev; 27 28 /// Load the prelude environment 28 29 this() 29 30 { 30 31 ev = new Evaluator; 32 + enrollRuntimeLibrary(ev); 31 33 } 32 34 33 35 /// Print the version number etc. 34 36 void greet() 35 37 { 36 38 writefln("Welcome to Polemy %d.%d.%d", VersionNoMajor, VersionNoMinor, VersionNoRev); 37 39 }

Modified polemy/ast.d from [cf8f245149fce4dc] to [f7a981003352ec6b].

9 9 import polemy.failure; 10 10 import polemy.layer; 11 11 12 12 /// 13 13 abstract class AST 14 14 { 15 15 LexPosition pos; 16 + 16 17 mixin SimpleConstructor; 17 - mixin SimplePatternMatch; 18 18 } 19 19 20 20 /// 21 21 class Int : AST 22 22 { 23 23 BigInt data; 24 + 24 25 mixin SimpleClass; 25 26 this(LexPosition pos, int n) {super(pos); data = n;} 26 27 this(LexPosition pos, long n) {super(pos); data = n;} 27 28 this(LexPosition pos, BigInt n) {super(pos); data = n;} 28 29 this(LexPosition pos, string n) {super(pos); data = BigInt(n);} 29 30 } 30 31 31 32 /// 32 33 class Str : AST 33 34 { 34 35 string data; 36 + 35 37 mixin SimpleClass; 36 38 } 37 39 38 40 /// 39 41 class Var : AST 40 42 { 41 43 string name; 44 + 42 45 mixin SimpleClass; 43 46 } 44 47 45 48 /// 46 49 class Lay : AST 47 50 { 48 51 Layer layer; 49 52 AST expr; 53 + 50 54 mixin SimpleClass; 51 55 } 52 56 53 57 /// 54 58 class Let : AST 55 59 { 56 60 string name; 57 61 Layer layer; 58 62 AST init; 59 63 AST expr; 64 + 60 65 mixin SimpleClass; 61 66 } 62 67 63 68 /// 64 69 class App : AST 65 70 { 66 71 AST fun; 67 72 AST[] args; 68 - this(LexPosition pos, AST fun, AST[] args...) 69 - { super(pos); this.fun=fun; this.args=args.dup; } 73 + 70 74 mixin SimpleClass; 75 + this(LexPosition pos, AST fun, AST[] args...) { super(pos); this.fun=fun; this.args=args.dup; } 71 76 } 72 77 73 78 /// 74 79 class Parameter 75 80 { 76 81 string name; 77 82 Layer[] layers; 83 + 78 84 mixin SimpleClass; 79 85 } 80 86 81 87 /// 82 88 class Fun : AST 83 89 { 84 90 Parameter[] params; 85 91 AST funbody; 92 + 86 93 mixin SimpleClass; 87 94 } 88 95 89 96 /// Handy Generator for AST nodes. To use this, mixin EasyAst; 90 97 91 98 /*mixin*/ 92 99 template EasyAST()

Modified polemy/eval.d from [b119954d6ce43301] to [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;

Modified polemy/layer.d from [79038e8ac0f7ba6a] to [62182a8e7452f9e8].

12 12 13 13 alias string Layer; 14 14 15 15 enum : Layer 16 16 { 17 17 SystemLayer = "(system)", /// Predefined layer for internal data 18 18 ValueLayer = "@value", /// Predefined layer for normal run 19 - MacroLayer = "@macro", /// Predefined layer for macro run 20 - RawMacroLayer = "(rawmacro)", /// Predefined layer for raw-macro run 19 + MacroLayer = "@macro", /// Predefined layer for macro run (@lay() changes layer) 20 + RawMacroLayer = "(rawmacro)", /// Predefined layer for macro run (@lay() becomes AST) 21 +} 22 + 23 +bool isMacroishLayer( Layer lay ) 24 +{ 25 + return lay==MacroLayer || lay==RawMacroLayer; 26 +} 27 + 28 +bool isNoLayerChangeLayer( Layer lay ) 29 +{ 30 + return lay==RawMacroLayer; 21 31 }

Modified polemy/value.d from [19366410c0eeb209] to [b6c76b48bfdecce6].

5 5 * Runtime data structures for Polemy programming language. 6 6 */ 7 7 module polemy.value; 8 8 import polemy._common; 9 9 import polemy.failure; 10 10 import polemy.ast; 11 11 import polemy.layer; 12 +import std.string; 12 13 13 14 /// Runtime values of Polemy 14 15 15 16 abstract class Value 16 17 { 18 + override bool opEquals(Object rhs) { return 0==opCmp(rhs); } 17 19 } 18 20 19 21 /// 20 22 class IntValue : Value 21 23 { 22 24 BigInt data; 23 25 24 - mixin SimpleClass; 25 - override string toString() const { return std.bigint.toDecimalString(cast(BigInt)data); } 26 + this(int n) { this.data = n; } 27 + this(long n) { this.data = n; } 28 + this(BigInt n) { this.data = n; } 29 + this(string n) { this.data = BigInt(n); } 30 + override string toString() const { return toDecimalString(cast(BigInt)data); } 31 + override int opCmp(Object rhs) { 32 + if(auto r = cast(IntValue)rhs) return data.opCmp(r.data); 33 + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 34 + throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other"); 35 + } 36 + mixin SimpleToHash; 26 37 } 27 38 28 39 /// 29 40 class StrValue : Value 30 41 { 31 42 string data; 32 43 33 - mixin SimpleClass; 44 + mixin SimpleConstructor; 34 45 override string toString() const { return data; } 46 + override int opCmp(Object rhs) { 47 + if(auto r = cast(StrValue)rhs) return typeid(string).compare(&data, &r.data); 48 + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 49 + throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other"); 50 + } 51 + mixin SimpleToHash; 35 52 } 36 53 37 54 /// 38 -class UndValue : Value 55 +class UndefinedValue : Value 39 56 { 40 - mixin SimpleClass; 57 + mixin SimpleConstructor; 41 58 override string toString() const { return "<undefined>"; } 59 + override int opCmp(Object rhs) { 60 + if(auto r = cast(StrValue)rhs) return 0; 61 + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 62 + throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other"); 63 + } 64 + mixin SimpleToHash; 42 65 } 43 - 44 66 45 67 /// 46 68 abstract class FunValue : Value 47 69 { 48 70 const(Parameter[]) params(); 49 71 Table definitionContext(); 50 - Value invoke(LexPosition pos, Layer lay, Table ctx); 72 + Value invoke(Layer lay, Table ctx, LexPosition pos); 51 73 } 52 74 53 75 /// Context (variable environment) 54 76 /// Simlar to prototype chain of ECMAScript etc. 55 77 /// But extended with the notion of "Layer" 56 78 57 79 class Table : Value ................................................................................ 334 356 } 335 357 336 358 Table fromPos(LexPosition pos) 337 359 { 338 360 Table t = new Table; 339 361 if( pos !is null ) { 340 362 t.set("filename", ValueLayer, new StrValue(pos.filename)); 341 - t.set("lineno", ValueLayer, new IntValue(BigInt(pos.lineno))); 342 - t.set("column", ValueLayer, new IntValue(BigInt(pos.column))); 363 + t.set("lineno", ValueLayer, new IntValue(pos.lineno)); 364 + t.set("column", ValueLayer, new IntValue(pos.column)); 343 365 } else { 344 366 t.set("filename", ValueLayer, new StrValue("nullpos")); 345 - t.set("lineno", ValueLayer, new IntValue(BigInt(0))); 346 - t.set("column", ValueLayer, new IntValue(BigInt(0))); 367 + t.set("lineno", ValueLayer, new IntValue(0)); 368 + t.set("column", ValueLayer, new IntValue(0)); 347 369 } 348 370 return t; 349 371 } 372 + 373 +/// Convert AST to Table so that it can be used in Polemy 374 +/// TODO: generalize to DValue2PolemyValue 375 + 376 +Value ast2table(T)(T e, Value delegate(AST) rec) 377 +{ 378 + assert( typeid(e) == typeid(T) ); 379 + 380 + static if(is(T==BigInt) || is(T==long) || is(T==int)) 381 + return new IntValue(e); 382 + else 383 + static if(is(T==string)) 384 + return new StrValue(e); 385 + else 386 + static if(is(T S : S[])) 387 + { 388 + Table lst = new Table; 389 + foreach_reverse(a; e) 390 + static if(is(S : AST)) 391 + lst = makeCons(rec(a), lst); 392 + else 393 + lst = makeCons(ast2table(a,rec), lst); 394 + return lst; 395 + } 396 + else 397 + static if(is(T : AST)) 398 + { 399 + auto t = new Table; 400 + t.set("pos", ValueLayer, fromPos(e.pos)); 401 + t.set("is" , ValueLayer, new StrValue(typeid(e).name.split(".")[$-1].tolower())); 402 + foreach(i,m; e.tupleof) 403 + static if(is(typeof(m) : AST)) 404 + t.set(e.tupleof[i].stringof[2..$], ValueLayer, rec(m)); 405 + else 406 + t.set(e.tupleof[i].stringof[2..$], ValueLayer, ast2table(m,rec)); 407 + return t; 408 + } 409 + else 410 + static if(is(T == class)) 411 + { 412 + auto t = new Table; 413 + foreach(i,m; e.tupleof) 414 + static if(is(typeof(m) : AST)) 415 + t.set(e.tupleof[i].stringof[2..$], ValueLayer, rec(m)); 416 + else 417 + t.set(e.tupleof[i].stringof[2..$], ValueLayer, ast2table(m,rec)); 418 + return t; 419 + } 420 + else 421 + static assert(false, "unknown type <"~T.stringof~"> during AST encoding"); 422 +}

Modified tricks/tricks.d from [004818c087feff6a] to [cc1b586b87325960].

98 98 assert( !__traits(compiles, { 99 99 class Tamp : Tomp { mixin SimpleConstructor; } 100 100 }) ); 101 101 } 102 102 103 103 /// Mixing-in the MOST-DERIVED-member-wise comparator for a class 104 104 105 +template SimpleToHash() 106 +{ 107 + override hash_t toHash() const /// member-by-member hash 108 + { 109 + hash_t h = 0; 110 + foreach(mem; this.tupleof) 111 + h += typeid(mem).getHash(&mem); 112 + return h; 113 + } 114 +} 115 + 116 +/// Mixing-in the MOST-DERIVED-member-wise comparator for a class 117 + 105 118 /*mixin*/ 106 119 template SimpleCompare() 107 120 { 108 121 override bool opEquals(Object rhs_) const /// member-by-member equality 109 122 { 110 123 if( auto rhs = cast(typeof(this))rhs_ ) 111 124 { ................................................................................ 113 126 if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) 114 127 return false; 115 128 return true; 116 129 } 117 130 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 118 131 } 119 132 120 - override hash_t toHash() const /// member-by-member hash 121 - { 122 - hash_t h = 0; 123 - foreach(mem; this.tupleof) 124 - h += typeid(mem).getHash(&mem); 125 - return h; 126 - } 133 + mixin SimpleToHash; 127 134 128 135 override int opCmp(Object rhs_) const /// member-by-member compare 129 136 { 130 137 if( auto rhs = cast(typeof(this))rhs_ ) 131 138 { 132 139 foreach(i,_; this.tupleof) 133 140 if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) { ................................................................................ 215 222 template SimpleClass() 216 223 { 217 224 mixin SimpleConstructor; 218 225 mixin SimpleCompare; 219 226 mixin SimpleToString; 220 227 } 221 228 222 -/// Simple PatternMatcher 223 - 224 -/*mixin*/ 225 -template SimplePatternMatch() 226 -{ 227 - SPM_Return!(PP) match(string fn=__FILE__, size_t ln=__LINE__, PP...)(PP pts) 228 - { 229 - foreach(i,_; pts) 230 - { 231 - alias pts[i] pt; // bug? pts[i]-->pt do not work 232 - static if(__traits(compiles, SPM_isMatchTag(pt))) 233 - { 234 - if( auto v = cast(pt.dynamicType)this ) 235 - return pt(v.tupleof); 236 - } 237 - else 238 - static if(__traits(compiles, SPM_isMatchAny(pt))) 239 - { 240 - return pt(); 241 - } 242 - else 243 - { 244 - if( auto v = cast(SPM_PTT!(pt)[0])this ) 245 - return pt(v); 246 - } 247 - } 248 - SPM_throwAssertError(fn, ln, "pattern matching failure"); 249 - assert(false); 250 - } 251 -} 252 - 253 -/// Pattern case clause 254 - 255 -SPM_MatchTag!(T, fn) when(T, alias fn)() 256 -{ 257 - SPM_MatchTag!(T, fn) m; 258 - return m; 259 -} 260 - 261 -/// Pattern case clause 262 - 263 -SPM_MatchAny!(fn) otherwise(alias fn)() 264 -{ 265 - SPM_MatchAny!(fn) m; 266 - return m; 267 -} 268 - 269 -// implementation detail of SimplePatternMatch 270 - 271 -void SPM_throwAssertError(T...)(T t) { core.exception.onAssertErrorMsg(t); } 272 - 273 -struct SPM_MatchTag(T, alias fn) 274 -{ 275 - alias T dynamicType; 276 - auto opCall(typeof(T.tupleof) s) { return fn(s); } 277 -} 278 - 279 -struct SPM_MatchAny(alias fn) 280 -{ 281 - auto opCall() { return fn(); } 282 -} 283 - 284 -template SPM_PTT(alias p) 285 -{ 286 - alias ParameterTypeTuple!(p) SPM_PTT; 287 -} 288 - 289 -template SPM_Each(P) 290 -{ 291 - static if(__traits(compiles, SPM_isMatchTag(P.init))) 292 - alias typeof(P(P.dynamicType.tupleof)) SPM_Each; 293 - else 294 - static if(__traits(compiles, SPM_isMatchAny(P.init))) 295 - alias typeof(P()) SPM_Each; 296 - else 297 - alias ReturnType!(P) SPM_Each; 298 -} 299 - 300 -template SPM_aVoid(T:void, TS...) { alias SPM_aVoid!(TS) SPM_aVoid; } 301 -template SPM_aVoid(T, TS...) { alias TypeTuple!(T,SPM_aVoid!(TS)) SPM_aVoid; } 302 -template SPM_aVoid() { alias TypeTuple!() SPM_aVoid; } 303 - 304 -template SPM_Return(PP...) 305 -{ 306 - alias CommonType!(SPM_aVoid!(staticMap!(SPM_Each, PP))) SPM_Return; 307 -} 308 - 309 -void SPM_isMatchTag(T,alias fn)(SPM_MatchTag!(T,fn)){} 310 -void SPM_isMatchAny(alias fn)(SPM_MatchAny!(fn)){} 311 - 312 -unittest 313 -{ 314 - static abstract class Base { 315 - mixin SimplePatternMatch; 316 - } 317 - class D1 : Base { 318 - int x; 319 - real y; 320 - mixin SimpleConstructor; 321 - } 322 - class D2 : Base { 323 - string s; 324 - mixin SimpleConstructor; 325 - } 326 - class D3 : Base { 327 - int[int] m; 328 - mixin SimpleConstructor; 329 - } 330 - 331 - Base d1 = new D1(1, 2.3); 332 - Base d2 = new D2("foobar"); 333 - Base d3 = new D3(null); (cast(D3)d3).m[1]=10; 334 - 335 - // normal dispatch 336 - assert_eq( d1.match( 337 - (D1 x){return 1;}, 338 - (D2 x){return 2;} 339 - ), 1); 340 - assert_eq( d2.match( 341 - (D1 x){return 1;}, 342 - (D2 x){return 2;} 343 - ), 2); 344 - assert_throw!AssertError( d3.match( 345 - (D1 x){return 1;}, 346 - (D2 x){return 2;} 347 - )); 348 - assert_eq( d3.match( 349 - (D1 x){return 1;}, 350 - (D2 x){return 2;}, 351 - (Base x){return 3;} 352 - ), 3); 353 - assert_eq( d2.match( 354 - (D1 x){return 1;}, 355 - (D2 x){return 2;}, 356 - (Base x){return 3;} 357 - ), 2); 358 - assert_eq( d2.match( 359 - (D1 x){return 1;}, 360 - (Base x){return 3;}, 361 - (D2 x){return 2;} 362 - ), 3); 363 - 364 - // member decomposing match 365 - assert_eq( d1.match( 366 - when!(D1, (x, y){return x + cast(int)y;}), 367 - when!(D2, (x){return x.length;}), 368 - when!(D3, (x){return x[1];}) 369 - ), 3); 370 - assert_eq( d2.match( 371 - when!(D1, (x, y){return x + cast(int)y;}), 372 - when!(D2, (x){return x.length;}), 373 - when!(D3, (x){return x[1];}) 374 - ), 6); 375 - assert_eq( d3.match( 376 - when!(D1, (x, y){return x + cast(int)y;}), 377 - when!(D2, (x){return x.length;}), 378 - when!(D3, (x){return x[1];}) 379 - ), 10); 380 - assert_throw!AssertError( d3.match( 381 - when!(D1, (x, y){return x + cast(int)y;}), 382 - when!(D2, (x){return x.length;}) 383 - )); 384 - assert_eq( d2.match( 385 - when!(D1, (x, y){return x + cast(int)y;}), 386 - when!(D2, (x){return x.length;}), 387 - otherwise!({return 999;}) 388 - ), 6); 389 - assert_eq( d2.match( 390 - when!(D1, (x, y){return x + cast(int)y;}), 391 - otherwise!({return 999;}), 392 - when!(D2, (x){return x.length;}) 393 - ), 999); 394 -} 395 - 396 229 /// Will be used for dynamic overload resolution pattern 397 230 398 231 template firstParam(T) 399 232 { 400 233 alias ParameterTypeTuple!(T)[0] firstParam; 401 234 }