Check-in [435fa085ec]
Not logged in
Overview
SHA1 Hash:435fa085ecbb38915bc81b52b32ebad205055044
Date: 2010-11-21 18:53:17
User: kinaba
Comment:refactored predefined layer names, and filled readme.txt.
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified .poseidon from [3a1ec7254a3a05f2] to [689f2a54d91081ce].

31 31 <name>d2stacktrace\dbghelp.d</name> 32 32 <name>d2stacktrace\stacktrace.d</name> 33 33 <name>main.d</name> 34 34 <name>polemy\_common.d</name> 35 35 <name>polemy\ast.d</name> 36 36 <name>polemy\eval.d</name> 37 37 <name>polemy\failure.d</name> 38 + <name>polemy\layer.d</name> 38 39 <name>polemy\lex.d</name> 39 40 <name>polemy\parse.d</name> 40 41 <name>polemy\value.d</name> 41 42 <name>tricks\test.d</name> 42 43 <name>tricks\tricks.d</name> 43 44 </source> 44 45 <interface />

Modified doc/candydoc/modules.ddoc from [16e1e2b29a0a959b] to [14742f81f6b8c11a].

1 1 MODULES = 2 2 $(MODULE main) 3 3 $(MODULE tricks.tricks) 4 4 $(MODULE tricks.test) 5 5 $(MODULE polemy._common) 6 6 $(MODULE polemy.failure) 7 + $(MODULE polemy.layer) 7 8 $(MODULE polemy.lex) 8 9 $(MODULE polemy.parse) 9 10 $(MODULE polemy.ast) 10 11 $(MODULE polemy.eval) 11 12 $(MODULE polemy.value)

Modified main.d from [3594122dc7a67c3c] to [636370f08c051cf2].

9 9 import std.algorithm; 10 10 import std.array; 11 11 import polemy.value; 12 12 import polemy.failure; 13 13 import polemy.parse; 14 14 import polemy.ast; 15 15 import polemy.eval; 16 +import polemy.layer; 16 17 17 18 enum VersionNoMajor = 0; 18 19 enum VersionNoMinor = 1; 19 20 enum VersionNoRev = 0; 20 21 21 22 /// Read-Eval-Print-Loop 22 23 ................................................................................ 33 34 { 34 35 writefln("Welcome to Polemy %d.%d.%d", VersionNoMajor, VersionNoMinor, VersionNoRev); 35 36 } 36 37 37 38 /// Run one file on the global scope 38 39 void runFile(string filename) 39 40 { 40 - eval(parseFile(filename), ctx, false, "@v"); 41 + eval(parseFile(filename), ctx, false, ValueLayer); 41 42 } 42 43 43 44 /// Repeat the singleInteraction 44 45 void replLoop() 45 46 { 46 47 while( singleInteraction() ) {} 47 48 } ................................................................................ 73 74 { 74 75 scope(failure) 75 76 { buf = ""; lineno = nextlineno; } 76 77 77 78 buf ~= s; 78 79 nextlineno ++; 79 80 try 80 - { lastVal = eval(parseString(buf, "<REPL>", lineno), ctx, false, "@v"); } 81 + { lastVal = eval(parseString(buf, "<REPL>", lineno), ctx, false, ValueLayer); } 81 82 catch( UnexpectedEOF ) 82 83 { return false; } // wait 83 84 buf = ""; 84 85 lineno = nextlineno; 85 86 return true; 86 87 } 87 88 }

Modified polemy/eval.d from [27ad20bc14df9938] to [0e6e0e9d77fcbedc].

6 6 */ 7 7 module polemy.eval; 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 +import polemy.layer; 13 14 import std.typecons; 14 15 import std.stdio; 15 16 16 17 /// 17 18 Table createGlobalContext() 18 19 { 19 20 auto ctx = new Table; 20 - ctx.set("+", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} )); 21 - ctx.set("-", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} )); 22 - ctx.set("*", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} )); 23 - ctx.set("/", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} )); 24 - ctx.set("%", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} )); 25 - ctx.set("||", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} )); 26 - ctx.set("&&", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} )); 27 - ctx.set("<", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} )); 28 - ctx.set(">", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} )); 29 - ctx.set("<=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} )); 30 - ctx.set(">=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} )); 31 - ctx.set("==", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} )); 32 - ctx.set("!=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} )); 33 - ctx.set("print", "@v", native( (Value a){ 21 + ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} )); 22 + ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} )); 23 + ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} )); 24 + ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} )); 25 + ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} )); 26 + ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} )); 27 + ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} )); 28 + ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} )); 29 + ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} )); 30 + ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} )); 31 + ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} )); 32 + ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} )); 33 + ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} )); 34 + ctx.set("print", ValueLayer, native( (Value a){ 34 35 writeln(a); 35 36 return new IntValue(BigInt(178)); 36 37 })); 37 - ctx.set("if", "@v", native( (IntValue x, FunValue ft, FunValue fe){ 38 + ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){ 38 39 auto toRun = (x.data==0 ? fe : ft); 39 - return toRun.invoke(null, "@v", toRun.definitionContext()); 40 + return toRun.invoke(null, ValueLayer, toRun.definitionContext()); 40 41 // return toRun.invoke(pos, lay, toRun.definitionContext()); 41 42 })); 42 - ctx.set("_isint", "@v", native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} )); 43 - ctx.set("_isstr", "@v", native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} )); 44 - ctx.set("_isfun", "@v", native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} )); 45 - ctx.set("_isundefined", "@v", native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} )); 46 - ctx.set("_istable", "@v", native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} )); 47 - ctx.set(".", "@v", native( (Table t, StrValue s){ 48 - return (t.has(s.data, "@v") ? t.get(s.data, "@v") : new UndValue); 43 + ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} )); 44 + ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} )); 45 + ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} )); 46 + ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} )); 47 + ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} )); 48 + ctx.set(".", ValueLayer, native( (Table t, StrValue s){ 49 + return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue); 50 + }) ); 51 + ctx.set(".?", ValueLayer, native( (Table t, StrValue s){ 52 + return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0)); 49 53 }) ); 50 - ctx.set(".?", "@v", native( (Table t, StrValue s){ 51 - return new IntValue(BigInt(t.has(s.data, "@v") ? 1 : 0)); 52 - }) ); 53 - ctx.set(".=", "@v", native( (Table t, StrValue s, Value v){ 54 + ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){ 54 55 auto t2 = new Table(t, Table.Kind.NotPropagateSet); 55 - t2.set(s.data, "@v", v); 56 + t2.set(s.data, ValueLayer, v); 56 57 return t2; 57 58 }) ); 58 - ctx.set("{}", "@v", native( (){ 59 + ctx.set("{}", ValueLayer, native( (){ 59 60 return new Table; 60 61 }) ); 61 62 return ctx; 62 63 } 63 64 64 65 /// Entry point of this module 65 66 ................................................................................ 76 77 } 77 78 78 79 /// Entry point of this module 79 80 80 81 Tuple!(Value,"val",Table,"ctx") eval(AST e) 81 82 { 82 83 Table ctx = createGlobalContext(); 83 - return typeof(return)(eval(e, ctx, false, "@v"), ctx); 84 + return typeof(return)(eval(e, ctx, false, ValueLayer), ctx); 84 85 } 85 86 86 87 Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false) 87 88 { 88 89 if(auto f = cast(FunValue)_f) 89 90 { 90 91 Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 91 92 foreach(i,p; f.params()) 92 93 if( p.layers.empty ) 93 - if(lay=="@macro") 94 + if(lay==MacroLayer) 94 95 ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro)); 95 96 else 96 97 ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay)); 97 98 else 98 99 foreach(argLay; p.layers) 99 - if(argLay=="@macro") 100 + if(argLay==MacroLayer) 100 101 ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro)); 101 102 else 102 103 ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay)); 103 104 return f.invoke(pos, lay, ctx); 104 105 } 105 106 throw genex!RuntimeException(pos, "tried to call non-function"); 106 107 } 107 108 108 109 Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx) 109 110 { 110 - // similar to invoke Function, but with only one argument bound to @v 111 - Value _f = callerCtx.get(lay, "(system)", pos); 111 + // similar to invoke Function, but with only one argument bound to ValueLayer 112 + Value _f = callerCtx.get(lay, SystemLayer, pos); 112 113 if(auto f = cast(FunValue)_f) 113 114 { 114 115 Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 115 116 auto ps = f.params(); 116 117 if( ps.length != 1 ) 117 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer"); 118 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]=="@v" ) 118 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 119 + if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 119 120 { 120 - ctx.set(ps[0].name, "@v", v); 121 - return f.invoke(pos, "@v", ctx); 121 + ctx.set(ps[0].name, ValueLayer, v); 122 + return f.invoke(pos, ValueLayer, ctx); 122 123 } 123 124 else 124 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer"); 125 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 125 126 } 126 127 throw genex!RuntimeException(pos, "tried to call non-function"); 127 128 } 128 129 129 130 /// Entry point of this module 130 131 /// If splitCtx = true, then inner variable declaration do not overwrite ctx. 131 -/// lay is the layer ID for evaluation (standard value semantics uses "@v"). 132 +/// lay is the layer ID for evaluation (standard value semantics uses ValueLayer). 132 133 133 134 Value eval(AST e, Table ctx, bool splitCtx, Layer lay) 134 135 { 135 136 return e.match( 136 137 (StrLiteral e) 137 138 { 138 139 Value v = new StrValue(e.data); 139 - if( lay == "@v" ) 140 + if( lay == ValueLayer ) 140 141 return v; 141 142 else 142 143 return lift(e.pos,v,lay,ctx); 143 144 }, 144 145 (IntLiteral e) 145 146 { 146 147 Value v = new IntValue(e.data); 147 - if( lay == "@v" ) 148 + if( lay == ValueLayer ) 148 149 return v; 149 150 else // rise 150 151 return lift(e.pos,v,lay,ctx); 151 152 }, 152 153 (VarExpression e) 153 154 { 154 - if( lay == "@v" ) 155 + if( lay == ValueLayer ) 155 156 return ctx.get(e.var, lay, e.pos); 156 157 try { 157 158 return ctx.get(e.var, lay, e.pos); 158 159 } catch( Throwable ) { // [TODO] more precise... 159 - return lift(e.pos, ctx.get(e.var, "@v", e.pos), lay, ctx); 160 + return lift(e.pos, ctx.get(e.var, ValueLayer, e.pos), lay, ctx); 160 161 } 161 162 }, 162 163 (LayeredExpression e) 163 164 { 164 - if( e.lay == "@macro" ) 165 + if( e.lay == MacroLayer ) 165 166 return macroEval(e.expr, ctx, false); 166 167 else 167 168 return eval(e.expr, ctx, true, e.lay); 168 169 }, 169 170 (LetExpression e) 170 171 { 171 172 // for letrec, we need this, but should avoid overwriting???? 172 - // ctx.set(e.var, "@v", new UndefinedValue, e.pos); 173 + // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos); 173 174 if(splitCtx) 174 175 ctx = new Table(ctx, Table.Kind.NotPropagateSet); 175 176 Value v = eval(e.init, ctx, true, lay); 176 177 ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); 177 178 return eval(e.expr, ctx, false, lay); 178 179 }, 179 180 (FuncallExpression e) ................................................................................ 195 196 } 196 197 ); 197 198 } 198 199 199 200 // [TODO] Optimization 200 201 Value macroEval(AST e, Table ctx, bool AlwaysMacro) 201 202 { 202 - Layer theLayer = "@v"; 203 + Layer theLayer = ValueLayer; 203 204 204 205 Table pos = new Table; 205 206 pos.set("filename", theLayer, new StrValue(e.pos.filename)); 206 207 pos.set("lineno", theLayer, new IntValue(BigInt(e.pos.lineno))); 207 208 pos.set("column", theLayer, new IntValue(BigInt(e.pos.column))); 208 209 return e.match( 209 210 (StrLiteral e) ................................................................................ 221 222 t.set("is", theLayer, new StrValue("int")); 222 223 t.set("data", theLayer, new IntValue(e.data)); 223 224 return t; 224 225 }, 225 226 (VarExpression e) 226 227 { 227 228 try { 228 - return ctx.get(e.var, "@macro", e.pos); 229 + return ctx.get(e.var, MacroLayer, e.pos); 229 230 } catch( Throwable ) {// [TODO] more precies... 230 231 Table t = new Table; 231 232 t.set("pos", theLayer, pos); 232 233 t.set("is", theLayer, new StrValue("var")); 233 234 t.set("name", theLayer, new StrValue(e.var)); 234 235 return cast(Value)t; 235 236 } ................................................................................ 243 244 t.set("is", theLayer, new StrValue("lay")); 244 245 t.set("layer", theLayer, new StrValue(e.lay)); 245 246 t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro)); 246 247 return cast(Value)t; 247 248 } 248 249 else 249 250 { 250 - if( e.lay == "@macro" ) 251 + if( e.lay == MacroLayer ) 251 252 return macroEval(e.expr, ctx, false); 252 253 else 253 254 return eval(e.expr, ctx, true, e.lay); 254 255 } 255 256 }, 256 257 (LetExpression e) 257 258 { ................................................................................ 264 265 return t; 265 266 }, 266 267 (FuncallExpression e) 267 268 { 268 269 Value _f = macroEval(e.fun,ctx,AlwaysMacro); 269 270 270 271 if( auto f = cast(FunValue)_f ) 271 - return invokeFunction(e.pos, f, e.args, ctx, "@macro", AlwaysMacro); 272 + return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro); 272 273 273 274 Table t = new Table; 274 275 t.set("pos", theLayer, pos); 275 276 t.set("is", theLayer, new StrValue("app")); 276 277 t.set("fun", theLayer, _f); 277 278 Table args = new Table; 278 279 foreach_reverse(a; e.args) { ................................................................................ 317 318 ); 318 319 } 319 320 320 321 unittest 321 322 { 322 323 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); 323 324 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 324 - assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21)) ); 325 - assert_nothrow( r.ctx.get("x","@v") ); 326 - assert_throw!RuntimeException( r.ctx.get("y","@v") ); 325 + assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) ); 326 + assert_nothrow( r.ctx.get("x",ValueLayer) ); 327 + assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) ); 327 328 } 328 329 unittest 329 330 { 330 331 auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) ); 331 332 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 332 - assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21+21*21)) ); 333 - assert_nothrow( r.ctx.get("x","@v") ); 334 - assert_throw!RuntimeException( r.ctx.get("y","@v") ); 333 + assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) ); 334 + assert_nothrow( r.ctx.get("x",ValueLayer) ); 335 + assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) ); 335 336 } 336 337 unittest 337 338 { 338 339 assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) ); 339 340 assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) ); 340 341 } 341 342 unittest ................................................................................ 364 365 fib(5);`).val, new IntValue(BigInt(8))); 365 366 } 366 367 367 368 unittest 368 369 { 369 370 assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) ); 370 371 assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) ); 371 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) ); 372 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) ); 372 + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) ); 373 + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) ); 373 374 } 374 375 375 376 unittest 376 377 { 377 378 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) ); 378 379 // there was a bug that declaration in the first line of function definition 379 380 // cannot be recursive 380 381 assert_nothrow( evalString(`def foo() { 381 382 def bar(y) { if(y<1) {0} else {bar(0)} }; 382 383 bar(1) 383 384 }; foo()`) ); 384 385 } 385 -

Modified polemy/parse.d from [25ec86a59533b939] to [71d187282fb3ce05].

5 5 * Parser for Polemy programming language 6 6 */ 7 7 module polemy.parse; 8 8 import polemy._common; 9 9 import polemy.failure; 10 10 import polemy.lex; 11 11 import polemy.ast; 12 +import polemy.layer; 12 13 13 14 /// Parse a string and return its AST 14 15 /// Throws: ParseException, LexException, UnexpectedEOF 15 16 16 17 AST parseString(S, T...)(S str, T fn_ln_cn) 17 18 { 18 19 return parserFromString(str, fn_ln_cn).parse(); ................................................................................ 98 99 string kwd = "@" ~ layer; 99 100 string var = layer; 100 101 101 102 auto e = tryEat("(") 102 103 ? parseLambdaAfterOpenParen(pos) // let var ( ... 103 104 : (eat("=", "after "~kwd), E(0)); // let var = ... 104 105 if( moreDeclarationExists() ) 105 - return new LetExpression(pos, var, "(system)", e, Body()); 106 + return new LetExpression(pos, var, SystemLayer, e, Body()); 106 107 else 107 - return new LetExpression(pos, var, "(system)", e, new VarExpression(pos, var)); 108 + return new LetExpression(pos, var, SystemLayer, e, new VarExpression(pos, var)); 108 109 } 109 110 else 110 111 { 111 112 string kwd = layer; 112 113 if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) 113 114 return null; // none of {@lay, let, var, def} occurred, it's not a declaration 114 115 ................................................................................ 471 472 assert_eq(parseString(`def foo(x) { x+1 }; foo`), 472 473 let("foo", "", 473 474 fun(["x"], call(var("+"), var("x"), intl(1))), 474 475 var("foo")) 475 476 ); 476 477 477 478 assert_eq(parseString(`@@type ( x ) { x }`), 478 - let("@type", "(system)", fun(["x"], var("x")), var("@type")) ); 479 + let("@type", SystemLayer, fun(["x"], var("x")), var("@type")) ); 479 480 480 481 assert_eq(parseString(`{}`), call(var("{}"))); 481 482 assert_eq(parseString(`{foo:1,"bar":2}`), 482 483 call(var(".="), call(var(".="), call(var("{}")), strl("foo"), intl(1)), strl("bar"), intl(2))); 483 484 assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo"))); 484 485 assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("foo"))); 485 486 assert_eq(parseString(`x{y:1}`), call(var(".="),var("x"),strl("y"),intl(1))); 486 487 }

Modified polemy/value.d from [f1a01bb8ba2daf26] to [57b0a5dd9a9946f6].

4 4 * 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 +import polemy.layer; 11 12 12 13 /// Runtime values of Polemy 13 14 14 15 abstract class Value 15 16 { 16 17 } 17 18 ................................................................................ 59 60 override const(Parameter[]) params() { return ast.params; } 60 61 override Table definitionContext() { return defCtx; } 61 62 override Value invoke(in LexPosition pos, Layer lay, Table ctx) 62 63 { 63 64 // TODO: only auto raised ones need memo? no? 64 65 // auto memoization 65 66 /* 66 - if( lay != "@v" && lay != "@macro" ) 67 + if( lay != ValueLayer && lay != MacroLayer ) 67 68 { 68 69 if( auto memolay = lay in memo ) 69 70 if( auto pv = args in *memolay ) 70 71 return *pv; 71 72 memo[lay][args] = lift(e.pos,new UndValue,lay,ctx); 72 73 } 73 74 74 75 */ 75 76 // @macro run!!! 76 - if( lay == "@macro" ) 77 + if( lay == MacroLayer ) 77 78 return macroEval(ast.funbody, ctx, false); 78 79 /*TODO memo*/ AST macroMemo; 79 80 if( macroMemo is null ) { 80 81 // .prototype!, forced macro cannot access parameters 81 82 ctx.kill = true; scope(exit)ctx.kill=false; 82 - macroMemo = tableToAST("@v",macroEval(ast.funbody, ctx, true)); 83 + macroMemo = tableToAST(ValueLayer,macroEval(ast.funbody, ctx, true)); 83 84 } 84 85 auto v = eval(macroMemo, ctx, true, lay); 85 86 86 87 //auto v = eval(e.funbody, ctxNeo, true, lay); 87 88 // auto memoization 88 -// if( lay != "@v" && lay != "@macro" ) 89 +// if( lay != ValueLayer && lay != MacroLayer ) 89 90 // memo[lay][args] = v; 90 91 return v; 91 92 } 92 93 93 94 mixin SimpleClass; 94 95 override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } 95 96 } ................................................................................ 110 111 this() 111 112 { 112 113 foreach(i, Ti; T) 113 114 params_data ~= new Parameter(text(i), []); 114 115 } 115 116 override Value invoke(in LexPosition pos, Layer lay, Table ctx) 116 117 { 117 - if( lay != "@v" ) 118 - throw genex!RuntimeException(pos, "only @v layer can call native function"); 118 + if( lay != ValueLayer ) 119 + throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function"); 119 120 T typed_args; 120 121 foreach(i, Ti; T) { 121 - typed_args[i] = cast(Ti) ctx.get(text(i), "@v"); 122 + typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer); 122 123 if( typed_args[i] is null ) 123 124 throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 124 125 } 125 126 try { 126 127 return dg(typed_args); 127 128 } catch( RuntimeException e ) { 128 129 throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 129 130 } 130 131 } 131 132 }; 132 133 } 133 134 134 -/// Layer ID 135 - 136 -alias string Layer; 137 - 138 135 /// Context (variable environment) 139 136 /// Simlar to prototype chain of ECMAScript etc. 140 137 /// But extended with the notion of "Layer" 141 138 142 139 class Table : Value 143 140 { 144 141 enum Kind {PropagateSet, NotPropagateSet}; ................................................................................ 245 242 unittest 246 243 { 247 244 Table c0 = new Table; 248 245 Table c01 = new Table(c0, Table.Kind.NotPropagateSet); 249 246 Table c012 = new Table(c01, Table.Kind.PropagateSet); 250 247 Table c013 = new Table(c01, Table.Kind.PropagateSet); 251 248 252 - assert_nothrow( c012.set("x", "@v", new IntValue(BigInt(12))) ); 253 - assert_throw!RuntimeException( c013.get("x", "@v") ); 254 - assert_nothrow( c013.set("x", "@v", new IntValue(BigInt(13))) ); 255 - assert_eq( c013.get("x", "@v"), new IntValue(BigInt(13)) ); 256 - assert_eq( c012.get("x", "@v"), new IntValue(BigInt(12)) ); 257 - assert_throw!RuntimeException( c01.get("x", "@v") ); 249 + assert_nothrow( c012.set("x", ValueLayer, new IntValue(BigInt(12))) ); 250 + assert_throw!RuntimeException( c013.get("x", ValueLayer) ); 251 + assert_nothrow( c013.set("x", ValueLayer, new IntValue(BigInt(13))) ); 252 + assert_eq( c013.get("x", ValueLayer), new IntValue(BigInt(13)) ); 253 + assert_eq( c012.get("x", ValueLayer), new IntValue(BigInt(12)) ); 254 + assert_throw!RuntimeException( c01.get("x", ValueLayer) ); 255 + 256 + assert_nothrow( c01.set("y", ValueLayer, new IntValue(BigInt(1))) ); 257 + assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(1)) ); 258 + assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(1)) ); 259 + assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(1)) ); 258 260 259 - assert_nothrow( c01.set("y", "@v", new IntValue(BigInt(1))) ); 260 - assert_eq( c013.get("y", "@v"), new IntValue(BigInt(1)) ); 261 - assert_eq( c012.get("y", "@v"), new IntValue(BigInt(1)) ); 262 - assert_eq( c01.get("y", "@v"), new IntValue(BigInt(1)) ); 261 + assert_nothrow( c0.set("z", ValueLayer, new IntValue(BigInt(0))) ); 262 + assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); 263 + assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(0)) ); 264 + assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); 265 + assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); 263 266 264 - assert_nothrow( c0.set("z", "@v", new IntValue(BigInt(0))) ); 265 - assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) ); 266 - assert_eq( c012.get("z", "@v"), new IntValue(BigInt(0)) ); 267 - assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) ); 268 - assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) ); 267 + assert_nothrow( c012.set("y", ValueLayer, new IntValue(BigInt(444))) ); 268 + assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(444)) ); 269 + assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(444)) ); 270 + assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(444)) ); 269 271 270 - assert_nothrow( c012.set("y", "@v", new IntValue(BigInt(444))) ); 271 - assert_eq( c013.get("y", "@v"), new IntValue(BigInt(444)) ); 272 - assert_eq( c012.get("y", "@v"), new IntValue(BigInt(444)) ); 273 - assert_eq( c01.get("y", "@v"), new IntValue(BigInt(444)) ); 274 - 275 - assert_nothrow( c012.set("z", "@v", new IntValue(BigInt(555))) ); 276 - assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) ); 277 - assert_eq( c012.get("z", "@v"), new IntValue(BigInt(555)) ); 278 - assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) ); 279 - assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) ); 272 + assert_nothrow( c012.set("z", ValueLayer, new IntValue(BigInt(555))) ); 273 + assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); 274 + assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(555)) ); 275 + assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); 276 + assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); 280 277 281 278 // [TODO] define the semantics and test @layers 282 279 } 283 280 284 281 immutable(LexPosition) extractPos( Table t ) 285 282 { 286 - Layer theLayer = "@v"; 283 + Layer theLayer = ValueLayer; 287 284 if(auto tt = t.access!Table(theLayer, "pos")) 288 285 { 289 286 auto fn = tt.access!StrValue(theLayer, "filename"); 290 287 auto ln = tt.access!IntValue(theLayer, "lineno"); 291 288 auto cl = tt.access!IntValue(theLayer, "column"); 292 289 if(fn !is null && ln !is null && cl !is null) 293 290 return new immutable(LexPosition)(fn.data,cast(int)ln.data.toInt,cast(int)cl.data.toInt);

Modified readme.txt from [6629940451babbd3] to [adcd1590f6f5bc80].

64 64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 65 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 66 66 | ("var"|"let"|"def"|LAYER) ID "=" E 67 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 68 68 // literal 69 69 | INTEGER 70 70 | STRING 71 - | "{" ENTRYS "}" 72 - | "fun" "(" PARAMS ")" "{" E "}" 71 + | "{" ENTRYS "}" // table 72 + | "fun" "(" PARAMS ")" "{" E "}" // anonymous function 73 73 // function call 74 74 | E "(" ARGS")" 75 75 where ARGS ::= E "," ... "," E 76 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER* 77 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E 78 78 ID ::= 'a-zA-Z0-9_...'+ 79 79 LAYER ::= "@" ID 80 80 // operators 81 81 | "(" E ")" 82 - | E "." ID 83 - | E ".?" ID 82 + | E "." ID // table field access 83 + | E ".?" ID // table field existence check 84 + | E "{" ENTRYS "}" // table extend (pure functionally) 84 85 | E BINOP E 85 86 | "if" "(" E ")" "{" E "}" 86 87 | "if" "(" E ")" "{" E "}" "else "{" E "}" 87 88 // layered exec 88 89 | LAYER "(" E ")" 89 90 90 91 The following are actually rewritten to function calls: 91 92 92 93 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 93 94 - E BINOP E ==> BINOP(E, E) 94 95 - E.ID ==> . (E, ID) 95 96 - E.?ID ==> .?(E, ID) 96 97 - {} ==> {}() 97 - - {ID:E, ...} ==> .=({...}, ID, E) 98 + - { ENTRIES } ==> {}{ ENTRIES } 99 + - E {ID:E, ...} ==> (.=(E, ID, E)) { ... } 98 100 99 101 Several styles of variable declaration can be used: 100 102 101 103 - fun(x){ fun(y){x} } # K-combinator 102 104 - fun(x){ let f = fun(y){x} in f } # let-in style 103 105 - fun(x){ var f = fun(y){x}; f } # var-; style 104 106 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var|def)-(;|in) ................................................................................ 125 127 - tables: {car: 1, cdr: {car: 2, cdr: {}}} 126 128 - functions: fun(x){x+1} 127 129 as primitive datatypes. Functions capture lexical closures. 128 130 It is almost 'pure' (except the primitve function "print" and some 129 131 trick inside scoping mechanisms). 130 132 131 133 132 -<<Layer>> 134 +<<Layers :: Overview>> 135 + 136 + Polemy's runtime environment has many "layer"s. 137 + Usual execution run in the @value layer. 138 + 139 + >> 1 + 2 140 + 3 141 + >> @value( 1 + 2 ) 142 + 3 143 + 144 + Here you can see that @LayerName( Expression ) executes the inner Expression in 145 + the @LayerName layer. Other than @value, one other predefined layer exists: @macro. 146 + 147 + >> @macro( 1+2 ) 148 + {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 149 + is@value:app, 150 + arg@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 151 + is@value:int, 152 + data@value:1}, 153 + cdr@value:{ 154 + car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>}, 155 + is@value:int, 156 + data@value:2}, 157 + cdr@value:{}}}, 158 + fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>}, 159 + is@value:var, 160 + name@value:+}} 161 + 162 + (Sorry, this pretty printing is not available on the actual interpreter...) 163 + This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of 164 + the program is its abstract syntax tree. 165 + 166 + You can interleave layers. 167 + The root node of the abstract syntax tree is function "app"lication. 168 + 169 + >> @value(@macro( 1+2 ).is) 170 + app 171 + 172 + 173 + 174 +<<Layers :: Defining a new layer>> 175 + 176 + To define a new layer, you should first tell how to "lift" existing values two the new layer. 177 + Let us define the "@type" layer, where the meaning of programs is their static type. 178 + 179 + >> @@type = fun(x) { 180 + >> if( _isint(x) ) { "int" } else { 181 + >> if( _isfun(x) ) { x } else { "unknown" } } 182 + >> } 183 + (Note: polemy REPL may warn some exception here but please ignore) 184 + 185 + For simplicity, I here deal only with integers. 186 + _isint is a primitive function of Polemy that checks the dynamic type of a value. 187 + For function, leaving it untouched works well for almost all layers. 188 + 189 + >> @type( 1 ) 190 + int 191 + >> @type( 2 ) 192 + int 193 + >> @type( "foo" ) 194 + unknown 195 + 196 + Fine! Let's try to type 1+2. 197 + 198 + >> @type( 1 + 2 ) 199 + ...\value.d(119): [<REPL>:6:8] only @value layer can call native function 200 + 201 + Note that the behavior of this program is 202 + - run 1+2 in the @type layer 203 + and NOT 204 + - run 1+2 in @value and obtain 3 and run 3 in the @type. 205 + The problem is, the variable "+" is defined only in the @value layer. 206 + To carry out computation in the @type layer. We need to define it also 207 + in the @type layer. 208 + 209 + To define some variable in a specific layer, use @LayerName in place of 210 + (let|var|def)s. 211 + 212 + >> let x = 2 213 + >> @value x = 2 214 + >> @type x = "int" 215 + >> @hoge x = "fuga" 216 + 217 + For "+", do it like this. 218 + 219 + >> @type "+" = fun(x,y) {@value( 220 + >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } 221 + >> )} 222 + polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 223 + 224 + It is just computing the return type from the input type. 225 + Not here that the intended "meaning" of if-then-else is the runtime-branching, 226 + and the meaning of "==" is the value-comparison. These are the @value layer 227 + behavior. So we have defined the function body inside @value layer. 228 + But when we refer the variables x and y, we need its @type layer meaning. 229 + Hence we use @type() there. 230 + 231 + Now we get it. 232 + 233 + >> @type( 1 + 2 ) 234 + int 235 + 236 + Well, but do we have to define the @type layer meaning for every variables??? 237 + No. After you defined @type "+", you'll automatically get the following: 238 + 239 + >> def double(x) { x + x } 240 + (function:17e4740:1789720) 241 + 242 + >> @type( double(123) ) 243 + int 244 + 245 + Every user-defined functions are automatically "lift"ed to the appropriate layer. 246 + Only primitive functions like "+" requires @yourNewLayer annotation. 247 + 248 + 249 + 250 +<<Layers :: neutral-layer>> 251 + 252 + let|var|def is to define a variable in the "current" layer. 253 + Not necessary to the @value layer. 254 + 255 + >> @value( let x = 1 in @value(x) ) 256 + 1 257 + 258 + >> @macro( let x = 1 in @value(x) ) 259 + polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found 260 + 261 + >> @macro( let x = 1 in @macro(x) ) 262 + {pos@value:{lineno@value:15, ... 263 + 264 + 265 + 266 +<<Layers :: Layered-Parameters>> 267 + 268 + >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } 269 + (function:1730360:1789720) 270 + 271 + If you annotate function parameters by @LayerNames, when you invoke the function... 272 + 273 + >> foo(1+2) 274 + {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>}, 275 + is@value:app, arg@value:{... 276 + /fst@value:3 277 + /} 278 + 279 + its corresponding arguments are evaluated in the layer and passed to it. 280 + If you specify multiple layers, the argument expression is run multiple times. 281 + If you do not specify any layer for a parameter, it works in the neutral layer. 282 + 283 + 284 + 285 +<<@macro layer>> 286 + 287 + When function is invoked, it first run in the @macro layer, and after that, 288 + it run in the neutral layer. Here is an example. 289 + 290 + >> @macro twice(x) { x; x } 291 + >> def f() { twice(print("Hello")); 999 } 292 + (function:173b6a0:1789720) 293 + >> f() 294 + Hello 295 + Hello 296 + 999 297 + 298 + When the interpreter evaluates f(), it first executes 299 + "twice(print("Hello")); 999" 300 + in the @macro layer. Basically what it does is to just construct its syntax tree. 301 + But, since we have defined the "twice" function in the @macro layer, it is 302 + execute as a function. Resulting syntax tree is 303 + "print("Hello"); print("Hello"); 999" 304 + and this is executed on the neutral (in this example, @value) layer. 305 + This is the reason why you see two "Hello"s. 306 + 307 + 308 + 309 + [[limitations]] 310 + 311 + This @macro layer is a very primitive one, and not a perfect macro language. 312 + Two major limitations are seen in the following "it" example. 313 + 314 + >> @macro LetItBe(x, y) { let it = x in y }; 315 + 316 + The variable name is not hygenic, and so without any effort, the syntax tree "y" 317 + can access the outer variable "it". 318 + 319 + >> def foo() { LetItBe( 1+2+3, it*it ) } 320 + >> foo() 321 + 36 322 + 323 + Of course, this is not just a limitation; it can sometimes allow us to write 324 + many interesting macros. 325 + 326 + The other problem is that the macro expansion is only done at function startup. 327 + So 328 + 329 + >> LetItBe( 1+2+3, it*it ) 330 + ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value 331 + 332 + you cannot directly use the macro in the same scope as the definition. 333 + You need to wrap it up in a function (like the foo() in the above example). 334 + 335 + 336 + 337 + [[quote and unquote]] 338 + 339 + Here is more involved example of code genration. 340 + From "x", it generates "x*x*x*x*x*x*x*x*x*x". 341 + 342 + @macro pow10(x) { 343 + @value( 344 + def pow(x, n) { 345 + if( n == 1 ) { x } 346 + else { 347 + @macro( @value(x) * @value(pow(x,n-1)) ) 348 + } 349 + } 350 + in 351 + pow(@macro(x),10) 352 + ) 353 + }; 133 354 134 - to be written 355 + Here, x is a syntax tree but n is an actual integer. If you read carefully, 356 + you should get what is going on. Basically, @macro can be considered like 357 + quasiquoting and @value to be an escape from it.

Modified sample/macro.pmy from [a38c7267da8f14a3] to [274d10aca22ce25f].

7 7 def maxNormal(x,y) { 8 8 if(x<y){y}else{x} 9 9 }; 10 10 @macro maxBad(x,y) { 11 11 if(x<y){y}else{x} 12 12 }; 13 13 14 -@macro LetItBe(x, y) { 15 - let it = x in y 16 -}; 14 +@macro LetItBe(x, y) { let it = x in y }; 17 15 18 16 @macro pow10(x) { 19 - @v( 17 + @value( 20 18 def pow(x, n) { 21 19 if( n == 1 ) { x } 22 20 else { 23 - @macro( @v(x) * @v(pow(x,n-1)) ) 21 + @macro( @value(x) * @value(pow(x,n-1)) ) 24 22 } 25 23 } 26 24 in 27 25 pow(@macro(x),10) 28 26 ) 29 27 }; 30 28