Diff
Not logged in

Differences From Artifact [2e1caca9f119fc4c]:

To Artifact [789e91a27a62e096]:


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 12 import polemy.layer; 13 +import polemy.fresh; 13 14 14 15 /// Parse a string and return its AST 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(); 19 20 } ................................................................................ 100 101 auto e = tryEat("(") 101 102 ? parseLambdaAfterOpenParen(pos) // let var ( ... 102 103 : (eat("=", "after "~kwd), E(0)); // let var = ... 103 104 if( moreDeclarationExists() ) 104 105 return new LetExpression(pos, var, SystemLayer, e, Body()); 105 106 else 106 107 return new LetExpression(pos, var, SystemLayer, e, 107 - new LayeredExpression(pos, SystemLayer, new VarExpression(pos, var)) 108 + new LayExpression(pos, SystemLayer, new VarExpression(pos, var)) 108 109 ); 109 110 } 110 111 else 111 112 { 112 113 string kwd = layer; 113 114 if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) 114 115 return null; // none of {@lay, let, var, def} occurred, it's not a declaration ................................................................................ 141 142 private bool moreDeclarationExists() 142 143 { 143 144 return (tryEat(";") || tryEat("in")) && !closingBracket(); 144 145 } 145 146 146 147 private bool closingBracket() 147 148 { 148 - return lex.empty || !lex.front.quoted && ["}",")","]"].canFind(lex.front.str); 149 + return lex.empty || !lex.front.quoted && ["}",")","]",","].canFind(lex.front.str); 149 150 } 150 151 151 152 // [TODO] make this customizable from program 152 153 private static string[][] operator_perferences = [ 153 154 ["||"], 154 155 ["&&"], 155 156 ["!="], ................................................................................ 262 263 } 263 264 if( tryEat("@") ) 264 265 { 265 266 auto lay = "@"~eatId("for layer ID"); 266 267 eat("(", "for layered execution"); 267 268 auto e = Body(); 268 269 eat(")", "after "~lay~"(..."); 269 - return new LayeredExpression(pos, lay, e); 270 + return new LayExpression(pos, lay, e); 270 271 } 271 272 if( tryEat("(") ) 272 273 { 273 274 auto e = Body(); 274 275 eat(")", "after parenthesized expression"); 275 276 return e; 276 277 } ................................................................................ 298 299 return new FuncallExpression(pos, 299 300 new VarExpression(pos, "if"), 300 301 cond, 301 302 new FunLiteral(thenPos, [], th), 302 303 new FunLiteral(elsePos, [], el) 303 304 ); 304 305 } 306 + if( tryEat("case") ) 307 + { 308 + return parsePatternMatch(pos); 309 + } 305 310 if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! 306 311 { 307 312 eat("(", "after fun"); 308 313 return parseLambdaAfterOpenParen(pos); 309 314 } 310 315 scope(exit) lex.popFront; 311 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 pmTryFirst()) 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, pmTryFirst))); 331 + return new LetExpression(pos, pmVar, [], pmExpr, pmBody); 332 + } 333 + 334 + AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST thenDoThis) 335 + { 336 + // when( pat ) { cBody } 337 + //==> 338 + // ... let failBranchVar = ... in 339 + // let tryThisBranchVar = fun(){ if(test){cBody}else{failBranchVar()} } in thenDoThis 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 VarExpression(pos, "if"), 351 + ppTest(pmVar, pr), new FunLiteral(pos,[],ppBind(pmVar, pr, cBody)), 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), thenDoThis) 357 + ); 358 + } 359 + else 360 + { 361 + auto pos = currentPosition(); 362 + AST doNothing = new FunLiteral(pos,[], 363 + new StrLiteral(pos, sprintf!"(pattern match failure:%s)"(pos))); 364 + return new LetExpression(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis); 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(pos, "."), e, new StrLiteral(pos, p)); 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, "_istable"), e), 384 + new FuncallExpression(pos, new VarExpression(pos, ".?"), e, new StrLiteral(pos, k)) 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]), path[i])); 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,path), thenDoThis); 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,"=="), access(pmVar,path), e) 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 pattern"); 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 VarExpression(pos,"&&"), cond, c2); 468 + } 469 + return cond is null ? new IntLiteral(currentPosition(), 1) : cond; 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 479 AST parseId() 315 480 { 316 481 scope(exit) lex.popFront; 317 482 return new StrLiteral(currentPosition(), lex.front.str); 318 483 } 319 484 ................................................................................ 481 646 assert_eq(parseString(`{}`), call(var("{}"))); 482 647 assert_eq(parseString(`{foo:1,"bar":2}`), 483 648 call(var(".="), call(var(".="), call(var("{}")), strl("foo"), intl(1)), strl("bar"), intl(2))); 484 649 assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo"))); 485 650 assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("foo"))); 486 651 assert_eq(parseString(`x{y:1}`), call(var(".="),var("x"),strl("y"),intl(1))); 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 +}