Differences From Artifact [2e1caca9f119fc4c]:
- File
polemy/parse.d
- 2010-11-21 11:11:49 - part of checkin [2bdfb8a182] on branch trunk - moved build sciprt for documents into Poseidon environment (user: kinaba) [annotate]
To Artifact [789e91a27a62e096]:
- File
polemy/parse.d
- 2010-11-21 14:24:33 - part of checkin [3995a5eb6a] on branch trunk - added iikagen pattern match (user: kinaba) [annotate]
6 */ 6 */
7 module polemy.parse; 7 module polemy.parse;
8 import polemy._common; 8 import polemy._common;
9 import polemy.failure; 9 import polemy.failure;
10 import polemy.lex; 10 import polemy.lex;
11 import polemy.ast; 11 import polemy.ast;
12 import polemy.layer; 12 import polemy.layer;
> 13 import polemy.fresh;
13 14
14 /// Parse a string and return its AST 15 /// Parse a string and return its AST
15 16
16 AST parseString(S, T...)(S str, T fn_ln_cn) 17 AST parseString(S, T...)(S str, T fn_ln_cn)
17 { 18 {
18 return parserFromString(str, fn_ln_cn).parse(); 19 return parserFromString(str, fn_ln_cn).parse();
19 } 20 }
................................................................................................................................................................................
100 auto e = tryEat("(") 101 auto e = tryEat("(")
101 ? parseLambdaAfterOpenParen(pos) // let var ( . 102 ? parseLambdaAfterOpenParen(pos) // let var ( .
102 : (eat("=", "after "~kwd), E(0)); // let var = . 103 : (eat("=", "after "~kwd), E(0)); // let var = .
103 if( moreDeclarationExists() ) 104 if( moreDeclarationExists() )
104 return new LetExpression(pos, var, SystemLayer, 105 return new LetExpression(pos, var, SystemLayer,
105 else 106 else
106 return new LetExpression(pos, var, SystemLayer, 107 return new LetExpression(pos, var, SystemLayer,
107 new LayeredExpression(pos, SystemLayer, | 108 new LayExpression(pos, SystemLayer, new
108 ); 109 );
109 } 110 }
110 else 111 else
111 { 112 {
112 string kwd = layer; 113 string kwd = layer;
113 if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="va 114 if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="va
114 return null; // none of {@lay, let, var, def} oc 115 return null; // none of {@lay, let, var, def} oc
................................................................................................................................................................................
141 private bool moreDeclarationExists() 142 private bool moreDeclarationExists()
142 { 143 {
143 return (tryEat(";") || tryEat("in")) && !closingBracket(); 144 return (tryEat(";") || tryEat("in")) && !closingBracket();
144 } 145 }
145 146
146 private bool closingBracket() 147 private bool closingBracket()
147 { 148 {
148 return lex.empty || !lex.front.quoted && ["}",")","]"].canFind(l | 149 return lex.empty || !lex.front.quoted && ["}",")","]",","].canFi
149 } 150 }
150 151
151 // [TODO] make this customizable from program 152 // [TODO] make this customizable from program
152 private static string[][] operator_perferences = [ 153 private static string[][] operator_perferences = [
153 ["||"], 154 ["||"],
154 ["&&"], 155 ["&&"],
155 ["!="], 156 ["!="],
................................................................................................................................................................................
262 } 263 }
263 if( tryEat("@") ) 264 if( tryEat("@") )
264 { 265 {
265 auto lay = "@"~eatId("for layer ID"); 266 auto lay = "@"~eatId("for layer ID");
266 eat("(", "for layered execution"); 267 eat("(", "for layered execution");
267 auto e = Body(); 268 auto e = Body();
268 eat(")", "after "~lay~"(..."); 269 eat(")", "after "~lay~"(...");
269 return new LayeredExpression(pos, lay, e); | 270 return new LayExpression(pos, lay, e);
270 } 271 }
271 if( tryEat("(") ) 272 if( tryEat("(") )
272 { 273 {
273 auto e = Body(); 274 auto e = Body();
274 eat(")", "after parenthesized expression"); 275 eat(")", "after parenthesized expression");
275 return e; 276 return e;
276 } 277 }
................................................................................................................................................................................
298 return new FuncallExpression(pos, 299 return new FuncallExpression(pos,
299 new VarExpression(pos, "if"), 300 new VarExpression(pos, "if"),
300 cond, 301 cond,
301 new FunLiteral(thenPos, [], th), 302 new FunLiteral(thenPos, [], th),
302 new FunLiteral(elsePos, [], el) 303 new FunLiteral(elsePos, [], el)
303 ); 304 );
304 } 305 }
> 306 if( tryEat("case") )
> 307 {
> 308 return parsePatternMatch(pos);
> 309 }
305 if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! 310 if( tryEat("fun") || tryEat("\u03BB") ) // lambda!!
306 { 311 {
307 eat("(", "after fun"); 312 eat("(", "after fun");
308 return parseLambdaAfterOpenParen(pos); 313 return parseLambdaAfterOpenParen(pos);
309 } 314 }
310 scope(exit) lex.popFront; 315 scope(exit) lex.popFront;
311 return new VarExpression(pos, lex.front.str); 316 return new VarExpression(pos, lex.front.str);
312 } 317 }
> 318
> 319 AST parsePatternMatch(LexPosition pos)
> 320 {
> 321 // case( pmExpr )cases
> 322 //==>
> 323 // let pmVar = pmExpr in (... let pmTryFirst = ... in pmTryFir
> 324 eat("(", "after case");
> 325 AST pmExpr = E(0);
> 326 eat(")", "after case");
> 327 string pmVar = freshVarName();
> 328 string pmTryFirst = freshVarName();
> 329 AST pmBody = parsePatternMatchCases(pmVar, pmTryFirst,
> 330 new FuncallExpression(pos, new VarExpression(pos, pmTryF
> 331 return new LetExpression(pos, pmVar, [], pmExpr, pmBody);
> 332 }
> 333
> 334 AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST th
> 335 {
> 336 // when( pat ) { cBody }
> 337 //==>
> 338 // ... let failBranchVar = ... in
> 339 // let tryThisBranchVar = fun(){ if(test){cBody}else{failBran
> 340 if( tryEat("when") )
> 341 {
> 342 auto pos = currentPosition();
> 343 string failBranchVar = freshVarName();
> 344
> 345 eat("(", "after when");
> 346 auto pr = parsePattern();
> 347 eat(")", "after when");
> 348 eat("{", "after pattern");
> 349 AST cBody = Body();
> 350 AST judgement = new FuncallExpression(pos, new VarExpres
> 351 ppTest(pmVar, pr), new FunLiteral(pos,[],ppBind(
> 352 new VarExpression(pos, failBranchVar));
> 353 eat("}", "after pattern clause");
> 354 return parsePatternMatchCases(pmVar, failBranchVar,
> 355 new LetExpression(pos, tryThisBranchVar, [],
> 356 new FunLiteral(pos,[],judgement), thenDo
> 357 );
> 358 }
> 359 else
> 360 {
> 361 auto pos = currentPosition();
> 362 AST doNothing = new FunLiteral(pos,[],
> 363 new StrLiteral(pos, sprintf!"(pattern match fail
> 364 return new LetExpression(currentPosition(), tryThisBranc
> 365 }
> 366 }
> 367
> 368 // hageshiku tenuki
> 369 abstract class SinglePattern
> 370 {
> 371 string[] path;
> 372 mixin SimpleClass;
> 373 private AST access(string pmVar, string[] path) {
> 374 auto pos = currentPosition();
> 375 AST e = new VarExpression(pos, pmVar);
> 376 foreach(p; path)
> 377 e = new FuncallExpression(pos, new VarExpression
> 378 return e;
> 379 }
> 380 private AST has(AST e, string k) {
> 381 auto pos = currentPosition();
> 382 return opAndAnd(
> 383 new FuncallExpression(pos, new VarExpression(pos
> 384 new FuncallExpression(pos, new VarExpression(pos
> 385 );
> 386 }
> 387 private AST opAndAnd(AST a, AST b) {
> 388 if( a is null ) return b;
> 389 if( b is null ) return a;
> 390 auto pos = currentPosition();
> 391 return new FuncallExpression(pos,
> 392 new VarExpression(pos, "if"),
> 393 a,
> 394 new FunLiteral(pos, [], b),
> 395 new FunLiteral(pos, [], new IntLiteral(pos, 0))
> 396 );
> 397 }
> 398 AST ppTest(string pmVar) {
> 399 AST c = null;
> 400 for(int i=0; i<path.length; ++i)
> 401 c = opAndAnd(c, has(access(pmVar,path[0..i]), pa
> 402 return c;
> 403 }
> 404 AST ppBind(string pmVar, AST thenDoThis) { return thenDoThis; }
> 405 }
> 406 class WildPattern : SinglePattern
> 407 {
> 408 mixin SimpleClass;
> 409 }
> 410 class VarPattern : SinglePattern
> 411 {
> 412 string name;
> 413 mixin SimpleClass;
> 414 AST ppBind(string pmVar, AST thenDoThis) {
> 415 auto pos = currentPosition();
> 416 return new LetExpression(pos, name, [], access(pmVar,pat
> 417 }
> 418 }
> 419 class ConstantPattern : SinglePattern
> 420 {
> 421 AST e;
> 422 mixin SimpleClass;
> 423 AST ppTest(string pmVar) {
> 424 auto pos = currentPosition();
> 425 return opAndAnd( super.ppTest(pmVar),
> 426 new FuncallExpression(pos, new VarExpression(pos
> 427 );
> 428 }
> 429 }
> 430
> 431 SinglePattern[] parsePattern(string[] path = null)
> 432 {
> 433 SinglePattern[] result;
> 434 if( tryEat("{") )
> 435 {
> 436 if( !tryEat("}") ) {
> 437 do {
> 438 string key = eatId("in table pattern");
> 439 eat(":", "after field-id in table patter
> 440 result ~= parsePattern(path ~ key);
> 441 } while( tryEat(",") );
> 442 eat("}", "at the end of table pattern");
> 443 }
> 444 }
> 445 else
> 446 {
> 447 AST e = E(0);
> 448 if(auto ev = cast(VarExpression)e)
> 449 if(ev.name == "_")
> 450 result ~= new WildPattern(path);
> 451 else
> 452 result ~= new VarPattern(path, ev.name);
> 453 else
> 454 result ~= new ConstantPattern(path, e);
> 455 }
> 456 return result;
> 457 }
> 458
> 459 AST ppTest(string pmVar, SinglePattern[] pats)
> 460 {
> 461 auto pos = currentPosition();
> 462 AST cond = null;
> 463 foreach(p; pats) {
> 464 AST c2 = p.ppTest(pmVar);
> 465 if( c2 !is null )
> 466 cond = cond is null ? c2
> 467 : new FuncallExpression(pos, new VarExpressi
> 468 }
> 469 return cond is null ? new IntLiteral(currentPosition(), 1) : con
> 470 }
> 471
> 472 AST ppBind(string pmVar, SinglePattern[] pats, AST thenDoThis)
> 473 {
> 474 foreach(p; pats)
> 475 thenDoThis = p.ppBind(pmVar, thenDoThis);
> 476 return thenDoThis;
> 477 }
313 478
314 AST parseId() 479 AST parseId()
315 { 480 {
316 scope(exit) lex.popFront; 481 scope(exit) lex.popFront;
317 return new StrLiteral(currentPosition(), lex.front.str); 482 return new StrLiteral(currentPosition(), lex.front.str);
318 } 483 }
319 484
................................................................................................................................................................................
481 assert_eq(parseString(`{}`), call(var("{}"))); 646 assert_eq(parseString(`{}`), call(var("{}")));
482 assert_eq(parseString(`{foo:1,"bar":2}`), 647 assert_eq(parseString(`{foo:1,"bar":2}`),
483 call(var(".="), call(var(".="), call(var("{}")), strl("foo"), in 648 call(var(".="), call(var(".="), call(var("{}")), strl("foo"), in
484 assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo 649 assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo
485 assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("f 650 assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("f
486 assert_eq(parseString(`x{y:1}`), call(var(".="),var("x"),strl("y"),intl( 651 assert_eq(parseString(`x{y:1}`), call(var(".="),var("x"),strl("y"),intl(
487 } 652 }
> 653
> 654 unittest
> 655 {
> 656 assert_nothrow(parseString(`
> 657 case( 1 )
> 658 when(x){1}
> 659 `));
> 660 assert_nothrow(parseString(`
> 661 case( 1 )
> 662 when({aaaa:_}){1}
> 663 `));
> 664 }