comparison src/luan/interp/LuanParser.java @ 48:64ecb7a3aad7

rename Lua to Luan git-svn-id: https://luan-java.googlecode.com/svn/trunk@49 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 28 Dec 2012 03:29:12 +0000
parents src/luan/interp/LuaParser.java@a443637829c1
children 8ede219cd111
comparison
equal deleted inserted replaced
47:659c7139e903 48:64ecb7a3aad7
1 package luan.interp;
2
3 import java.util.Set;
4 import java.util.HashSet;
5 import java.util.Arrays;
6 import java.util.List;
7 import java.util.ArrayList;
8 import java.util.Scanner;
9 import org.parboiled.BaseParser;
10 import org.parboiled.Parboiled;
11 import org.parboiled.Rule;
12 import org.parboiled.parserunners.ReportingParseRunner;
13 import org.parboiled.support.ParsingResult;
14 import org.parboiled.support.Var;
15 import org.parboiled.support.StringVar;
16 import org.parboiled.support.StringBuilderVar;
17 import org.parboiled.support.ValueStack;
18 import org.parboiled.errors.ErrorUtils;
19 import luan.Luan;
20 import luan.LuanState;
21 import luan.LuanSource;
22
23
24 class LuanParser extends BaseParser<Object> {
25
26 LuanSource source;
27
28 LuanSource.Element se(int start) {
29 return new LuanSource.Element(source,start,currentIndex());
30 }
31
32 static final String _ENV = "_ENV";
33
34 static final class Frame {
35 final Frame parent;
36 final List<String> symbols = new ArrayList<String>();
37 int stackSize = 0;
38 int loops = 0;
39 boolean isVarArg = false;
40 final List<String> upValueSymbols = new ArrayList<String>();
41 final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>();
42
43 Frame() {
44 this.parent = null;
45 upValueSymbols.add(_ENV);
46 upValueGetters.add(UpValue.globalGetter);
47 }
48
49 Frame(Frame parent) {
50 this.parent = parent;
51 }
52
53 int stackIndex(String name) {
54 int i = symbols.size();
55 while( --i >= 0 ) {
56 if( symbols.get(i).equals(name) )
57 return i;
58 }
59 return -1;
60 }
61
62 int upValueIndex(String name) {
63 int i = upValueSymbols.size();
64 while( --i >= 0 ) {
65 if( upValueSymbols.get(i).equals(name) )
66 return i;
67 }
68 if( parent==null )
69 return -1;
70 i = parent.stackIndex(name);
71 if( i != -1 ) {
72 upValueGetters.add(new UpValue.StackGetter(i));
73 } else {
74 i = parent.upValueIndex(name);
75 if( i == -1 )
76 return -1;
77 upValueGetters.add(new UpValue.NestedGetter(i));
78 }
79 upValueSymbols.add(name);
80 return upValueSymbols.size() - 1;
81 }
82 }
83
84 static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0];
85
86 int nEquals;
87 int parens = 0;
88 Frame frame = new Frame();
89
90 boolean nEquals(int n) {
91 nEquals = n;
92 return true;
93 }
94
95 boolean incParens() {
96 parens++;
97 return true;
98 }
99
100 boolean decParens() {
101 parens--;
102 return true;
103 }
104
105 List<String> symbols() {
106 return frame.symbols;
107 }
108
109 int symbolsSize() {
110 return frame.symbols.size();
111 }
112
113 boolean addSymbol(String name) {
114 frame.symbols.add(name);
115 if( frame.stackSize < symbolsSize() )
116 frame.stackSize = symbolsSize();
117 return true;
118 }
119
120 boolean addSymbols(List<String> names) {
121 frame.symbols.addAll(names);
122 if( frame.stackSize < symbolsSize() )
123 frame.stackSize = symbolsSize();
124 return true;
125 }
126
127 int stackIndex(String name) {
128 return frame.stackIndex(name);
129 }
130
131 boolean popSymbols(int n) {
132 List<String> symbols = frame.symbols;
133 while( n-- > 0 ) {
134 symbols.remove(symbols.size()-1);
135 }
136 return true;
137 }
138
139 int upValueIndex(String name) {
140 return frame.upValueIndex(name);
141 }
142
143 boolean incLoops() {
144 frame.loops++;
145 return true;
146 }
147
148 boolean decLoops() {
149 frame.loops--;
150 return true;
151 }
152
153 Chunk newChunk(int start) {
154 return new Chunk( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
155 }
156
157 Rule Target() {
158 Var<Integer> start = new Var<Integer>();
159 return Sequence(
160 Spaces(),
161 FirstOf(
162 Sequence( ExpList(), EOI ),
163 Sequence(
164 start.set(currentIndex()),
165 action( frame.isVarArg = true ),
166 Block(),
167 EOI,
168 push( newChunk(start.get()) )
169 )
170 )
171 );
172 }
173
174 Rule Block() {
175 Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>());
176 Var<Integer> stackStart = new Var<Integer>(symbolsSize());
177 return Sequence(
178 Optional( Stmt(stmts) ),
179 ZeroOrMore(
180 StmtSep(),
181 Optional( Stmt(stmts) )
182 ),
183 push( newBlock(stmts.get(),stackStart.get()) )
184 );
185 }
186
187 Stmt newBlock(List<Stmt> stmts,int stackStart) {
188 int stackEnd = symbolsSize();
189 popSymbols( stackEnd - stackStart );
190 if( stmts.isEmpty() )
191 return Stmt.EMPTY;
192 if( stmts.size()==1 && stackStart==stackEnd )
193 return stmts.get(0);
194 return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
195 }
196
197 Rule StmtSep() {
198 return Sequence(
199 FirstOf(
200 ';',
201 Sequence(
202 Optional( "--", ZeroOrMore(NoneOf("\r\n")) ),
203 EndOfLine()
204 )
205 ),
206 Spaces()
207 );
208 }
209
210 Rule EndOfLine() {
211 return FirstOf("\r\n", '\r', '\n');
212 }
213
214 Rule Stmt(Var<List<Stmt>> stmts) {
215 return FirstOf(
216 LocalStmt(stmts),
217 Sequence(
218 FirstOf(
219 ReturnStmt(),
220 FunctionStmt(),
221 LocalFunctionStmt(),
222 BreakStmt(),
223 GenericForStmt(),
224 NumericForStmt(),
225 TryStmt(),
226 DoStmt(),
227 WhileStmt(),
228 RepeatStmt(),
229 IfStmt(),
230 SetStmt(),
231 ExpressionsStmt()
232 ),
233 stmts.get().add( (Stmt)pop() )
234 )
235 );
236 }
237
238 Rule ReturnStmt() {
239 Var<Integer> start = new Var<Integer>();
240 return Sequence(
241 start.set(currentIndex()),
242 Keyword("return"), Expressions(),
243 push( new ReturnStmt( se(start.get()), (Expressions)pop() ) )
244 );
245 }
246
247 Rule FunctionStmt() {
248 return Sequence(
249 Keyword("function"), FnName(), Function(),
250 push( new SetStmt( (Settable)pop(1), expr(pop()) ) )
251 );
252 }
253
254 Rule FnName() {
255 Var<Integer> start = new Var<Integer>();
256 return Sequence(
257 start.set(currentIndex()),
258 push(null), // marker
259 Name(),
260 ZeroOrMore(
261 '.', Spaces(),
262 makeVarExp(start.get()),
263 NameExpr()
264 ),
265 makeSettableVar(start.get())
266 );
267 }
268
269 Rule LocalFunctionStmt() {
270 return Sequence(
271 Keyword("local"), Keyword("function"),
272 Name(),
273 addSymbol( (String)pop() ),
274 Function(),
275 push( new SetStmt( new SetLocalVar(symbolsSize()-1), expr(pop()) ) )
276 );
277 }
278
279 Rule BreakStmt() {
280 return Sequence(
281 Keyword("break"),
282 frame.loops > 0,
283 push( new BreakStmt() )
284 );
285 }
286
287 Rule GenericForStmt() {
288 Var<Integer> start = new Var<Integer>();
289 Var<Integer> stackStart = new Var<Integer>(symbolsSize());
290 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
291 return Sequence(
292 start.set(currentIndex()),
293 Keyword("for"), NameList(names), Keyword("in"), Expr(), Keyword("do"),
294 addSymbols(names.get()),
295 LoopBlock(), Keyword("end"),
296 push( new GenericForStmt( se(start.get()), stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
297 popSymbols( symbolsSize() - stackStart.get() )
298 );
299 }
300
301 Rule NumericForStmt() {
302 Var<Integer> start = new Var<Integer>();
303 return Sequence(
304 start.set(currentIndex()),
305 Keyword("for"), Name(), '=', Spaces(), Expr(), Keyword("to"), Expr(),
306 push( new ConstExpr(1) ), // default step
307 Optional(
308 Keyword("step"),
309 drop(),
310 Expr()
311 ),
312 addSymbol( (String)pop(3) ), // add "for" var to symbols
313 Keyword("do"), LoopBlock(), Keyword("end"),
314 push( new NumericForStmt( se(start.get()), symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
315 popSymbols(1)
316 );
317 }
318
319 Rule TryStmt() {
320 return Sequence(
321 Keyword("try"), Block(),
322 Keyword("catch"), Name(), addSymbol( (String)pop() ),
323 Keyword("do"), Block(), Keyword("end"),
324 push( new TryStmt( (Stmt)pop(1), symbolsSize()-1, (Stmt)pop() ) ),
325 popSymbols(1)
326 );
327 }
328
329 Rule DoStmt() {
330 return Sequence(
331 Keyword("do"), Block(), Keyword("end")
332 );
333 }
334
335 Rule LocalStmt(Var<List<Stmt>> stmts) {
336 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
337 return Sequence(
338 Keyword("local"), NameList(names),
339 Optional(
340 '=', Spaces(), ExpList(),
341 stmts.get().add( newSetLocalStmt(names.get().size()) )
342 ),
343 addSymbols(names.get())
344 );
345 }
346
347 Rule NameList(Var<List<String>> names) {
348 return Sequence(
349 Name(),
350 names.get().add( (String)pop() ),
351 ZeroOrMore(
352 ',', Spaces(), Name(),
353 names.get().add( (String)pop() )
354 )
355 );
356 }
357
358 SetStmt newSetLocalStmt(int nVars) {
359 Expressions values = (Expressions)pop();
360 SetLocalVar[] vars = new SetLocalVar[nVars];
361 int stackStart = symbolsSize();
362 for( int i=0; i<vars.length; i++ ) {
363 vars[i] = new SetLocalVar(stackStart+i);
364 }
365 return new SetStmt( vars, values );
366 }
367
368 Rule WhileStmt() {
369 return Sequence(
370 Keyword("while"), Expr(), Keyword("do"), LoopBlock(), Keyword("end"),
371 push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) )
372 );
373 }
374
375 Rule RepeatStmt() {
376 return Sequence(
377 Keyword("repeat"), LoopBlock(), Keyword("until"), Expr(),
378 push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) )
379 );
380 }
381
382 Rule LoopBlock() {
383 return Sequence( incLoops(), Block(), decLoops() );
384 }
385
386 Rule IfStmt() {
387 Var<Integer> n = new Var<Integer>(1);
388 return Sequence(
389 Keyword("if"), Expr(), Keyword("then"), Block(),
390 push(Stmt.EMPTY),
391 ZeroOrMore(
392 Keyword("elseif"), drop(), Expr(), Keyword("then"), Block(),
393 push(Stmt.EMPTY),
394 n.set(n.get()+1)
395 ),
396 Optional(
397 Keyword("else"), drop(), Block()
398 ),
399 Keyword("end"),
400 buildIfStmt(n.get())
401 );
402 }
403
404 boolean buildIfStmt(int n) {
405 while( n-- > 0 ) {
406 Stmt elseStmt = (Stmt)pop();
407 Stmt thenStmt = (Stmt)pop();
408 Expr cnd = expr(pop());
409 push( new IfStmt(cnd,thenStmt,elseStmt) );
410 }
411 return true;
412 }
413
414 Rule SetStmt() {
415 return Sequence(
416 VarList(),
417 '=', Spaces(),
418 ExpList(),
419 push( newSetStmt() )
420 );
421 }
422
423 Rule ExpressionsStmt() {
424 return Sequence(
425 ExpList(),
426 push( new ExpressionsStmt((Expressions)pop()) )
427 );
428 }
429
430 SetStmt newSetStmt() {
431 Expressions values = (Expressions)pop();
432 @SuppressWarnings("unchecked")
433 List<Settable> vars = (List<Settable>)pop();
434 return new SetStmt( vars.toArray(new Settable[0]), values );
435 }
436
437 Rule VarList() {
438 Var<List<Settable>> vars = new Var<List<Settable>>(new ArrayList<Settable>());
439 return Sequence(
440 SettableVar(),
441 vars.get().add( (Settable)pop() ),
442 ZeroOrMore(
443 ',', Spaces(), SettableVar(),
444 vars.get().add( (Settable)pop() )
445 ),
446 push(vars.get())
447 );
448 }
449
450 Rule SettableVar() {
451 Var<Integer> start = new Var<Integer>();
452 return Sequence(
453 start.set(currentIndex()),
454 Var(),
455 makeSettableVar(start.get())
456 );
457 }
458
459 boolean makeSettableVar(int start) {
460 Object obj2 = pop();
461 if( obj2==null )
462 return false;
463 Object obj1 = pop();
464 if( obj1!=null ) {
465 Expr key = expr(obj2);
466 Expr table = expr(obj1);
467 return push( new SetTableEntry(se(start),table,key) );
468 }
469 String name = (String)obj2;
470 int index = stackIndex(name);
471 if( index != -1 )
472 return push( new SetLocalVar(index) );
473 index = upValueIndex(name);
474 if( index != -1 )
475 return push( new SetUpVar(index) );
476 return push( new SetTableEntry( se(start), env(), new ConstExpr(name) ) );
477 }
478
479 Rule Expr() {
480 return FirstOf(
481 VarArgs(),
482 OrExpr()
483 );
484 }
485
486 Rule OrExpr() {
487 Var<Integer> start = new Var<Integer>();
488 return Sequence(
489 start.set(currentIndex()),
490 AndExpr(),
491 ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
492 );
493 }
494
495 Rule AndExpr() {
496 Var<Integer> start = new Var<Integer>();
497 return Sequence(
498 start.set(currentIndex()),
499 RelExpr(),
500 ZeroOrMore( "and", Spaces(), RelExpr(), push( new AndExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
501 );
502 }
503
504 Rule RelExpr() {
505 Var<Integer> start = new Var<Integer>();
506 return Sequence(
507 start.set(currentIndex()),
508 ConcatExpr(),
509 ZeroOrMore(
510 FirstOf(
511 Sequence( "==", Spaces(), ConcatExpr(), push( new EqExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
512 Sequence( "~=", Spaces(), ConcatExpr(), push( new NotExpr(se(start.get()),new EqExpr(se(start.get()),expr(pop(1)),expr(pop()))) ) ),
513 Sequence( "<=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
514 Sequence( ">=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop()),expr(pop())) ) ),
515 Sequence( "<", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
516 Sequence( ">", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop()),expr(pop())) ) )
517 )
518 )
519 );
520 }
521
522 Rule ConcatExpr() {
523 Var<Integer> start = new Var<Integer>();
524 return Sequence(
525 start.set(currentIndex()),
526 SumExpr(),
527 Optional( "..", Spaces(), ConcatExpr(), push( new ConcatExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
528 );
529 }
530
531 Rule SumExpr() {
532 Var<Integer> start = new Var<Integer>();
533 return Sequence(
534 start.set(currentIndex()),
535 TermExpr(),
536 ZeroOrMore(
537 FirstOf(
538 Sequence( '+', Spaces(), TermExpr(), push( new AddExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
539 Sequence( '-', TestNot('-'), Spaces(), TermExpr(), push( new SubExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
540 )
541 )
542 );
543 }
544
545 Rule TermExpr() {
546 Var<Integer> start = new Var<Integer>();
547 return Sequence(
548 start.set(currentIndex()),
549 UnaryExpr(),
550 ZeroOrMore(
551 FirstOf(
552 Sequence( '*', Spaces(), UnaryExpr(), push( new MulExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
553 Sequence( '/', Spaces(), UnaryExpr(), push( new DivExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
554 Sequence( '%', Spaces(), UnaryExpr(), push( new ModExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
555 )
556 )
557 );
558 }
559
560 Rule UnaryExpr() {
561 Var<Integer> start = new Var<Integer>();
562 return Sequence(
563 start.set(currentIndex()),
564 FirstOf(
565 Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(se(start.get()),expr(pop())) ) ),
566 Sequence( '-', TestNot('-'), Spaces(), PowExpr(), push( new UnmExpr(se(start.get()),expr(pop())) ) ),
567 Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(se(start.get()),expr(pop())) ) ),
568 PowExpr()
569 )
570 );
571 }
572
573 Rule PowExpr() {
574 Var<Integer> start = new Var<Integer>();
575 return Sequence(
576 start.set(currentIndex()),
577 SingleExpr(),
578 Optional( '^', Spaces(), PowExpr(), push( new PowExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
579 );
580 }
581
582 Rule SingleExpr() {
583 return FirstOf(
584 FunctionExpr(),
585 TableExpr(),
586 VarExp(),
587 LiteralExpr()
588 );
589 }
590
591 Rule FunctionExpr() {
592 return Sequence( "function", Spaces(), Function() );
593 }
594
595 Rule Function() {
596 Var<Integer> start = new Var<Integer>();
597 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
598 return Sequence(
599 start.set(currentIndex()),
600 '(', incParens(), Spaces(),
601 action( frame = new Frame(frame) ),
602 Optional(
603 FirstOf(
604 Sequence(
605 NameList(names), addSymbols(names.get()),
606 Optional( ',', Spaces(), VarArgName() )
607 ),
608 VarArgName()
609 )
610 ),
611 ')', decParens(), Spaces(), Block(), Keyword("end"),
612 push( newChunk(start.get()) ),
613 action( frame = frame.parent )
614 );
615 }
616
617 Rule VarArgName() {
618 return Sequence(
619 "...", Spaces(),
620 action( frame.isVarArg = true )
621 );
622 }
623
624 Rule VarArgs() {
625 Var<Integer> start = new Var<Integer>();
626 return Sequence(
627 start.set(currentIndex()),
628 "...", Spaces(),
629 frame.isVarArg,
630 push( new VarArgs(se(start.get())) )
631 );
632 }
633
634 Rule TableExpr() {
635 Var<Integer> start = new Var<Integer>();
636 Var<List<TableExpr.Field>> fields = new Var<List<TableExpr.Field>>(new ArrayList<TableExpr.Field>());
637 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
638 return Sequence(
639 start.set(currentIndex()),
640 '{', incParens(), Spaces(),
641 Optional(
642 Field(fields,builder),
643 ZeroOrMore(
644 FieldSep(),
645 Field(fields,builder)
646 ),
647 Optional( FieldSep() )
648 ),
649 '}', decParens(),
650 Spaces(),
651 push( new TableExpr( se(start.get()), fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
652 );
653 }
654
655 Rule FieldSep() {
656 return Sequence( AnyOf(",;"), Spaces() );
657 }
658
659 Rule Field(Var<List<TableExpr.Field>> fields,Var<ExpList.Builder> builder) {
660 return FirstOf(
661 Sequence(
662 FirstOf( SubExpr(), NameExpr() ),
663 '=', Spaces(), Expr(),
664 fields.get().add( new TableExpr.Field( expr(pop(1)), expr(pop()) ) )
665 ),
666 Sequence(
667 Expr(),
668 addToExpList(builder.get())
669 )
670 );
671 }
672
673 static Expr expr(Object obj) {
674 if( obj instanceof Expressions )
675 return new ExpressionsExpr((Expressions)obj);
676 return (Expr)obj;
677 }
678
679 Rule VarExp() {
680 Var<Integer> start = new Var<Integer>();
681 return Sequence(
682 start.set(currentIndex()),
683 Var(),
684 makeVarExp(start.get())
685 );
686 }
687
688 Rule Var() {
689 Var<Integer> start = new Var<Integer>();
690 return Sequence(
691 start.set(currentIndex()),
692 FirstOf(
693 Sequence(
694 '(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(),
695 push(expr(pop())),
696 push(null) // marker
697 ),
698 Sequence(
699 push(null), // marker
700 Name()
701 )
702 ),
703 ZeroOrMore(
704 makeVarExp(start.get()),
705 FirstOf(
706 SubExpr(),
707 Sequence( '.', Spaces(), NameExpr() ),
708 Sequence(
709 Args(start),
710 push(null) // marker
711 )
712 )
713 )
714 );
715 }
716
717 Expr env() {
718 int index = stackIndex(_ENV);
719 if( index != -1 )
720 return new GetLocalVar(null,index);
721 index = upValueIndex(_ENV);
722 if( index != -1 )
723 return new GetUpVar(null,index);
724 throw new RuntimeException("_ENV not found");
725 }
726
727 boolean makeVarExp(int start) {
728 Object obj2 = pop();
729 if( obj2==null )
730 return true;
731 Object obj1 = pop();
732 if( obj1 != null )
733 return push( new IndexExpr( se(start), expr(obj1), expr(obj2) ) );
734 String name = (String)obj2;
735 int index = stackIndex(name);
736 if( index != -1 )
737 return push( new GetLocalVar(se(start),index) );
738 index = upValueIndex(name);
739 if( index != -1 )
740 return push( new GetUpVar(se(start),index) );
741 return push( new IndexExpr( se(start), env(), new ConstExpr(name) ) );
742 }
743
744 // function should be on top of the stack
745 Rule Args(Var<Integer> start) {
746 return Sequence(
747 FirstOf(
748 Sequence(
749 '(', incParens(), Spaces(), Expressions(), ')', decParens(), Spaces()
750 ),
751 Sequence(
752 TableExpr(),
753 push( new ExpList.SingleExpList(expr(pop())) )
754 ),
755 Sequence(
756 StringLiteral(), Spaces(),
757 push( new ExpList.SingleExpList(new ConstExpr(pop())) )
758 )
759 ),
760 push( new FnCall( se(start.get()), expr(pop(1)), (Expressions)pop() ) )
761 );
762 }
763
764 Rule Expressions() {
765 return FirstOf(
766 ExpList(),
767 push( ExpList.emptyExpList )
768 );
769 }
770
771 Rule ExpList() {
772 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
773 return Sequence(
774 Expr(),
775 addToExpList(builder.get()),
776 ZeroOrMore(
777 ',', Spaces(), Expr(),
778 addToExpList(builder.get())
779 ),
780 push( builder.get().build() )
781 );
782 }
783
784 boolean addToExpList(ExpList.Builder bld) {
785 Object obj = pop();
786 if( obj instanceof Expressions ) {
787 bld.add( (Expressions)obj );
788 } else {
789 bld.add( (Expr)obj );
790 }
791 return true;
792 }
793
794 Rule SubExpr() {
795 return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() );
796 }
797
798 Rule NameExpr() {
799 return Sequence(
800 Name(),
801 push( new ConstExpr((String)pop()) )
802 );
803 }
804
805 Rule Name() {
806 return Sequence(
807 Sequence(
808 NameFirstChar(),
809 ZeroOrMore( NameChar() )
810 ),
811 !keywords.contains(match()),
812 push(match()),
813 Spaces()
814 );
815 }
816
817 Rule NameChar() {
818 return FirstOf( NameFirstChar(), Digit() );
819 }
820
821 Rule NameFirstChar() {
822 return FirstOf(
823 CharRange('a', 'z'),
824 CharRange('A', 'Z'),
825 '_'
826 );
827 }
828
829 Rule Keyword(String keyword) {
830 return Sequence(
831 keyword,
832 TestNot( NameChar() ),
833 Spaces()
834 );
835 }
836
837 static final Set<String> keywords = new HashSet<String>(Arrays.asList(
838 "and",
839 "break",
840 "catch",
841 "do",
842 "else",
843 "elseif",
844 "end",
845 "false",
846 "for",
847 "function",
848 "goto",
849 "if",
850 "in",
851 "local",
852 "nil",
853 "not",
854 "or",
855 "repeat",
856 "return",
857 "step",
858 "then",
859 "to",
860 "true",
861 "try",
862 "until",
863 "while"
864 ));
865
866 Rule LiteralExpr() {
867 return Sequence(
868 Literal(), Spaces(),
869 push(new ConstExpr(pop()))
870 );
871 }
872
873 Rule Literal() {
874 return FirstOf(
875 NilLiteral(),
876 BooleanLiteral(),
877 NumberLiteral(),
878 StringLiteral()
879 );
880 }
881
882 Rule NilLiteral() {
883 return Sequence( "nil", push(null) );
884 }
885
886 Rule BooleanLiteral() {
887 return FirstOf(
888 Sequence( "true", push(true) ),
889 Sequence( "false", push(false) )
890 );
891 }
892
893 Rule NumberLiteral() {
894 return FirstOf(
895 Sequence(
896 IgnoreCase("0x"),
897 HexNumber()
898 ),
899 Sequence(
900 DecNumber(),
901 push(Double.valueOf(match()))
902 )
903 );
904 }
905
906 Rule DecNumber() {
907 return FirstOf(
908 Sequence(
909 Int(),
910 Optional( '.', Optional(Int()) ),
911 Exponent()
912 ),
913 Sequence( '.', Int(), Exponent() )
914 );
915 }
916
917 Rule Exponent() {
918 return Optional(
919 IgnoreCase('e'),
920 Optional(AnyOf("+-")),
921 Int()
922 );
923 }
924
925 Rule Int() {
926 return OneOrMore(Digit());
927 }
928
929 Rule Digit() {
930 return CharRange('0', '9');
931 }
932
933 Rule HexNumber() {
934 return FirstOf(
935 Sequence(
936 HexInt(),
937 push( (double)Long.parseLong(match(),16) ),
938 Optional( '.', Optional(HexDec()) ),
939 HexExponent()
940 ),
941 Sequence( push(0.0), '.', HexDec(), HexExponent() )
942 );
943 }
944
945 Rule HexDec() {
946 return Sequence(
947 HexInt(),
948 push( (Double)pop() + (double)Long.parseLong(match(),16) / Math.pow(16,matchLength()) )
949 );
950 }
951
952 Rule HexExponent() {
953 return Optional(
954 IgnoreCase('p'),
955 Sequence(
956 Optional(AnyOf("+-")),
957 HexInt()
958 ),
959 push( (Double)pop() * Math.pow(2,(double)Long.parseLong(match())) )
960 );
961 }
962
963 Rule HexInt() {
964 return OneOrMore(Digit());
965 }
966
967
968 Rule HexDigit() {
969 return FirstOf(
970 Digit(),
971 AnyOf("abcdefABCDEF")
972 );
973 }
974
975 Rule StringLiteral() {
976 return FirstOf(
977 QuotedString('"'),
978 QuotedString('\''),
979 LongString()
980 );
981 }
982
983 Rule LongString() {
984 return Sequence(
985 '[',
986 ZeroOrMore('='),
987 nEquals(matchLength()),
988 '[',
989 ZeroOrMore(
990 TestNot(LongBracketsEnd()),
991 ANY
992 ),
993 push( match() ),
994 LongBracketsEnd()
995 );
996 }
997
998 Rule QuotedString(char quote) {
999 StringBuilderVar buf = new StringBuilderVar();
1000 return Sequence(
1001 quote,
1002 ZeroOrMore(
1003 FirstOf(
1004 Sequence(
1005 NoneOf("\\\n"+quote),
1006 buf.append(matchedChar())
1007 ),
1008 EscSeq(buf)
1009 )
1010 ),
1011 quote,
1012 push( buf.getString() )
1013 );
1014 }
1015
1016 Rule EscSeq(StringBuilderVar buf) {
1017 return Sequence(
1018 '\\',
1019 FirstOf(
1020 Sequence( 'a', buf.append('\u0007') ),
1021 Sequence( 'b', buf.append('\b') ),
1022 Sequence( 'f', buf.append('\f') ),
1023 Sequence( 'n', buf.append('\n') ),
1024 Sequence( 'r', buf.append('\r') ),
1025 Sequence( 't', buf.append('\t') ),
1026 Sequence( 'v', buf.append('\u000b') ),
1027 Sequence( '\\', buf.append('\\') ),
1028 Sequence( '"', buf.append('"') ),
1029 Sequence( '\'', buf.append('\'') ),
1030 Sequence(
1031 'x',
1032 Sequence( HexDigit(), HexDigit() ),
1033 buf.append( (char)Integer.parseInt(match(),16) )
1034 ),
1035 Sequence(
1036 Sequence(
1037 Digit(),
1038 Optional(
1039 Digit(),
1040 Optional(
1041 Digit()
1042 )
1043 )
1044 ),
1045 buf.append( (char)Integer.parseInt(match()) )
1046 )
1047 )
1048 );
1049 }
1050
1051 Rule Spaces() {
1052 return ZeroOrMore(
1053 FirstOf(
1054 AnyOf(" \t"),
1055 Comment(),
1056 Sequence( '\\', EndOfLine() ),
1057 Sequence( AnyOf("\r\n"), parens > 0 )
1058 )
1059 );
1060 }
1061
1062 Rule Comment() {
1063 return Sequence(
1064 "--[",
1065 ZeroOrMore('='),
1066 nEquals(matchLength()),
1067 '[',
1068 ZeroOrMore(
1069 TestNot(LongBracketsEnd()),
1070 ANY
1071 ),
1072 LongBracketsEnd()
1073 );
1074 }
1075
1076 Rule LongBracketsEnd() {
1077 return Sequence( ']', ZeroOrMore('='), nEquals==matchLength(), ']' );
1078 }
1079
1080 static boolean action(Object obj) {
1081 return true;
1082 }
1083
1084 // for debugging
1085 boolean print(Object o) {
1086 System.out.println(o);
1087 return true;
1088 }
1089
1090 }