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 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 +}