Overview
SHA1 Hash: | 515502e8d1fa4b18993621b1ed16e936b4675d5e |
---|---|
Date: | 2010-11-20 18:20:03 |
User: | kinaba |
Comment: | table get, init, ask expressions addded |
Timelines: | family | ancestors | descendants | both | trunk |
Downloads: | Tarball | ZIP archive |
Other Links: | files | file ages | manifest |
Tags And Properties
- branch=trunk inherited from [f65680e1d2]
- sym-trunk inherited from [f65680e1d2]
Changes
Modified d2stacktrace/stacktrace.d from [2d470e3c95d4cfbd] to [9e66870b7d120c42].
353 353 if(isOK) 354 354 lineStr ~= demangledName; 355 355 356 356 DWORD zeichen = 0; 357 357 if(Dbghelp.SymGetLineFromAddr64(hProcess,stackframe.AddrPC.Offset,&zeichen,&Line) == TRUE){ 358 358 char[] fileName = new char[strlen(Line.FileName)]; 359 359 fileName = std.path.basename( Line.FileName[0..fileName.length] ); 360 - lineStr = to!string(fileName ~ "::" ~ to!string(Line.LineNumber) ~ "(" ~ to!string(zeichen) ~ ") " ~ lineStr); 360 + lineStr = text(fileName ~ "::" ~ text(Line.LineNumber) ~ "(" ~ text(zeichen) ~ ") " ~ lineStr); 361 361 } 362 362 } 363 363 else { 364 - lineStr = to!string(cast(ulong)stackframe.AddrPC.Offset); 364 + lineStr = text(cast(ulong)stackframe.AddrPC.Offset); 365 365 } 366 - lineStr = to!string(frameNum-2) ~ " " ~ lineStr; 366 + lineStr = text(frameNum-2) ~ " " ~ lineStr; 367 367 if(frameNum-2 < 10) 368 368 lineStr = "0" ~ lineStr; 369 369 if(frameNum >= 2) 370 370 stack.append(lineStr); 371 371 } 372 372 } 373 373 374 374 free(Symbol); 375 375 return stack; 376 376 } 377 377 }; 378 378
Modified polemy/_common.d from [7abcb8181e6c0ff0] to [ae51765dfb783149].
1 1 /** 2 2 * Authors: k.inaba 3 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 4 * 5 - * "Always-opend" modules inside Polemy. 5 + * These modules are globaly used inside Polemy. 6 6 */ 7 7 module polemy._common; 8 -public import std.array; 9 -public import std.range; 8 +public import tricks.test; 9 +public import tricks.tricks; 10 10 public import std.algorithm; 11 -public import std.conv : to; 11 +public import std.array; 12 12 public import std.bigint; 13 +public import std.conv : text; 13 14 public import std.exception; 14 -public import tricks.tricks; 15 -public import tricks.test; 15 +public import std.range; 16 16 public import std.stdio : writeln; // for debugging...
Modified polemy/eval.d from [5c2f449580dd9555] to [6db0ce492da06d00].
9 9 import polemy.lex : LexPosition; 10 10 import polemy.ast; 11 11 import polemy.parse; 12 12 import polemy.value; 13 13 import std.typecons; 14 14 import std.stdio; 15 15 16 -// [todo] move to value.d 17 - 18 -FunValue nativef(Value delegate(immutable LexPosition pos, Layer lay, Value[] args) dg) 19 -{ 20 - return new FunValue(dg); 21 -} 22 - 23 -FunValue native(R,T...)(R delegate (T) dg) 24 -{ 25 - return nativef( delegate Value(immutable LexPosition pos, Layer lay, Value[] args) { 26 - if( lay != "@v" ) 27 - throw genex!RuntimeException(pos, "only @v layer can call native function"); 28 - if( T.length != args.length ) 29 - throw genex!RuntimeException(pos, "argument number mismatch!"); 30 - T typed_args; 31 - foreach(i, Ti; T) 32 - { 33 - typed_args[i] = cast(Ti) args[i]; 34 - if( typed_args[i] is null ) 35 - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 36 - } 37 - try { 38 - return dg(typed_args); 39 - } catch( RuntimeException e ) { 40 - throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 41 - } 42 - }); 43 -} 44 - 45 16 /// 46 17 Table createGlobalContext() 47 18 { 48 19 auto ctx = new Table; 49 20 ctx.set("+", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} )); 50 21 ctx.set("-", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} )); 51 22 ctx.set("*", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} )); ................................................................................ 74 45 return (x.data == 0 ? fe : ft).call(pos,lay,[]); 75 46 throw genex!RuntimeException(pos, "type mismatch in if"); 76 47 })); 77 48 ctx.set("_isint", "@v", native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} )); 78 49 ctx.set("_isstr", "@v", native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} )); 79 50 ctx.set("_isfun", "@v", native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} )); 80 51 ctx.set("_isundefined", "@v", native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} )); 52 + ctx.set("_istable", "@v", native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} )); 53 + ctx.set(".", "@v", native( (Table t, StrValue s){ 54 + return (t.has(s.data, "@v") ? t.get(s.data, "@v") : new UndValue); 55 + }) ); 56 + ctx.set(".?", "@v", native( (Table t, StrValue s){ 57 + return new IntValue(BigInt(t.has(s.data, "@v") ? 1 : 0)); 58 + }) ); 59 + ctx.set(".=", "@v", native( (Table t, StrValue s, Value v){ 60 + auto t2 = new Table(t, Table.Kind.NotPropagateSet); 61 + t2.set(s.data, "@v", v); 62 + return t2; 63 + }) ); 64 + ctx.set("{}", "@v", native( (){ 65 + return new Table; 66 + }) ); 81 67 return ctx; 82 68 } 83 69 84 70 /// Entry point of this module 85 71 86 72 Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn) 87 73 {
Modified polemy/lex.d from [a4ea515a0f014c9c] to [f9cdaf211a0e9fb0].
50 50 unittest 51 51 { 52 52 auto p = new LexPosition("hello.cpp", 123, 45); 53 53 54 54 assert_eq( p.filename, "hello.cpp" ); 55 55 assert_eq( p.lineno, 123 ); 56 56 assert_eq( p.column, 45 ); 57 - assert_eq( to!string(p), "hello.cpp:123:45" ); 57 + assert_eq( text(p), "hello.cpp:123:45" ); 58 58 59 59 assert( !__traits(compiles, new LexPosition) ); 60 60 assert( !__traits(compiles, p.filename="foo") ); 61 61 assert( !__traits(compiles, p.lineno =789) ); 62 62 assert( !__traits(compiles, p.column =222) ); 63 63 64 64 auto q = new LexPosition("hello.cpp", 123, 46);
Modified polemy/parse.d from [7ed0053850ffa032] to [6bec0997c5764737].
163 163 ["|"], 164 164 ["^"], 165 165 ["&"], 166 166 ["<<", ">>"], 167 167 ["+","-"], 168 168 ["~"], 169 169 ["*","/","%"], 170 - ["^^","**"] 170 + ["^^","**"], 171 + [".",".?"] 171 172 ]; 172 173 173 174 AST E(size_t level) 174 175 { 175 176 /// Expression ::= (Binary left-associative operators over) Funcall 176 177 177 178 AST rec(AST lhs) ................................................................................ 178 179 { 179 180 if( closingBracket() ) 180 181 return lhs; 181 182 182 183 auto pos = currentPosition(); 183 184 foreach(op; operator_perferences[level]) 184 185 if( tryEat(op) ) 186 + if( op[0]=='.' ) 187 + return rec( 188 + new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, parseId())); 189 + else 185 190 return rec( 186 191 new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, E(level+1))); 187 192 return lhs; 188 193 } 189 194 190 195 if( operator_perferences.length <= level ) 191 196 return Funcall(); ................................................................................ 241 246 return new LayeredExpression(pos, lay, e); 242 247 } 243 248 if( tryEat("(") ) 244 249 { 245 250 auto e = Body(); 246 251 eat(")", "after parenthesized expression"); 247 252 return e; 253 + } 254 + if( tryEat("{") ) 255 + { 256 + AST e = new FuncallExpression(pos, new VarExpression(pos,"{}")); 257 + if( tryEat("}") ) 258 + return e; 259 + for(;;) 260 + { 261 + string key = eatId("for table key", AllowQuoted); 262 + eat(":", "after table key"); 263 + AST val = E(0); 264 + e = new FuncallExpression(pos, new VarExpression(pos,".="), 265 + e, new StrLiteral(pos,key), val); 266 + if( !tryEat(",") ) 267 + { 268 + eat("}", "for the end of table literal"); 269 + break; 270 + } 271 + } 272 + return e; 248 273 } 249 274 if( tryEat("if") ) 250 275 { 251 276 eat("(", "after if"); 252 277 auto cond = E(0); 253 278 eat(")", "after if condition"); 254 279 auto thenPos = lex.front.pos; ................................................................................ 273 298 { 274 299 eat("(", "after fun"); 275 300 return parseLambdaAfterOpenParen(pos); 276 301 } 277 302 scope(exit) lex.popFront; 278 303 return new VarExpression(pos, lex.front.str); 279 304 } 305 + 306 + AST parseId() 307 + { 308 + scope(exit) lex.popFront; 309 + return new StrLiteral(currentPosition(), lex.front.str); 310 + } 280 311 281 312 AST parseLambdaAfterOpenParen(immutable LexPosition pos) 282 313 { 283 314 Parameter[] params; 284 315 while( !tryEat(")") ) 285 316 { 286 317 params ~= parseParam(); ................................................................................ 434 465 let("foo", "", 435 466 fun(["x"], call(var("+"), var("x"), intl(1))), 436 467 var("foo")) 437 468 ); 438 469 439 470 assert_eq(parseString(`@@type ( x ) { x }`), 440 471 let("@type", "(system)", fun(["x"], var("x")), var("@type")) ); 472 + 473 + assert_eq(parseString(`{}`), call(var("{}"))); 474 + assert_eq(parseString(`{foo:1,"bar":2}`), 475 + call(var(".="), call(var(".="), call(var("{}")), strl("foo"), intl(1)), strl("bar"), intl(2))); 476 + assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo"))); 477 + assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("foo"))); 441 478 }
Modified polemy/value.d from [fe3f0c39a200a0bc] to [a4c75e644b34fb64].
17 17 18 18 /// Runtime values of Polemy 19 19 20 20 abstract class Value 21 21 { 22 22 } 23 23 24 +/// 24 25 class IntValue : Value 25 26 { 26 27 BigInt data; 27 28 28 29 mixin SimpleClass; 29 30 override string toString() const { return std.bigint.toDecimalString(cast(BigInt)data); } 30 31 } 31 32 33 +/// 32 34 class StrValue : Value 33 35 { 34 36 string data; 35 37 36 38 mixin SimpleClass; 37 39 override string toString() const { return data; } 38 40 } 39 41 42 +/// 40 43 class FunValue : Value 41 44 { 42 45 Value delegate(immutable LexPosition pos, string lay, Value[]) data; 43 46 44 47 mixin SimpleConstructor; 45 48 alias data call; 46 49 override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); } 47 50 } 48 51 52 +/// 49 53 class UndValue : Value 50 54 { 51 55 mixin SimpleClass; 52 56 override string toString() const { return "<undefined>"; } 53 57 } 58 + 59 +/// Named Constructor for FunValue 60 + 61 +FunValue nativef(Value delegate(immutable LexPosition pos, Layer lay, Value[] args) dg) 62 +{ 63 + return new FunValue(dg); 64 +} 65 + 66 +/// Named Constructor for FunValue 67 + 68 +FunValue native(R,T...)(R delegate (T) dg) 69 +{ 70 + return nativef( delegate Value(immutable LexPosition pos, Layer lay, Value[] args) { 71 + if( lay != "@v" ) 72 + throw genex!RuntimeException(pos, "only @v layer can call native function"); 73 + if( T.length != args.length ) 74 + throw genex!RuntimeException(pos, "argument number mismatch!"); 75 + T typed_args; 76 + foreach(i, Ti; T) 77 + { 78 + typed_args[i] = cast(Ti) args[i]; 79 + if( typed_args[i] is null ) 80 + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 81 + } 82 + try { 83 + return dg(typed_args); 84 + } catch( RuntimeException e ) { 85 + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 86 + } 87 + }); 88 +} 54 89 55 90 /// Layer ID 56 91 57 92 alias string Layer; 58 93 59 94 /// Context (variable environment) 60 95 /// Simlar to prototype chain of ECMAScript etc. ................................................................................ 69 104 70 105 void set(string i, Layer lay, Value v, in LexPosition pos=null) 71 106 { 72 107 if( setIfExist(i, lay, v) ) 73 108 return; 74 109 data[i][lay] = v; 75 110 } 111 + 112 + bool has(string i, Layer lay, in LexPosition pos=null) 113 + { 114 + if( i in data ) { 115 + if( lay !in data[i] ) 116 + return false; 117 + return true; 118 + } 119 + if( prototype is null ) 120 + return false; 121 + return prototype.has(i, lay, pos); 122 + } 76 123 77 124 Value get(string i, Layer lay, in LexPosition pos=null) 78 125 { 79 126 if( i in data ) { 127 + // [TODO] consider forwarding to proto also in this case 80 128 if( lay !in data[i] ) 81 129 throw genex!RuntimeException(pos, sprintf!"variable %s is not set in layer %s"(i,lay)); 82 130 return data[i][lay]; 83 131 } 84 132 if( prototype is null ) 85 133 throw new RuntimeException(pos, sprintf!"variable %s not found"(i)); 86 134 return prototype.get(i, lay, pos);
Modified readme.txt from [7d7a59abebf26f18] to [b45d599d08f18ee0].
1 1 ----------------------------------------------------------------------------- 2 2 Polemy 0.1.0 3 3 by k.inaba (www.kmonos.net) 4 - Nov 8, 2010 4 + Nov 20, 2010 5 5 ----------------------------------------------------------------------------- 6 6 7 7 8 8 9 9 <<How to Build>> 10 10 11 11 - Install DMD 12 12 http://www.digitalmars.com/d/2.0/changelog.html 13 - Version 2.050 is recommended. Older and/or newer version may not work. 13 + Version 2.050 is recommended. Older or newer version may not work. 14 14 15 15 - Build 16 16 (for Windows) Run build.bat 17 17 (for Unix) Run build.sh 18 18 or use your favorite build tools upon main.d and polemy/*.d. 19 19 20 20 Then you will get the executable "polemy" in the "bin" directory. ................................................................................ 43 43 44 44 > polemy 45 45 starts REPL 46 46 47 47 > polemy foo.pmy 48 48 executes foo.pmy 49 49 50 + > polemy -l foo.pmy 51 + after executing foo.pmy, starts REPL 50 52 51 53 52 -<<Memo of Language Spec>> 53 54 54 -syntax 55 +<<Syntax>> 55 56 56 - E ::= ("var"|"let"|"def"|LAYER) ID "=" E ; E 57 + Comment is "# ... \n" 58 + 59 + E ::= 60 + // declaration 61 + | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 62 + | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 63 + | ("var"|"let"|"def"|LAYER) ID "=" E 64 + | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 65 + // literal 66 + | INTEGER 67 + | STRING 68 + | "{" ENTRYS "}" 57 69 | "fun" "(" PARAMS ")" "{" E "}" 58 - | E "(" ARGS ")" 59 - 60 - | LAYER "(" E ")" 61 - 70 + // function call 71 + | E "(" ARGS")" 72 + where ARGS ::= E "," ... "," E 73 + PARAMS ::= ID LAYER* "," ... "," ID LAYER* 74 + ENTRYS ::= ID ":" E "," ... "," ID ":" E 75 + ID ::= 'a-zA-Z0-9_...'+ 76 + LAYER ::= "@" ID 77 + // operators 62 78 | "(" E ")" 79 + | E "." ID 80 + | E ".?" ID 63 81 | E BINOP E 64 82 | "if" "(" E ")" "{" E "}" 65 83 | "if" "(" E ")" "{" E "}" "else "{" E "}" 66 - | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 84 + // layered exec 85 + | LAYER "(" E ")" 86 + 87 +The following are actually rewritten to function calls: 88 + 89 + - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 90 + - E BINOP E ==> BINOP(E, E) 91 + - E.ID ==> . (E, ID) 92 + - E.?ID ==> .?(E, ID) 93 + - {} ==> {}() 94 + - {ID:E, ...} ==> .=({...}, ID, E) 95 + 96 +Several styles of variable declaration can be used: 97 + 98 + - fun(x){ fun(y){x} } # K-combinator 99 + - fun(x){ let f = fun(y){x} in f } # let-in style 100 + - fun(x){ var f = fun(y){x}; f } # var-; style 101 + - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var|def)-(;|in) 102 + - fun(x){ def f(y){x} in f } # syntax sugar for function declaration 103 + - fun(x){ let f(y){x}; f } # this is also ok 104 + - fun(x){ var f(y){x} } # omitting (;|in) returns the last declared object directly 105 + - fun(x,y){x} #< this is not equal to the above ones. functions are no curried. 106 + 107 +NOTE: Theres no "let rec" syntax, but still recursive definition works 108 + def f(x) { if(x==0){1}else{x*f(x-1)} } in f(10) #=> 3628800 109 + yet still the code below also works 110 + def x=21 in def x=x+x in x #=> 42. 111 + The internal scoping mechanism is a little tricky (this is for coping with 112 + the "layer" feature explained below), but I hope that it works as everyone 113 + expects in most cases, as long as you don't use the same-name-variables heavily :). 114 + 115 + 67 116 68 -ARGS ::= ","-separated E's 69 -PARAMS ::= ","-separated VAR's 70 -LAYER ::= "@" ID 117 +<<Basic Features>> 71 118 72 -if-then-else is a syntax sugar for a function call: if( E, fun(){E}, fun(){E} ) 73 -binary ops (e.g., E + E) is a syntax sugar: +(E, E) 119 + Polemy is an untyped functional programming language that has 120 + - integers: 0, 123, 456666666666666666666666666666666666666789, ... 121 + - strings: "hello, world!\n", ... 122 + - tables: {car: 1, cdr: {car: 2, cdr: {}}} 123 + - functions: fun(x){x+1} 124 + as primitive datatypes. Functions capture lexical closures. 125 + It is almost 'pure' (except the primitve function "print" and some 126 + trick inside scoping mechanisms). 127 + 74 128 75 -comment is "# ... \n" 129 +<<Layer>> 76 130 131 + to be written
Modified tricks/test.d from [fc21831342965670] to [b9b84a35fccc5116].
1 1 /** 2 2 * Authors: k.inaba 3 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 4 * 5 - * Unittest helpers. 6 - * TODO: use stderr instead of stdout. the problem is that std.cstream is xxxx.... 7 - * TODO: is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? 5 + * Hepler routines for unittesting. 6 + * TODO: Is there any clean way to implement "assert_compiles" and "assert_not_compile"? 8 7 */ 9 8 module tricks.test; 10 -import std.conv : to; 9 +import std.conv : text; 11 10 import core.exception; 12 11 13 12 version(unittest) 14 13 { 15 - import std.stdio; 14 + import std.cstream; 16 15 import core.runtime; 17 16 18 - // Install custom test runner 19 17 static this() 20 18 { 19 + installCustomTestRunner(); 20 + } 21 + 22 + private void installCustomTestRunner() 23 + { 21 24 Runtime.moduleUnitTester = function() 22 25 { 23 - Throwable ee = null; 24 - size_t failed=0; 25 - foreach(m; ModuleInfo) if(m) if(auto fp=m.unitTest) 26 + Throwable firstError = null; 27 + 28 + void logError(Throwable e) 29 + { 30 + if(firstError is null) 31 + firstError = e; 32 + derr.writefln(" !! %s(%d): %s", e.file, e.line, e.msg); 33 + } 34 + 35 + void testModule(ModuleInfo* m, void function() test) 26 36 { 27 - writeln("[TEST] ", m.name); 28 - try { 29 - fp(); 30 - } catch( Throwable e ) { 31 - if(ee is null) 32 - ee = e; 33 - failed++; 34 - writeln(" !! ",e.file,"(",e.line,"): ",e.msg); 35 - } 37 + derr.writefln("[TEST] %s", m.name); 38 + try { test(); } catch( Throwable e ) { logError(e); } 36 39 } 37 - if(ee !is null) 40 + 41 + bool report() 38 42 { 39 - writeln("[TEST] ",failed," modules failed. The first error was:"); 40 - writeln(ee); 41 - write("[TEST] press enter to exit."); 42 - readln(); 43 + if(firstError is null) 44 + return true; 45 + derr.writefln("[TEST] The first error was:\n%s", firstError); 46 + derr.writeString("[TEST] press enter to exit."); 47 + din.readLine(); 43 48 return false; 44 49 } 45 - return true; 50 + 51 + foreach(m; ModuleInfo) 52 + if(m && m.unitTest) 53 + testModule(m, m.unitTest); 54 + return report(); 46 55 }; 47 56 } 48 57 } 49 58 50 59 /// Unittest helper that asserts an expression must throw something 51 60 52 61 void assert_throw(ExcT=Throwable, T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="") ................................................................................ 97 106 { 98 107 void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(A a, B b, string msg="") 99 108 { 100 109 try 101 110 { if( mixin("a"~op~"b") ) return; } 102 111 catch(Throwable e) 103 112 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); } 104 - onAssertErrorMsg(fn, ln, msg.length ? msg : to!string(a)~" !"~op~" "~to!string(b)); 113 + onAssertErrorMsg(fn, ln, msg.length ? msg : text(a, " !", op, " ", b)); 105 114 } 106 115 } 107 116 108 117 alias assertOp!(`==`) assert_eq; /// asserts two operands are == 109 118 alias assertOp!(`!=`) assert_ne; /// asserts two operands are != 110 119 alias assertOp!(`<`) assert_lt; /// asserts two operands are < 111 120 alias assertOp!(`<=`) assert_le; /// asserts two operands are <=
Modified tricks/tricks.d from [d1500d1519df592c] to [0eae6cc37f045c97].
2 2 * Authors: k.inaba 3 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 4 * 5 5 * Common tricks and utilities for programming in D. 6 6 */ 7 7 module tricks.tricks; 8 8 import tricks.test; 9 -import std.array : appender; 10 -import std.format : formattedWrite; 11 9 import core.exception; 10 +import std.array : appender; 11 +import std.format : formattedWrite; 12 12 import std.traits; 13 13 import std.typetuple; 14 14 15 15 /// Simple Wrapper for std.format.doFormat 16 16 17 17 string sprintf(string fmt, T...)(T params) 18 18 { ................................................................................ 106 106 template SimpleCompare() 107 107 { 108 108 override bool opEquals(Object rhs_) const /// member-by-member equality 109 109 { 110 110 if( auto rhs = cast(typeof(this))rhs_ ) 111 111 { 112 112 foreach(i,_; this.tupleof) 113 - if( this.tupleof[i] != rhs.tupleof[i] ) 113 + if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) 114 114 return false; 115 115 return true; 116 116 } 117 117 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 118 118 } 119 119 120 120 override hash_t toHash() const /// member-by-member hash ................................................................................ 126 126 } 127 127 128 128 override int opCmp(Object rhs_) const /// member-by-member compare 129 129 { 130 130 if( auto rhs = cast(typeof(this))rhs_ ) 131 131 { 132 132 foreach(i,_; this.tupleof) 133 - if( this.tupleof[i] != rhs.tupleof[i] ) { 134 - auto a = this.tupleof[i]; 133 + if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) { 134 + auto a = (cast(SC_Unqual!(typeof(this)))this).tupleof[i]; 135 135 auto b = rhs.tupleof[i]; 136 - return cast(SC_Unqual!(typeof(a)))a < b ? -1 : +1; 136 + return a < b ? -1 : +1; 137 137 } 138 +// not work well for structures??????? 138 139 // if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i])) 139 140 // return c; 140 141 return 0; 141 142 } 142 143 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 143 144 } 144 145 } ................................................................................ 319 320 mixin SimpleConstructor; 320 321 } 321 322 class D2 : Base { 322 323 string s; 323 324 mixin SimpleConstructor; 324 325 } 325 326 class D3 : Base { 326 - int[int]m; 327 + int[int] m; 327 328 mixin SimpleConstructor; 328 329 } 329 330 330 331 Base d1 = new D1(1, 2.3); 331 332 Base d2 = new D2("foobar"); 332 333 Base d3 = new D3(null); (cast(D3)d3).m[1]=10; 333 334 334 335 // normal dispatch 335 336 assert_eq( d1.match( 336 337 (D1 x){return 1;}, 337 - (D2 x){return 2;}, 338 + (D2 x){return 2;} 338 339 ), 1); 339 340 assert_eq( d2.match( 340 341 (D1 x){return 1;}, 341 - (D2 x){return 2;}, 342 + (D2 x){return 2;} 342 343 ), 2); 343 344 assert_throw!AssertError( d3.match( 344 345 (D1 x){return 1;}, 345 - (D2 x){return 2;}, 346 + (D2 x){return 2;} 346 347 )); 347 348 assert_eq( d3.match( 348 349 (D1 x){return 1;}, 349 350 (D2 x){return 2;}, 350 - (Base x){return 3;}, 351 + (Base x){return 3;} 351 352 ), 3); 352 353 assert_eq( d2.match( 353 354 (D1 x){return 1;}, 354 355 (D2 x){return 2;}, 355 - (Base x){return 3;}, 356 + (Base x){return 3;} 356 357 ), 2); 357 358 assert_eq( d2.match( 358 359 (D1 x){return 1;}, 359 360 (Base x){return 3;}, 360 - (D2 x){return 2;}, 361 + (D2 x){return 2;} 361 362 ), 3); 362 363 363 364 // member decomposing match 364 365 assert_eq( d1.match( 365 366 when!(D1, (x, y){return x + cast(int)y;}), 366 367 when!(D2, (x){return x.length;}), 367 - when!(D3, (x){return x[1];}), 368 + when!(D3, (x){return x[1];}) 368 369 ), 3); 369 370 assert_eq( d2.match( 370 371 when!(D1, (x, y){return x + cast(int)y;}), 371 372 when!(D2, (x){return x.length;}), 372 - when!(D3, (x){return x[1];}), 373 + when!(D3, (x){return x[1];}) 373 374 ), 6); 374 375 assert_eq( d3.match( 375 376 when!(D1, (x, y){return x + cast(int)y;}), 376 377 when!(D2, (x){return x.length;}), 377 - when!(D3, (x){return x[1];}), 378 + when!(D3, (x){return x[1];}) 378 379 ), 10); 379 380 assert_throw!AssertError( d3.match( 380 381 when!(D1, (x, y){return x + cast(int)y;}), 381 - when!(D2, (x){return x.length;}), 382 + when!(D2, (x){return x.length;}) 382 383 )); 383 384 assert_eq( d2.match( 384 385 when!(D1, (x, y){return x + cast(int)y;}), 385 386 when!(D2, (x){return x.length;}), 386 - otherwise!({return 999;}), 387 + otherwise!({return 999;}) 387 388 ), 6); 388 389 assert_eq( d2.match( 389 390 when!(D1, (x, y){return x + cast(int)y;}), 390 391 otherwise!({return 999;}), 391 - when!(D2, (x){return x.length;}), 392 + when!(D2, (x){return x.length;}) 392 393 ), 999); 393 394 }