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(