Mercurial Hosting > luan
comparison src/luan/interp/LuaParser.java @ 17:09d41f7490a8
add local variables
git-svn-id: https://luan-java.googlecode.com/svn/trunk@18 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Fri, 30 Nov 2012 11:46:34 +0000 |
parents | 2a30281ef47c |
children | 3971113699b8 |
comparison
equal
deleted
inserted
replaced
16:2a30281ef47c | 17:09d41f7490a8 |
---|---|
11 import org.parboiled.Rule; | 11 import org.parboiled.Rule; |
12 import org.parboiled.parserunners.ReportingParseRunner; | 12 import org.parboiled.parserunners.ReportingParseRunner; |
13 import org.parboiled.support.ParsingResult; | 13 import org.parboiled.support.ParsingResult; |
14 import org.parboiled.support.Var; | 14 import org.parboiled.support.Var; |
15 import org.parboiled.support.StringVar; | 15 import org.parboiled.support.StringVar; |
16 import org.parboiled.support.StringBuilderVar; | |
16 import org.parboiled.support.ValueStack; | 17 import org.parboiled.support.ValueStack; |
17 import org.parboiled.errors.ErrorUtils; | 18 import org.parboiled.errors.ErrorUtils; |
18 import luan.Lua; | 19 import luan.Lua; |
19 import luan.LuaNumber; | 20 import luan.LuaNumber; |
20 import luan.LuaState; | 21 import luan.LuaState; |
21 | 22 |
22 | 23 |
23 public class LuaParser extends BaseParser<Object> { | 24 public class LuaParser extends BaseParser<Object> { |
24 int nEquals; | 25 int nEquals; |
25 int parens = 0; | 26 int parens = 0; |
27 List<String> symbols = new ArrayList<String>(); | |
28 int stackSize = 0; | |
26 | 29 |
27 boolean nEquals(int n) { | 30 boolean nEquals(int n) { |
28 nEquals = n; | 31 nEquals = n; |
29 return true; | 32 return true; |
30 } | 33 } |
35 } | 38 } |
36 | 39 |
37 boolean decParens() { | 40 boolean decParens() { |
38 parens--; | 41 parens--; |
39 return true; | 42 return true; |
43 } | |
44 | |
45 int index(String name) { | |
46 int i = symbols.size(); | |
47 while( --i >= 0 ) { | |
48 if( symbols.get(i).equals(name) ) | |
49 return i; | |
50 } | |
51 return -1; | |
40 } | 52 } |
41 | 53 |
42 public Rule Target() { | 54 public Rule Target() { |
43 return Sequence( | 55 return Sequence( |
44 Spaces(), | 56 Spaces(), |
49 ); | 61 ); |
50 } | 62 } |
51 | 63 |
52 Rule Chunk() { | 64 Rule Chunk() { |
53 return Sequence( | 65 return Sequence( |
54 push(new ArrayList<Stmt>()), | 66 Block(), |
55 Optional( Stmt() ), | 67 push( new Chunk( (Stmt)pop(), stackSize ) ) |
68 ); | |
69 } | |
70 | |
71 Rule Block() { | |
72 Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>()); | |
73 return Sequence( | |
74 push(0), // stackCount | |
75 Optional( Stmt(stmts) ), | |
56 ZeroOrMore( | 76 ZeroOrMore( |
57 StmtSep(), | 77 StmtSep(), |
58 Optional( Stmt() ) | 78 Optional( Stmt(stmts) ) |
59 ), | 79 ), |
60 push( newChunk() ) | 80 push( newBlock(stmts.get()) ) |
61 ); | 81 ); |
62 } | 82 } |
63 | 83 |
64 boolean addStmt() { | 84 Stmt newBlock(List<Stmt> stmts) { |
65 Stmt stmt = (Stmt)pop(); | 85 if( stackSize < symbols.size() ) |
66 @SuppressWarnings("unchecked") | 86 stackSize = symbols.size(); |
67 List<Stmt> stmts = (List<Stmt>)peek(); | 87 int stackN = (Integer)pop(); |
68 stmts.add(stmt); | 88 for( int i=0; i<stackN; i++ ) { |
69 return true; | 89 symbols.remove(symbols.size()-1); // pop |
70 } | 90 } |
71 | 91 if( stmts.isEmpty() ) |
72 Stmt newChunk() { | |
73 @SuppressWarnings("unchecked") | |
74 List<Stmt> stmts = (List<Stmt>)pop(); | |
75 switch( stmts.size() ) { | |
76 case 0: | |
77 return Stmt.EMPTY; | 92 return Stmt.EMPTY; |
78 case 1: | 93 if( stmts.size()==1 && stackN==0 ) |
79 return stmts.get(0); | 94 return stmts.get(0); |
80 default: | 95 return new Block( stmts.toArray(new Stmt[0]), symbols.size(), symbols.size()+stackN ); |
81 return new Block(stmts.toArray(new Stmt[0])); | |
82 } | |
83 } | 96 } |
84 | 97 |
85 Rule StmtSep() { | 98 Rule StmtSep() { |
86 return Sequence( | 99 return Sequence( |
87 FirstOf( | 100 FirstOf( |
97 | 110 |
98 Rule EndOfLine() { | 111 Rule EndOfLine() { |
99 return FirstOf("\r\n", '\r', '\n'); | 112 return FirstOf("\r\n", '\r', '\n'); |
100 } | 113 } |
101 | 114 |
102 Rule Stmt() { | 115 Rule Stmt(Var<List<Stmt>> stmts) { |
103 return Sequence( | 116 return FirstOf( |
104 FirstOf( | 117 LocalStmt(stmts), |
105 WhileStmt(), | 118 Sequence( |
106 RepeatStmt(), | 119 FirstOf( |
107 IfStmt(), | 120 DoStmt(), |
108 SetStmt(), | 121 WhileStmt(), |
109 ExpressionsStmt() | 122 RepeatStmt(), |
110 ), | 123 IfStmt(), |
111 addStmt() | 124 SetStmt(), |
112 ); | 125 ExpressionsStmt() |
126 ), | |
127 stmts.get().add( (Stmt)pop() ) | |
128 ) | |
129 ); | |
130 } | |
131 | |
132 Rule DoStmt() { | |
133 return Sequence( | |
134 Keyword("do"), Block(), Keyword("end") | |
135 ); | |
136 } | |
137 | |
138 Rule LocalStmt(Var<List<Stmt>> stmts) { | |
139 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>()); | |
140 return Sequence( | |
141 Keyword("local"), | |
142 Name(), | |
143 newName(names.get()), | |
144 ZeroOrMore( | |
145 ',', Spaces(), Name(), | |
146 newName(names.get()) | |
147 ), | |
148 Optional( | |
149 '=', Spaces(), | |
150 ExpList(), | |
151 stmts.get().add( newSetLocalStmt(names.get()) ) | |
152 ) | |
153 ); | |
154 } | |
155 | |
156 boolean newName(List<String> names) { | |
157 String name = (String)pop(); | |
158 names.add(name); | |
159 symbols.add(name); | |
160 push( ((Integer)pop()) + 1 ); | |
161 return true; | |
162 } | |
163 | |
164 SetStmt newSetLocalStmt(List<String> names) { | |
165 Expressions values = (Expressions)pop(); | |
166 SetLocalVar[] vars = new SetLocalVar[names.size()]; | |
167 for( int i=0; i<vars.length; i++ ) { | |
168 vars[i] = new SetLocalVar(index(names.get(i))); | |
169 } | |
170 return new SetStmt( vars, values ); | |
113 } | 171 } |
114 | 172 |
115 Rule WhileStmt() { | 173 Rule WhileStmt() { |
116 return Sequence( | 174 return Sequence( |
117 "while", Spaces(), Expr(), "do", Spaces(), Chunk(), "end", Spaces(), | 175 Keyword("while"), Expr(), Keyword("do"), Block(), Keyword("end"), |
118 push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) ) | 176 push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) ) |
119 ); | 177 ); |
120 } | 178 } |
121 | 179 |
122 Rule RepeatStmt() { | 180 Rule RepeatStmt() { |
123 return Sequence( | 181 return Sequence( |
124 "repeat", Spaces(), Chunk(), "until", Spaces(), Expr(), | 182 Keyword("repeat"), Block(), Keyword("until"), Expr(), |
125 push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) ) | 183 push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) ) |
126 ); | 184 ); |
127 } | 185 } |
128 | 186 |
129 Rule IfStmt() { | 187 Rule IfStmt() { |
130 Var<Integer> n = new Var<Integer>(1); | 188 Var<Integer> n = new Var<Integer>(1); |
131 return Sequence( | 189 return Sequence( |
132 "if", Spaces(), Expr(), "then", Spaces(), Chunk(), | 190 Keyword("if"), Expr(), Keyword("then"), Block(), |
133 push(Stmt.EMPTY), | 191 push(Stmt.EMPTY), |
134 ZeroOrMore( | 192 ZeroOrMore( |
135 "elseif", Spaces(), drop(), Expr(), "then", Spaces(), Chunk(), | 193 Keyword("elseif"), drop(), Expr(), Keyword("then"), Block(), |
136 push(Stmt.EMPTY), | 194 push(Stmt.EMPTY), |
137 n.set(n.get()+1) | 195 n.set(n.get()+1) |
138 ), | 196 ), |
139 Optional( | 197 Optional( |
140 "else", Spaces(), drop(), Chunk() | 198 Keyword("else"), drop(), Block() |
141 ), | 199 ), |
142 "end", Spaces(), | 200 Keyword("end"), |
143 buildIfStmt(n.get()) | 201 buildIfStmt(n.get()) |
144 ); | 202 ); |
145 } | 203 } |
146 | 204 |
147 boolean buildIfStmt(int n) { | 205 boolean buildIfStmt(int n) { |
171 } | 229 } |
172 | 230 |
173 SetStmt newSetStmt() { | 231 SetStmt newSetStmt() { |
174 Expressions values = (Expressions)pop(); | 232 Expressions values = (Expressions)pop(); |
175 @SuppressWarnings("unchecked") | 233 @SuppressWarnings("unchecked") |
176 List<SetStmt.Var> vars = (List<SetStmt.Var>)pop(); | 234 List<Settable> vars = (List<Settable>)pop(); |
177 return new SetStmt( vars.toArray(new SetStmt.Var[0]), values ); | 235 return new SetStmt( vars.toArray(new Settable[0]), values ); |
178 } | 236 } |
179 | 237 |
180 Rule VarList() { | 238 Rule VarList() { |
181 return Sequence( | 239 return Sequence( |
182 push(new ArrayList<SetStmt.Var>()), | 240 push(new ArrayList<Settable>()), |
183 Var(), | 241 Var(), |
184 addToVarList(), | 242 addToVarList(), |
185 ZeroOrMore( | 243 ZeroOrMore( |
186 ',', Spaces(), Var(), | 244 ',', Spaces(), Var(), |
187 addToVarList() | 245 addToVarList() |
188 ) | 246 ) |
189 ); | 247 ); |
190 } | 248 } |
191 | 249 |
192 boolean addToVarList() { | 250 boolean addToVarList() { |
193 Object obj = pop(); | 251 Object obj2 = pop(); |
194 if( obj==null ) | 252 if( obj2==null ) |
195 return false; | 253 return false; |
196 Expr key = expr(obj); | 254 Object obj1 = pop(); |
197 Expr table = expr(pop()); | |
198 @SuppressWarnings("unchecked") | 255 @SuppressWarnings("unchecked") |
199 List<SetStmt.Var> vars = (List<SetStmt.Var>)peek(); | 256 List<Settable> vars = (List<Settable>)peek(); |
200 vars.add( new SetStmt.Var(table,key) ); | 257 if( obj1==null ) { |
258 String name = (String)obj2; | |
259 int index = index(name); | |
260 if( index == -1 ) { | |
261 vars.add( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) ); | |
262 } else { | |
263 vars.add( new SetLocalVar(index) ); | |
264 } | |
265 } else { | |
266 Expr key = expr(obj2); | |
267 Expr table = expr(obj1); | |
268 vars.add( new SetTableEntry(table,key) ); | |
269 } | |
201 return true; | 270 return true; |
202 } | 271 } |
203 | 272 |
204 Rule Expr() { | 273 Rule Expr() { |
205 return OrExpr(); | 274 return OrExpr(); |
322 } | 391 } |
323 | 392 |
324 Rule Field() { | 393 Rule Field() { |
325 return FirstOf( | 394 return FirstOf( |
326 Sequence( | 395 Sequence( |
327 FirstOf( SubExpr(), Name() ), | 396 FirstOf( SubExpr(), NameExpr() ), |
328 '=', Spaces(), Expr(), | 397 '=', Spaces(), Expr(), |
329 addField() | 398 addField() |
330 ), | 399 ), |
331 Sequence( | 400 Sequence( |
332 Expr(), | 401 Expr(), |
374 '(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(), | 443 '(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(), |
375 push(expr(pop())), | 444 push(expr(pop())), |
376 push(null) // marker | 445 push(null) // marker |
377 ), | 446 ), |
378 Sequence( | 447 Sequence( |
379 push(EnvExpr.INSTANCE), | 448 push(null), // marker |
380 Name() | 449 Name() |
381 ) | 450 ) |
382 ), | 451 ), |
383 ZeroOrMore( | 452 ZeroOrMore( |
384 makeVarExp(), | 453 makeVarExp(), |
385 FirstOf( | 454 FirstOf( |
386 SubExpr(), | 455 SubExpr(), |
387 Sequence( '.', Spaces(), Name() ), | 456 Sequence( '.', Spaces(), NameExpr() ), |
388 Sequence( | 457 Sequence( |
389 Args(), | 458 Args(), |
390 push(null) // marker | 459 push(null) // marker |
391 ) | 460 ) |
392 ) | 461 ) |
393 ) | 462 ) |
394 ); | 463 ); |
395 } | 464 } |
396 | 465 |
397 boolean makeVarExp() { | 466 boolean makeVarExp() { |
398 Object obj = pop(); | 467 Object obj2 = pop(); |
399 if( obj==null ) | 468 if( obj2==null ) |
400 return true; | 469 return true; |
401 return push( new GetExpr( expr(pop()), expr(obj) ) ); | 470 Object obj1 = pop(); |
471 if( obj1==null ) { | |
472 String name = (String)obj2; | |
473 int index = index(name); | |
474 if( index == -1 ) { | |
475 return push( new GetExpr( EnvExpr.INSTANCE, new ConstExpr(name) ) ); | |
476 } else { | |
477 return push( new GetLocalVar(index) ); | |
478 } | |
479 } | |
480 return push( new GetExpr( expr(obj1), expr(obj2) ) ); | |
402 } | 481 } |
403 | 482 |
404 // function should be on top of the stack | 483 // function should be on top of the stack |
405 Rule Args() { | 484 Rule Args() { |
406 return Sequence( | 485 return Sequence( |
427 push( ExpList.emptyExpList ) | 506 push( ExpList.emptyExpList ) |
428 ); | 507 ); |
429 } | 508 } |
430 | 509 |
431 Rule ExpList() { | 510 Rule ExpList() { |
432 return Sequence( | 511 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder()); |
433 push(new ExpList.Builder()), | 512 return Sequence( |
434 Expr(), | 513 Expr(), |
435 addToExpList(), | 514 addToExpList(builder.get()), |
436 ZeroOrMore( | 515 ZeroOrMore( |
437 ',', Spaces(), Expr(), | 516 ',', Spaces(), Expr(), |
438 addToExpList() | 517 addToExpList(builder.get()) |
439 ), | 518 ), |
440 push( ((ExpList.Builder)pop()).build() ) | 519 push( builder.get().build() ) |
441 ); | 520 ); |
442 } | 521 } |
443 | 522 |
444 boolean addToExpList() { | 523 boolean addToExpList(ExpList.Builder bld) { |
445 Object obj = pop(); | 524 Object obj = pop(); |
446 ExpList.Builder bld = (ExpList.Builder)peek(); | |
447 if( obj instanceof Expressions ) { | 525 if( obj instanceof Expressions ) { |
448 bld.add( (Expressions)obj ); | 526 bld.add( (Expressions)obj ); |
449 } else { | 527 } else { |
450 bld.add( (Expr)obj ); | 528 bld.add( (Expr)obj ); |
451 } | 529 } |
452 return true; | 530 return true; |
453 } | 531 } |
454 | 532 |
533 | |
455 Rule SubExpr() { | 534 Rule SubExpr() { |
456 return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() ); | 535 return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() ); |
457 } | 536 } |
458 | 537 |
538 Rule NameExpr() { | |
539 return Sequence( | |
540 Name(), | |
541 push( new ConstExpr((String)pop()) ) | |
542 ); | |
543 } | |
544 | |
459 Rule Name() { | 545 Rule Name() { |
460 return Sequence( | 546 return Sequence( |
461 Sequence( | 547 Sequence( |
462 NameStart(), | 548 NameFirstChar(), |
463 ZeroOrMore( | 549 ZeroOrMore( NameChar() ) |
464 FirstOf( NameStart(), Digit() ) | 550 ), |
465 ) | 551 !keywords.contains(match()), |
466 ), | 552 push(match()), |
467 pushNameExpr(), | |
468 Spaces() | 553 Spaces() |
469 ); | 554 ); |
470 } | 555 } |
471 | 556 |
472 Rule NameStart() { | 557 Rule NameChar() { |
558 return FirstOf( NameFirstChar(), Digit() ); | |
559 } | |
560 | |
561 Rule NameFirstChar() { | |
473 return FirstOf( | 562 return FirstOf( |
474 CharRange('a', 'z'), | 563 CharRange('a', 'z'), |
475 CharRange('A', 'Z'), | 564 CharRange('A', 'Z'), |
476 '_' | 565 '_' |
477 ); | 566 ); |
478 } | 567 } |
479 | 568 |
480 boolean pushNameExpr() { | 569 Rule Keyword(String keyword) { |
481 String name = match(); | 570 return Sequence( |
482 if( keywords.contains(name) ) | 571 keyword, |
483 return false; | 572 TestNot( NameChar() ), |
484 return push( new ConstExpr(name) ); | 573 Spaces() |
485 } | 574 ); |
486 | 575 } |
487 private static final Set<String> keywords = new HashSet<String>(Arrays.asList( | 576 |
577 static final Set<String> keywords = new HashSet<String>(Arrays.asList( | |
488 "and", | 578 "and", |
489 "break", | 579 "break", |
490 "do", | 580 "do", |
491 "else", | 581 "else", |
492 "elseif", | 582 "elseif", |
633 ); | 723 ); |
634 } | 724 } |
635 | 725 |
636 Rule LongString() { | 726 Rule LongString() { |
637 return Sequence( | 727 return Sequence( |
638 "[", | 728 '[', |
639 ZeroOrMore('='), | 729 ZeroOrMore('='), |
640 nEquals(matchLength()), | 730 nEquals(matchLength()), |
641 '[', | 731 '[', |
642 ZeroOrMore( | 732 ZeroOrMore( |
643 TestNot(LongBracketsEnd()), | 733 TestNot(LongBracketsEnd()), |
647 LongBracketsEnd() | 737 LongBracketsEnd() |
648 ); | 738 ); |
649 } | 739 } |
650 | 740 |
651 Rule QuotedString(char quote) { | 741 Rule QuotedString(char quote) { |
742 StringBuilderVar buf = new StringBuilderVar(); | |
652 return Sequence( | 743 return Sequence( |
653 quote, | 744 quote, |
654 push(new StringBuffer()), | |
655 ZeroOrMore( | 745 ZeroOrMore( |
656 FirstOf( | 746 FirstOf( |
657 Sequence( | 747 Sequence( |
658 NoneOf("\\\n"+quote), | 748 NoneOf("\\\n"+quote), |
659 append(matchedChar()) | 749 buf.append(matchedChar()) |
660 ), | 750 ), |
661 EscSeq() | 751 EscSeq(buf) |
662 ) | 752 ) |
663 ), | 753 ), |
664 quote, | 754 quote, |
665 push(((StringBuffer)pop()).toString()) | 755 push( buf.getString() ) |
666 ); | 756 ); |
667 } | 757 } |
668 | 758 |
669 Rule EscSeq() { | 759 Rule EscSeq(StringBuilderVar buf) { |
670 return Sequence( | 760 return Sequence( |
671 '\\', | 761 '\\', |
672 FirstOf( | 762 FirstOf( |
673 Sequence( 'a', append('\u0007') ), | 763 Sequence( 'a', buf.append('\u0007') ), |
674 Sequence( 'b', append('\b') ), | 764 Sequence( 'b', buf.append('\b') ), |
675 Sequence( 'f', append('\f') ), | 765 Sequence( 'f', buf.append('\f') ), |
676 Sequence( 'n', append('\n') ), | 766 Sequence( 'n', buf.append('\n') ), |
677 Sequence( 'r', append('\r') ), | 767 Sequence( 'r', buf.append('\r') ), |
678 Sequence( 't', append('\t') ), | 768 Sequence( 't', buf.append('\t') ), |
679 Sequence( 'v', append('\u000b') ), | 769 Sequence( 'v', buf.append('\u000b') ), |
680 Sequence( '\\', append('\\') ), | 770 Sequence( '\\', buf.append('\\') ), |
681 Sequence( '"', append('"') ), | 771 Sequence( '"', buf.append('"') ), |
682 Sequence( '\'', append('\'') ), | 772 Sequence( '\'', buf.append('\'') ), |
683 Sequence( | 773 Sequence( |
684 'x', | 774 'x', |
685 Sequence( HexDigit(), HexDigit() ), | 775 Sequence( HexDigit(), HexDigit() ), |
686 append( (char)Integer.parseInt(match(),16) ) | 776 buf.append( (char)Integer.parseInt(match(),16) ) |
687 ), | 777 ), |
688 Sequence( | 778 Sequence( |
689 Sequence( | 779 Sequence( |
690 Digit(), | 780 Digit(), |
691 Optional( | 781 Optional( |
693 Optional( | 783 Optional( |
694 Digit() | 784 Digit() |
695 ) | 785 ) |
696 ) | 786 ) |
697 ), | 787 ), |
698 append( (char)Integer.parseInt(match()) ) | 788 buf.append( (char)Integer.parseInt(match()) ) |
699 ) | 789 ) |
700 ) | 790 ) |
701 ); | 791 ); |
702 } | |
703 | |
704 boolean append(char ch) { | |
705 StringBuffer sb = (StringBuffer)peek(); | |
706 sb.append(ch); | |
707 return true; | |
708 } | 792 } |
709 | 793 |
710 Rule Spaces() { | 794 Rule Spaces() { |
711 return ZeroOrMore( | 795 return ZeroOrMore( |
712 FirstOf( | 796 FirstOf( |