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 9 import polemy.lex; 10 10 11 11 /// 12 12 abstract class AST 13 13 { 14 14 immutable LexPosition pos; 15 15 mixin SimpleConstructor; 16 + mixin SimplePatternMatch; 16 17 } 17 18 18 19 /// 19 20 class StrLiteral : AST 20 21 { 21 22 string data; 22 23 mixin SimpleClass;
Modified polemy/eval.d from [9d70fd9339035713] to [a16d8d322739557e].
105 105 Table ctx = createGlobalContext(); 106 106 return typeof(return)(eval(e, ctx, false, "@v"), ctx); 107 107 } 108 108 109 109 /// Entry point of this module 110 110 /// If splitCtx = true, then inner variable declaration do not overwrite ctx. 111 111 /// lay is the layer ID for evaluation (standard value semantics uses "@v"). 112 - 113 -Value eval(AST _e, Table ctx, bool splitCtx, Layer lay) 112 +import std.typetuple; 113 +Value eval(AST e, Table ctx, bool splitCtx, Layer lay) 114 114 { 115 - if( auto e = cast(StrLiteral)_e ) 116 - { 117 - return new StrValue(e.data); 118 - } 119 - else 120 - if( auto e = cast(IntLiteral)_e ) 121 - { 122 - return new IntValue(e.data); 123 - } 124 - else 125 - if( auto e = cast(VarExpression)_e ) 126 - { 127 - return ctx.get(e.var, lay, e.pos); 128 - } 129 - else 130 - if( auto e = cast(LayeredExpression)_e ) 131 - { 132 - return eval(e.expr, ctx, false, e.lay); 133 - } 134 - else 135 - if( auto e = cast(LetExpression)_e ) 136 - { 137 - // for letrec, we need this, but should avoid overwriting???? 138 - // ctx.set(e.var, "@v", new UndefinedValue, e.pos); 139 - Value v = eval(e.init, ctx, true, lay); 140 - if(splitCtx) 141 - ctx = new Table(ctx, Table.Kind.NotPropagateSet); 142 - ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); 143 - return eval(e.expr, ctx, false, lay); 144 - } 145 - else 146 - if( auto e = cast(FuncallExpression)_e ) 147 - { 148 - Value _f = eval(e.fun, ctx, true, lay); 149 - if( auto f = cast(FunValue)_f ) { 150 - Value[] args; 151 - foreach(a; e.args) 152 - args ~= eval(a, ctx, true, lay); 153 - return f.call(e.pos, lay, args); 154 - } else 115 + return e.match( 116 + (StrLiteral e) 117 + { 118 + return new StrValue(e.data); 119 + }, 120 + (IntLiteral e) 121 + { 122 + return new IntValue(e.data); 123 + }, 124 + (VarExpression e) 125 + { 126 + return ctx.get(e.var, lay, e.pos); 127 + }, 128 + (LayeredExpression e) 129 + { 130 + return eval(e.expr, ctx, false, e.lay); 131 + }, 132 + (LetExpression e) 133 + { 134 + // for letrec, we need this, but should avoid overwriting???? 135 + // ctx.set(e.var, "@v", new UndefinedValue, e.pos); 136 + Value v = eval(e.init, ctx, true, lay); 137 + if(splitCtx) 138 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 139 + ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); 140 + return eval(e.expr, ctx, false, lay); 141 + }, 142 + (FuncallExpression e) 143 + { 144 + Value _f = eval(e.fun, ctx, true, lay); 145 + if( auto f = cast(FunValue)_f ) { 146 + Value[] args; 147 + foreach(a; e.args) 148 + args ~= eval(a, ctx, true, lay); 149 + return f.call(e.pos, lay, args); 150 + } 155 151 throw genex!RuntimeException(e.pos, "Non-funcion is applied"); 156 - } 157 - else 158 - if( auto e = cast(FunLiteral)_e ) 159 - { 160 - return new FunValue(delegate Value(immutable LexPosition pos, string lay, Value[] args){ 161 - if( e.params.length != args.length ) 162 - throw genex!RuntimeException(e.pos, sprintf!"Argument Number Mismatch (%d required but %d given)" 163 - (e.params.length, args.length)); 164 - Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet); 165 - foreach(i,p; e.params) 166 - ctxNeo.set(p.name, lay, args[i]); 167 - return eval(e.funbody, ctxNeo, true, lay); 168 - }); 169 - } 170 - throw genex!RuntimeException(_e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(_e))); 152 + }, 153 + (FunLiteral e) 154 + { 155 + return new FunValue(delegate Value(immutable LexPosition pos, string lay, Value[] args){ 156 + if( e.params.length != args.length ) 157 + throw genex!RuntimeException(e.pos, sprintf!"Argument Number Mismatch (%d required but %d given)" 158 + (e.params.length, args.length)); 159 + Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet); 160 + foreach(i,p; e.params) 161 + ctxNeo.set(p.name, lay, args[i]); 162 + return eval(e.funbody, ctxNeo, true, lay); 163 + }); 164 + }, 165 + delegate Value (AST e) 166 + { 167 + throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); 168 + } 169 + ); 171 170 } 172 171 173 172 unittest 174 173 { 175 174 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); 176 175 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 177 176 assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21)) );
Modified polemy/lex.d from [4e484112cd314d8d] to [a4ea515a0f014c9c].
13 13 template ExceptionWithPosition() 14 14 { 15 15 const LexPosition pos; 16 16 this( const LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null ) 17 17 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos = pos; } 18 18 } 19 19 20 -/// 20 +/// Thrown when encountered an EOF in the middle of a lexical token 21 + 21 22 class UnexpectedEOF : Exception 22 23 { 23 24 mixin ExceptionWithPosition; 24 25 } 25 26 26 -/// 27 +/// Thrown when encountered a lexical error 28 + 27 29 class LexException : Exception 28 30 { 29 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 36 class LexPosition 35 37 { 36 38 immutable string filename; /// name of the source file 37 39 immutable int lineno; /// 1-origin 38 40 immutable int column; /// 1-origin 39 41 ................................................................................ 93 95 assert( !__traits(compiles, t.pos=p) ); 94 96 assert( !__traits(compiles, t.str=789) ); 95 97 assert( !__traits(compiles, t.quoted=true) ); 96 98 } 97 99 98 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 109 LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzilla:2581 */ 108 110 lexerFromString(CharSeq)( CharSeq str, string filename="<unnamed>", int lineno=1, int column=1 ) 109 111 { 110 112 return new LexerT!(PositionedReader!CharSeq)( 111 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 Tokens) 117 +/// Standard Lexer Type (all you have to know is that this is a forward range of Tokens!) 116 118 117 119 alias LexerT!(PositionedReader!string) Lexer; 118 120 119 121 /// Lexer Implementation 120 122 121 123 class LexerT(Reader) 122 - if( isForwardRange!(Reader) && is(ElementType!(Reader) == dchar) ) 124 + if( isForwardRange!(Reader) && is(ElementType!(Reader)==dchar) ) 123 125 { 124 126 /// Range primitive 125 127 bool empty() /*@property*/ 126 128 { 127 129 return current is null; 128 130 } 129 131 ................................................................................ 149 151 private: // implementation 150 152 151 153 Reader reader; 152 154 Token current; 153 155 154 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 161 this( Reader reader, Token current = null ) 160 162 { 161 163 this.reader = reader; 162 164 readWhile!isSpace(); 163 165 this.current = (current is null ? readNext() : current); 164 166 } 165 167 166 - public static { 168 + public static 169 + { 167 170 bool isSpace (dchar c) { return std.ctype.isspace(c)!=0; } 168 171 bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.ctype.isalnum(c) && c!='_' && c!='\''; } 169 172 bool isSSymbol (dchar c) { return "()[]{};@".canFind(c); } 170 173 bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) && c!='"' && c!='#'; } 171 174 bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } 172 175 } 173 176 ................................................................................ 374 377 assert( lex.empty ); 375 378 assert_eq( lexerFromString(`-@`).front.str, "-" ); 376 379 } 377 380 378 381 /// Forward range for reader character by character, 379 382 /// keeping track of position information and caring \r\n -> \n conversion. 380 383 381 -private 382 384 struct PositionedReader(CharSeq) 383 - if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq) == dchar) ) 385 + if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq)==dchar) ) 384 386 { 385 387 CharSeq buffer; 386 388 string filename; 387 389 int lineno; 388 390 int column; 389 391 390 392 /// Range primitive
Modified tricks/tricks.d from [d70e48b147acc242] to [c96de2738d81e418].
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 9 import std.array : appender; 10 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 15 /// Simple Wrapper for std.format.doFormat 14 16 15 17 string sprintf(string fmt, T...)(T params) 16 18 { 17 19 auto writer = appender!string(); 18 20 formattedWrite(writer, fmt, params); ................................................................................ 204 206 /*mixin*/ 205 207 template SimpleClass() 206 208 { 207 209 mixin SimpleConstructor; 208 210 mixin SimpleCompare; 209 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 pts) 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 +}