Overview
SHA1 Hash: | 1c01f44f52d9db646f9dec7e2b3e495e81145505 |
---|---|
Date: | 2010-11-13 11:48:58 |
User: | kinaba |
Comment: | simplepatternmatch |
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 polemy/ast.d from [239622603e376c11] to [f8a685431329b03d].
9 import polemy.lex; 9 import polemy.lex; 10 10 11 /// 11 /// 12 abstract class AST 12 abstract class AST 13 { 13 { 14 immutable LexPosition pos; 14 immutable LexPosition pos; 15 mixin SimpleConstructor; 15 mixin SimpleConstructor; > 16 mixin SimplePatternMatch; 16 } 17 } 17 18 18 /// 19 /// 19 class StrLiteral : AST 20 class StrLiteral : AST 20 { 21 { 21 string data; 22 string data; 22 mixin SimpleClass; 23 mixin SimpleClass;
Modified polemy/eval.d from [9d70fd9339035713] to [a16d8d322739557e].
105 Table ctx = createGlobalContext(); 105 Table ctx = createGlobalContext(); 106 return typeof(return)(eval(e, ctx, false, "@v"), ctx); 106 return typeof(return)(eval(e, ctx, false, "@v"), ctx); 107 } 107 } 108 108 109 /// Entry point of this module 109 /// Entry point of this module 110 /// If splitCtx = true, then inner variable declaration do not overwrite ctx. 110 /// If splitCtx = true, then inner variable declaration do not overwrite ctx. 111 /// lay is the layer ID for evaluation (standard value semantics uses "@v"). 111 /// lay is the layer ID for evaluation (standard value semantics uses "@v"). 112 < > 112 import std.typetuple; 113 Value eval(AST _e, Table ctx, bool splitCtx, Layer lay) | 113 Value eval(AST e, Table ctx, bool splitCtx, Layer lay) 114 { 114 { > 115 return e.match( 115 if( auto e = cast(StrLiteral)_e ) | 116 (StrLiteral e) 116 { | 117 { 117 return new StrValue(e.data); | 118 return new StrValue(e.data); 118 } | 119 }, 119 else < 120 if( auto e = cast(IntLiteral)_e ) | 120 (IntLiteral e) 121 { | 121 { 122 return new IntValue(e.data); | 122 return new IntValue(e.data); 123 } | 123 }, 124 else < 125 if( auto e = cast(VarExpression)_e ) | 124 (VarExpression e) 126 { | 125 { 127 return ctx.get(e.var, lay, e.pos); | 126 return ctx.get(e.var, lay, e.pos); 128 } | 127 }, 129 else < 130 if( auto e = cast(LayeredExpression)_e ) | 128 (LayeredExpression e) 131 { | 129 { 132 return eval(e.expr, ctx, false, e.lay); | 130 return eval(e.expr, ctx, false, e.lay); 133 } | 131 }, 134 else < 135 if( auto e = cast(LetExpression)_e ) | 132 (LetExpression e) 136 { | 133 { 137 // for letrec, we need this, but should avoid overwriting???? | 134 // for letrec, we need this, but should avoid overwritin 138 // ctx.set(e.var, "@v", new UndefinedValue, e.pos); | 135 // ctx.set(e.var, "@v", new UndefinedValue, e.pos); 139 Value v = eval(e.init, ctx, true, lay); | 136 Value v = eval(e.init, ctx, true, lay); 140 if(splitCtx) | 137 if(splitCtx) 141 ctx = new Table(ctx, Table.Kind.NotPropagateSet); | 138 ctx = new Table(ctx, Table.Kind.NotPropagateSet) 142 ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); | 139 ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.po 143 return eval(e.expr, ctx, false, lay); | 140 return eval(e.expr, ctx, false, lay); 144 } | 141 }, 145 else < 146 if( auto e = cast(FuncallExpression)_e ) | 142 (FuncallExpression e) 147 { | 143 { 148 Value _f = eval(e.fun, ctx, true, lay); | 144 Value _f = eval(e.fun, ctx, true, lay); 149 if( auto f = cast(FunValue)_f ) { | 145 if( auto f = cast(FunValue)_f ) { 150 Value[] args; | 146 Value[] args; 151 foreach(a; e.args) | 147 foreach(a; e.args) 152 args ~= eval(a, ctx, true, lay); | 148 args ~= eval(a, ctx, true, lay); 153 return f.call(e.pos, lay, args); | 149 return f.call(e.pos, lay, args); 154 } else < > 150 } 155 throw genex!RuntimeException(e.pos, "Non-funcion is appl 151 throw genex!RuntimeException(e.pos, "Non-funcion is appl 156 } | 152 }, 157 else < 158 if( auto e = cast(FunLiteral)_e ) | 153 (FunLiteral e) 159 { | 154 { 160 return new FunValue(delegate Value(immutable LexPosition pos, st | 155 return new FunValue(delegate Value(immutable LexPosition 161 if( e.params.length != args.length ) | 156 if( e.params.length != args.length ) 162 throw genex!RuntimeException(e.pos, sprintf!"Arg | 157 throw genex!RuntimeException(e.pos, spri 163 (e.params.length, args.length)); | 158 (e.params.length, args.length)); 164 Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet | 159 Table ctxNeo = new Table(ctx, Table.Kind.NotProp 165 foreach(i,p; e.params) | 160 foreach(i,p; e.params) 166 ctxNeo.set(p.name, lay, args[i]); | 161 ctxNeo.set(p.name, lay, args[i]); 167 return eval(e.funbody, ctxNeo, true, lay); | 162 return eval(e.funbody, ctxNeo, true, lay); 168 }); | 163 }); 169 } | 164 }, > 165 delegate Value (AST e) > 166 { 170 throw genex!RuntimeException(_e.pos, sprintf!"Unknown Kind of Expression | 167 throw genex!RuntimeException(e.pos, sprintf!"Unknown Kin > 168 } > 169 ); 171 } 170 } 172 171 173 unittest 172 unittest 174 { 173 { 175 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); 174 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); 176 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 175 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 177 assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21)) ); 176 assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21)) );
Modified polemy/lex.d from [4e484112cd314d8d] to [a4ea515a0f014c9c].
13 template ExceptionWithPosition() 13 template ExceptionWithPosition() 14 { 14 { 15 const LexPosition pos; 15 const LexPosition pos; 16 this( const LexPosition pos, string msg, string file=null, size_t line=0 16 this( const LexPosition pos, string msg, string file=null, size_t line=0 17 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos 17 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos 18 } 18 } 19 19 20 /// | 20 /// Thrown when encountered an EOF in the middle of a lexical token > 21 21 class UnexpectedEOF : Exception 22 class UnexpectedEOF : Exception 22 { 23 { 23 mixin ExceptionWithPosition; 24 mixin ExceptionWithPosition; 24 } 25 } 25 26 26 /// | 27 /// Thrown when encountered a lexical error > 28 27 class LexException : Exception 29 class LexException : Exception 28 { 30 { 29 mixin ExceptionWithPosition; 31 mixin ExceptionWithPosition; 30 }; 32 }; 31 33 32 /// Represents a position in a source code | 34 /// Represents a position in source codes 33 35 34 class LexPosition 36 class LexPosition 35 { 37 { 36 immutable string filename; /// name of the source file 38 immutable string filename; /// name of the source file 37 immutable int lineno; /// 1-origin 39 immutable int lineno; /// 1-origin 38 immutable int column; /// 1-origin 40 immutable int column; /// 1-origin 39 41 ................................................................................................................................................................................ 93 assert( !__traits(compiles, t.pos=p) ); 95 assert( !__traits(compiles, t.pos=p) ); 94 assert( !__traits(compiles, t.str=789) ); 96 assert( !__traits(compiles, t.str=789) ); 95 assert( !__traits(compiles, t.quoted=true) ); 97 assert( !__traits(compiles, t.quoted=true) ); 96 } 98 } 97 99 98 /// Named Construtors for Lexer 100 /// Named Construtors for Lexer 99 101 100 Lexer lexerFromFile(T...)( string filename, T rest ) | 102 Lexer lexerFromFile(T...)( string filename, T ln_cn ) 101 { 103 { 102 return lexerFromString( std.file.readText(filename), filename, rest ); | 104 return lexerFromString( std.file.readText(filename), filename, ln_cn ); 103 } 105 } 104 106 105 /// Named Construtors for Lexer | 107 /// Named Construtor for Lexer 106 108 107 LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzi 109 LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzi 108 lexerFromString(CharSeq)( CharSeq str, string filename="<unnamed>", int lineno=1 110 lexerFromString(CharSeq)( CharSeq str, string filename="<unnamed>", int lineno=1 109 { 111 { 110 return new LexerT!(PositionedReader!CharSeq)( 112 return new LexerT!(PositionedReader!CharSeq)( 111 PositionedReader!CharSeq(str, filename, lineno, column) 113 PositionedReader!CharSeq(str, filename, lineno, column) 112 ); 114 ); 113 } 115 } 114 116 115 /// Standard Lexer Type (all you have to know is that this is a forward range of | 117 /// Standard Lexer Type (all you have to know is that this is a forward range of 116 118 117 alias LexerT!(PositionedReader!string) Lexer; 119 alias LexerT!(PositionedReader!string) Lexer; 118 120 119 /// Lexer Implementation 121 /// Lexer Implementation 120 122 121 class LexerT(Reader) 123 class LexerT(Reader) 122 if( isForwardRange!(Reader) && is(ElementType!(Reader) == dchar) ) | 124 if( isForwardRange!(Reader) && is(ElementType!(Reader)==dchar) ) 123 { 125 { 124 /// Range primitive 126 /// Range primitive 125 bool empty() /*@property*/ 127 bool empty() /*@property*/ 126 { 128 { 127 return current is null; 129 return current is null; 128 } 130 } 129 131 ................................................................................................................................................................................ 149 private: // implementation 151 private: // implementation 150 152 151 Reader reader; 153 Reader reader; 152 Token current; 154 Token current; 153 155 154 invariant() 156 invariant() 155 { 157 { 156 assert( reader.empty || !std.ctype.isspace(reader.front) ); | 158 assert( reader.empty || !isSpace(reader.front) ); 157 } 159 } 158 160 159 this( Reader reader, Token current = null ) 161 this( Reader reader, Token current = null ) 160 { 162 { 161 this.reader = reader; 163 this.reader = reader; 162 readWhile!isSpace(); 164 readWhile!isSpace(); 163 this.current = (current is null ? readNext() : current); 165 this.current = (current is null ? readNext() : current); 164 } 166 } 165 167 166 public static { | 168 public static > 169 { 167 bool isSpace (dchar c) { return std.ctype.isspace(c)!=0; } 170 bool isSpace (dchar c) { return std.ctype.isspace(c)!=0; } 168 bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.cty 171 bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.cty 169 bool isSSymbol (dchar c) { return "()[]{};@".canFind(c); } 172 bool isSSymbol (dchar c) { return "()[]{};@".canFind(c); } 170 bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) & 173 bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) & 171 bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } 174 bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } 172 } 175 } 173 176 ................................................................................................................................................................................ 374 assert( lex.empty ); 377 assert( lex.empty ); 375 assert_eq( lexerFromString(`-@`).front.str, "-" ); 378 assert_eq( lexerFromString(`-@`).front.str, "-" ); 376 } 379 } 377 380 378 /// Forward range for reader character by character, 381 /// Forward range for reader character by character, 379 /// keeping track of position information and caring \r\n -> \n conversion. 382 /// keeping track of position information and caring \r\n -> \n conversion. 380 383 381 private < 382 struct PositionedReader(CharSeq) 384 struct PositionedReader(CharSeq) 383 if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq) == dchar) ) | 385 if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq)==dchar) ) 384 { 386 { 385 CharSeq buffer; 387 CharSeq buffer; 386 string filename; 388 string filename; 387 int lineno; 389 int lineno; 388 int column; 390 int column; 389 391 390 /// Range primitive 392 /// Range primitive
Modified tricks/tricks.d from [d70e48b147acc242] to [c96de2738d81e418].
4 * 4 * 5 * Common tricks and utilities for programming in D. 5 * Common tricks and utilities for programming in D. 6 */ 6 */ 7 module tricks.tricks; 7 module tricks.tricks; 8 import tricks.test; 8 import tricks.test; 9 import std.array : appender; 9 import std.array : appender; 10 import std.format : formattedWrite; 10 import std.format : formattedWrite; 11 import core.exception : AssertError; | 11 import core.exception; > 12 import std.traits; > 13 import std.typetuple; 12 14 13 /// Simple Wrapper for std.format.doFormat 15 /// Simple Wrapper for std.format.doFormat 14 16 15 string sprintf(string fmt, T...)(T params) 17 string sprintf(string fmt, T...)(T params) 16 { 18 { 17 auto writer = appender!string(); 19 auto writer = appender!string(); 18 formattedWrite(writer, fmt, params); 20 formattedWrite(writer, fmt, params); ................................................................................................................................................................................ 204 /*mixin*/ 206 /*mixin*/ 205 template SimpleClass() 207 template SimpleClass() 206 { 208 { 207 mixin SimpleConstructor; 209 mixin SimpleConstructor; 208 mixin SimpleCompare; 210 mixin SimpleCompare; 209 mixin SimpleToString; 211 mixin SimpleToString; 210 } 212 } > 213 > 214 /// Simple PatternMatcher > 215 > 216 /*mixin*/ > 217 template SimplePatternMatch() > 218 { > 219 SPM_Return!(PP) match(string fn=__FILE__, size_t ln=__LINE__, PP...)(PP > 220 { > 221 foreach(i,_; pts) > 222 { > 223 alias pts[i] pt; // bug? pts[i]-->pt do not work > 224 static if(__traits(compiles, SPM_isMatchTag(pt))) > 225 { > 226 if( auto v = cast(pt.dynamicType)this ) > 227 return pt(v.tupleof); > 228 } > 229 else > 230 static if(__traits(compiles, SPM_isMatchAny(pt))) > 231 { > 232 return pt(); > 233 } > 234 else > 235 { > 236 if( auto v = cast(SPM_PTT!(pt)[0])this ) > 237 return pt(v); > 238 } > 239 } > 240 SPM_throwAssertError(fn, ln, "pattern matching failure"); > 241 assert(false); > 242 } > 243 } > 244 > 245 /// Pattern case clause > 246 > 247 SPM_MatchTag!(T, fn) when(T, alias fn)() > 248 { > 249 SPM_MatchTag!(T, fn) m; > 250 return m; > 251 } > 252 > 253 /// Pattern case clause > 254 > 255 SPM_MatchAny!(fn) otherwise(alias fn)() > 256 { > 257 SPM_MatchAny!(fn) m; > 258 return m; > 259 } > 260 > 261 // implementation detail of SimplePatternMatch > 262 > 263 void SPM_throwAssertError(T...)(T t) { core.exception.onAssertErrorMsg(t); } > 264 > 265 struct SPM_MatchTag(T, alias fn) > 266 { > 267 alias T dynamicType; > 268 auto opCall(typeof(T.tupleof) s) { return fn(s); } > 269 } > 270 > 271 struct SPM_MatchAny(alias fn) > 272 { > 273 auto opCall() { return fn(); } > 274 } > 275 > 276 template SPM_PTT(alias p) > 277 { > 278 alias ParameterTypeTuple!(p) SPM_PTT; > 279 } > 280 > 281 template SPM_Each(P) > 282 { > 283 static if(__traits(compiles, SPM_isMatchTag(P.init))) > 284 alias typeof(P(P.dynamicType.tupleof)) SPM_Each; > 285 else > 286 static if(__traits(compiles, SPM_isMatchAny(P.init))) > 287 alias typeof(P()) SPM_Each; > 288 else > 289 alias ReturnType!(P) SPM_Each; > 290 } > 291 > 292 template SPM_aVoid(T:void, TS...) { alias SPM_aVoid!(TS) SPM_aVoid; } > 293 template SPM_aVoid(T, TS...) { alias TypeTuple!(T,SPM_aVoid!(TS)) SPM_aVoid; } > 294 template SPM_aVoid() { alias TypeTuple!() SPM_aVoid; } > 295 > 296 template SPM_Return(PP...) > 297 { > 298 alias CommonType!(SPM_aVoid!(staticMap!(SPM_Each, PP))) SPM_Return; > 299 } > 300 > 301 void SPM_isMatchTag(T,alias fn)(SPM_MatchTag!(T,fn)){} > 302 void SPM_isMatchAny(alias fn)(SPM_MatchAny!(fn)){} > 303 > 304 unittest > 305 { > 306 static abstract class Base { > 307 mixin SimplePatternMatch; > 308 } > 309 class D1 : Base { > 310 int x; > 311 real y; > 312 mixin SimpleConstructor; > 313 } > 314 class D2 : Base { > 315 string s; > 316 mixin SimpleConstructor; > 317 } > 318 class D3 : Base { > 319 int[int]m; > 320 mixin SimpleConstructor; > 321 } > 322 > 323 Base d1 = new D1(1, 2.3); > 324 Base d2 = new D2("foobar"); > 325 Base d3 = new D3(null); (cast(D3)d3).m[1]=10; > 326 > 327 // normal dispatch > 328 assert_eq( d1.match( > 329 (D1 x){return 1;}, > 330 (D2 x){return 2;}, > 331 ), 1); > 332 assert_eq( d2.match( > 333 (D1 x){return 1;}, > 334 (D2 x){return 2;}, > 335 ), 2); > 336 assert_throw!AssertError( d3.match( > 337 (D1 x){return 1;}, > 338 (D2 x){return 2;}, > 339 )); > 340 assert_eq( d3.match( > 341 (D1 x){return 1;}, > 342 (D2 x){return 2;}, > 343 (Base x){return 3;}, > 344 ), 3); > 345 assert_eq( d2.match( > 346 (D1 x){return 1;}, > 347 (D2 x){return 2;}, > 348 (Base x){return 3;}, > 349 ), 2); > 350 assert_eq( d2.match( > 351 (D1 x){return 1;}, > 352 (Base x){return 3;}, > 353 (D2 x){return 2;}, > 354 ), 3); > 355 > 356 // member decomposing match > 357 assert_eq( d1.match( > 358 when!(D1, (x, y){return x + cast(int)y;}), > 359 when!(D2, (x){return x.length;}), > 360 when!(D3, (x){return x[1];}), > 361 ), 3); > 362 assert_eq( d2.match( > 363 when!(D1, (x, y){return x + cast(int)y;}), > 364 when!(D2, (x){return x.length;}), > 365 when!(D3, (x){return x[1];}), > 366 ), 6); > 367 assert_eq( d3.match( > 368 when!(D1, (x, y){return x + cast(int)y;}), > 369 when!(D2, (x){return x.length;}), > 370 when!(D3, (x){return x[1];}), > 371 ), 10); > 372 assert_throw!AssertError( d3.match( > 373 when!(D1, (x, y){return x + cast(int)y;}), > 374 when!(D2, (x){return x.length;}), > 375 )); > 376 assert_eq( d2.match( > 377 when!(D1, (x, y){return x + cast(int)y;}), > 378 when!(D2, (x){return x.length;}), > 379 otherwise!({return 999;}), > 380 ), 6); > 381 assert_eq( d2.match( > 382 when!(D1, (x, y){return x + cast(int)y;}), > 383 otherwise!({return 999;}), > 384 when!(D2, (x){return x.length;}), > 385 ), 999); > 386 }