comparison core/src/luan/impl/LuanParser.java @ 171:3dcb0f9bee82

add core component git-svn-id: https://luan-java.googlecode.com/svn/trunk@172 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Sun, 22 Jun 2014 05:41:22 +0000
parents src/luan/impl/LuanParser.java@4eaee12f6c65
children bdbd4740121f
comparison
equal deleted inserted replaced
170:7c792a328a83 171:3dcb0f9bee82
1 package luan.impl;
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 luan.Luan;
10 import luan.LuanState;
11 import luan.LuanSource;
12
13
14 final class LuanParser {
15
16 private static final class Frame {
17 final Frame parent;
18 final List<String> symbols = new ArrayList<String>();
19 int stackSize = 0;
20 int loops = 0;
21 boolean isVarArg = false;
22 final List<String> upValueSymbols = new ArrayList<String>();
23 final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>();
24
25 Frame(UpValue.Getter envGetter) {
26 this.parent = null;
27 upValueSymbols.add(_ENV);
28 upValueGetters.add(envGetter);
29 }
30
31 Frame(Frame parent) {
32 this.parent = parent;
33 if( upValueIndex(_ENV) != 0 )
34 throw new RuntimeException();
35 }
36
37 int stackIndex(String name) {
38 int i = symbols.size();
39 while( --i >= 0 ) {
40 if( symbols.get(i).equals(name) )
41 return i;
42 }
43 return -1;
44 }
45
46 int upValueIndex(String name) {
47 int i = upValueSymbols.size();
48 while( --i >= 0 ) {
49 if( upValueSymbols.get(i).equals(name) )
50 return i;
51 }
52 if( parent==null )
53 return -1;
54 i = parent.stackIndex(name);
55 if( i != -1 ) {
56 upValueGetters.add(new UpValue.StackGetter(i));
57 } else {
58 i = parent.upValueIndex(name);
59 if( i == -1 )
60 return -1;
61 upValueGetters.add(new UpValue.NestedGetter(i));
62 }
63 upValueSymbols.add(name);
64 return upValueSymbols.size() - 1;
65 }
66
67 void addUpValueGetter(String name,UpValue.Getter upValueGetter) {
68 upValueSymbols.add(name);
69 upValueGetters.add(upValueGetter);
70 }
71 }
72
73 private static class In {
74 static final In NOTHING = new In(false,false);
75
76 final boolean parens;
77 final boolean template;
78
79 private In(boolean parens,boolean template) {
80 this.parens = parens;
81 this.template = template;
82 }
83
84 In parens() {
85 return parens ? this : new In(true,template);
86 }
87
88 In template() {
89 return template ? this : new In(parens,true);
90 }
91 }
92
93 private static final String _ENV = "_ENV";
94 private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0];
95
96 final LuanSource source;
97 private Frame frame;
98 private final Parser parser;
99 private final boolean interactive;
100
101 LuanParser(LuanSource source,UpValue.Getter envGetter) {
102 this.source = source;
103 this.frame = new Frame(envGetter);
104 this.parser = new Parser(source);
105 this.interactive = envGetter instanceof UpValue.ValueGetter;
106 }
107
108 void addVar(String name,Object value) {
109 frame.addUpValueGetter(name,new UpValue.ValueGetter(value));
110 }
111
112 private LuanSource.Element se(int start) {
113 return new LuanSource.Element(source,start,parser.currentIndex());
114 }
115
116 private List<String> symbols() {
117 return frame.symbols;
118 }
119
120 private int symbolsSize() {
121 return frame.symbols.size();
122 }
123
124 private void addSymbol(String name) {
125 frame.symbols.add(name);
126 if( frame.stackSize < symbolsSize() )
127 frame.stackSize = symbolsSize();
128 }
129
130 private void addSymbols(List<String> names) {
131 frame.symbols.addAll(names);
132 if( frame.stackSize < symbolsSize() )
133 frame.stackSize = symbolsSize();
134 }
135
136 private int stackIndex(String name) {
137 return frame.stackIndex(name);
138 }
139
140 private void popSymbols(int n) {
141 List<String> symbols = frame.symbols;
142 while( n-- > 0 ) {
143 symbols.remove(symbols.size()-1);
144 }
145 }
146
147 private int upValueIndex(String name) {
148 return frame.upValueIndex(name);
149 }
150
151 private void incLoops() {
152 frame.loops++;
153 }
154
155 private void decLoops() {
156 frame.loops--;
157 }
158
159 private <T> T required(T t) throws ParseException {
160 if( t==null )
161 throw parser.exception();
162 return t;
163 }
164
165 private <T> T required(T t,String msg) throws ParseException {
166 if( t==null )
167 throw parser.exception(msg);
168 return t;
169 }
170
171 private static Expr expr(Expressions exprs) {
172 if( exprs instanceof Expr )
173 return (Expr)exprs;
174 return new ExpressionsExpr(exprs);
175 }
176
177 private FnDef newFnDef(int start,Stmt stmt) {
178 return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
179 }
180
181 FnDef Expression() throws ParseException {
182 Spaces(In.NOTHING);
183 int start = parser.begin();
184 Expressions expr = Expr(In.NOTHING);
185 if( expr != null && parser.endOfInput() ) {
186 Stmt stmt = new ReturnStmt( se(start), expr );
187 return parser.success(newFnDef(start,stmt));
188 }
189 return parser.failure(null);
190 }
191
192 FnDef RequiredModule() throws ParseException {
193 Spaces(In.NOTHING);
194 int start = parser.begin();
195 frame.isVarArg = true;
196 Stmt stmt = RequiredBlock();
197 if( parser.endOfInput() )
198 return parser.success(newFnDef(start,stmt));
199 throw parser.exception();
200 }
201
202 private Stmt RequiredBlock() throws ParseException {
203 List<Stmt> stmts = new ArrayList<Stmt>();
204 int stackStart = symbolsSize();
205 Stmt(stmts);
206 while( StmtSep(stmts) ) {
207 Spaces(In.NOTHING);
208 Stmt(stmts);
209 }
210 int stackEnd = symbolsSize();
211 popSymbols( stackEnd - stackStart );
212 if( stmts.isEmpty() )
213 return Stmt.EMPTY;
214 if( stmts.size()==1 && stackStart==stackEnd )
215 return stmts.get(0);
216 return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
217 }
218
219 private boolean StmtSep(List<Stmt> stmts) throws ParseException {
220 parser.begin();
221 if( parser.match( ';' ) )
222 return parser.success();
223 if( parser.match( "--" ) ) {
224 while( parser.noneOf("\r\n") );
225 }
226 if( EndOfLine() )
227 return parser.success();
228 parser.rollback();
229 Stmt stmt = TemplateStmt();
230 if( stmt != null ) {
231 stmts.add(stmt);
232 return parser.success();
233 }
234 return parser.failure();
235 }
236
237 private boolean EndOfLine() {
238 return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' );
239 }
240
241 private void Stmt(List<Stmt> stmts) throws ParseException {
242 if( LocalStmt(stmts) )
243 return;
244 Stmt stmt;
245 if( (stmt=ReturnStmt()) != null
246 || (stmt=FunctionStmt()) != null
247 || (stmt=LocalFunctionStmt()) != null
248 || (stmt=ImportStmt()) != null
249 || (stmt=BreakStmt()) != null
250 || (stmt=ForStmt()) != null
251 || (stmt=TryStmt()) != null
252 || (stmt=DoStmt()) != null
253 || (stmt=WhileStmt()) != null
254 || (stmt=FunctionStmt()) != null
255 || (stmt=RepeatStmt()) != null
256 || (stmt=IfStmt()) != null
257 || (stmt=SetStmt()) != null
258 || (stmt=ExpressionsStmt()) != null
259 ) {
260 stmts.add(stmt);
261 }
262 }
263
264 private Stmt TemplateStmt() throws ParseException {
265 int start = parser.currentIndex();
266 Expressions exp = TemplateExpressions(In.NOTHING);
267 if( exp == null )
268 return null;
269 Expr fnExp = (Expr)nameVar(start,"Io").expr();
270 fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("stdout") );
271 fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("write") );
272 FnCall fnCall = new FnCall( se(start), fnExp, exp );
273 return new ExpressionsStmt(fnCall);
274 }
275
276 private Expressions TemplateExpressions(In in) throws ParseException {
277 if( in.template )
278 return null;
279 int start = parser.begin();
280 if( !parser.match( "%>" ) )
281 return parser.failure(null);
282 EndOfLine();
283 In inTemplate = in.template();
284 List<Expressions> builder = new ArrayList<Expressions>();
285 while(true) {
286 if( parser.match( "<%=" ) ) {
287 Spaces(inTemplate);
288 builder.add( RequiredExpr(inTemplate) );
289 RequiredMatch( "%>" );
290 } else if( parser.match( "<%" ) ) {
291 Spaces(inTemplate);
292 return parser.success(ExpList.build(builder));
293 } else {
294 int i = parser.currentIndex();
295 do {
296 if( parser.match( "%>" ) )
297 throw parser.exception("'%>' unexpected");
298 if( !parser.anyChar() )
299 throw parser.exception("Unclosed template expression");
300 } while( !parser.test( "<%" ) );
301 String match = parser.textFrom(i);
302 builder.add( new ConstExpr(match) );
303 }
304 }
305 }
306
307 private Stmt ReturnStmt() throws ParseException {
308 int start = parser.begin();
309 if( !Keyword("return",In.NOTHING) )
310 return parser.failure(null);
311 Expressions exprs = ExpList(In.NOTHING);
312 if( exprs==null )
313 exprs = ExpList.emptyExpList;
314 return parser.success( new ReturnStmt(se(start),exprs) );
315 }
316
317 private Stmt FunctionStmt() throws ParseException {
318 parser.begin();
319 if( !Keyword("function",In.NOTHING) )
320 return parser.failure(null);
321
322 int start = parser.currentIndex();
323 Var var = nameVar(start,RequiredName(In.NOTHING));
324 while( parser.match( '.' ) ) {
325 Spaces(In.NOTHING);
326 var = indexVar( start, expr(var.expr()), NameExpr(In.NOTHING) );
327 }
328 Settable fnName = var.settable();
329
330 FnDef fnDef = RequiredFunction(In.NOTHING);
331 return parser.success( new SetStmt(fnName,fnDef) );
332 }
333
334 private Stmt LocalFunctionStmt() throws ParseException {
335 parser.begin();
336 if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) )
337 return parser.failure(null);
338 String name = RequiredName(In.NOTHING);
339 addSymbol( name );
340 FnDef fnDef = RequiredFunction(In.NOTHING);
341 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) );
342 }
343
344 private Stmt ImportStmt() throws ParseException {
345 int start = parser.begin();
346 if( !Keyword("import",In.NOTHING) )
347 return parser.failure(null);
348 Expr importExpr = (Expr)nameVar(start,"require").expr();
349 String modName = StringLiteral(In.NOTHING);
350 if( modName==null )
351 return parser.failure(null);
352 String varName = modName.substring(modName.lastIndexOf('.')+1);
353 LuanSource.Element se = se(start);
354 FnCall require = new FnCall( se, importExpr, new ConstExpr(modName) );
355 Settable settable;
356 if( interactive ) {
357 settable = nameVar(se,varName).settable();
358 } else {
359 addSymbol( varName );
360 settable = new SetLocalVar(symbolsSize()-1);
361 }
362 return parser.success( new SetStmt( settable, expr(require) ) );
363 }
364
365 private Stmt BreakStmt() throws ParseException {
366 parser.begin();
367 if( !Keyword("break",In.NOTHING) )
368 return parser.failure(null);
369 if( frame.loops <= 0 )
370 throw parser.exception("'break' outside of loop");
371 return parser.success( new BreakStmt() );
372 }
373
374 private Stmt ForStmt() throws ParseException {
375 int start = parser.begin();
376 int stackStart = symbolsSize();
377 if( !Keyword("for",In.NOTHING) )
378 return parser.failure(null);
379 List<String> names = RequiredNameList(In.NOTHING);
380 if( !Keyword("in",In.NOTHING) )
381 return parser.failure(null);
382 Expr expr = expr(RequiredExpr(In.NOTHING));
383 RequiredKeyword("do",In.NOTHING);
384 addSymbols(names);
385 Stmt loop = RequiredLoopBlock();
386 RequiredKeyword("end",In.NOTHING);
387 Stmt stmt = new ForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop );
388 popSymbols( symbolsSize() - stackStart );
389 return parser.success(stmt);
390 }
391
392 private Stmt TryStmt() throws ParseException {
393 parser.begin();
394 if( !Keyword("try",In.NOTHING) )
395 return parser.failure(null);
396 Stmt tryBlock = RequiredBlock();
397 RequiredKeyword("catch",In.NOTHING);
398 String name = RequiredName(In.NOTHING);
399 addSymbol(name);
400 RequiredKeyword("do",In.NOTHING);
401 Stmt catchBlock = RequiredBlock();
402 RequiredKeyword("end",In.NOTHING);
403 Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock );
404 popSymbols(1);
405 return parser.success(stmt);
406 }
407
408 private Stmt DoStmt() throws ParseException {
409 parser.begin();
410 if( !Keyword("do",In.NOTHING) )
411 return parser.failure(null);
412 Stmt stmt = RequiredBlock();
413 RequiredKeyword("end",In.NOTHING);
414 return parser.success(stmt);
415 }
416
417 private boolean LocalStmt(List<Stmt> stmts) throws ParseException {
418 parser.begin();
419 if( !Keyword("local",In.NOTHING) )
420 return parser.failure();
421 List<String> names = NameList(In.NOTHING);
422 if( names==null )
423 return parser.failure();
424 if( parser.match( '=' ) ) {
425 Spaces(In.NOTHING);
426 Expressions values = ExpList(In.NOTHING);
427 if( values==null )
428 throw parser.exception("Expressions expected");
429 SetLocalVar[] vars = new SetLocalVar[names.size()];
430 int stackStart = symbolsSize();
431 for( int i=0; i<vars.length; i++ ) {
432 vars[i] = new SetLocalVar(stackStart+i);
433 }
434 stmts.add( new SetStmt( vars, values ) );
435 }
436 addSymbols(names);
437 return parser.success();
438 }
439
440 private List<String> RequiredNameList(In in) throws ParseException {
441 parser.begin();
442 List<String> names = NameList(in);
443 if( names==null )
444 throw parser.exception("Name expected");
445 return parser.success(names);
446 }
447
448 private List<String> NameList(In in) throws ParseException {
449 String name = Name(in);
450 if( name==null )
451 return null;
452 List<String> names = new ArrayList<String>();
453 names.add(name);
454 while( (name=anotherName(in)) != null ) {
455 names.add(name);
456 }
457 return names;
458 }
459
460 private String anotherName(In in) throws ParseException {
461 parser.begin();
462 if( !parser.match( ',' ) )
463 return parser.failure(null);
464 Spaces(in);
465 String name = Name(in);
466 if( name==null )
467 return parser.failure(null);
468 return parser.success(name);
469 }
470
471 private Stmt WhileStmt() throws ParseException {
472 int start = parser.begin();
473 if( !Keyword("while",In.NOTHING) )
474 return parser.failure(null);
475 Expr cnd = expr(RequiredExpr(In.NOTHING));
476 RequiredKeyword("do",In.NOTHING);
477 Stmt loop = RequiredLoopBlock();
478 RequiredKeyword("end",In.NOTHING);
479 return parser.success( new WhileStmt(se(start),cnd,loop) );
480 }
481
482 private Stmt RepeatStmt() throws ParseException {
483 int start = parser.begin();
484 if( !Keyword("repeat",In.NOTHING) )
485 return parser.failure(null);
486 Stmt loop = RequiredLoopBlock();
487 RequiredKeyword("until",In.NOTHING);
488 Expr cnd = expr(RequiredExpr(In.NOTHING));
489 return parser.success( new RepeatStmt(se(start),loop,cnd) );
490 }
491
492 private Stmt RequiredLoopBlock() throws ParseException {
493 incLoops();
494 Stmt stmt = RequiredBlock();
495 decLoops();
496 return stmt;
497 }
498
499 private Stmt IfStmt() throws ParseException {
500 parser.begin();
501 if( !Keyword("if",In.NOTHING) )
502 return parser.failure(null);
503 return parser.success( IfStmt2() );
504 }
505
506 private Stmt IfStmt2() throws ParseException {
507 int start = parser.currentIndex();
508 Expr cnd = expr(RequiredExpr(In.NOTHING));
509 RequiredKeyword("then",In.NOTHING);
510 Stmt thenBlock = RequiredBlock();
511 Stmt elseBlock;
512 if( Keyword("elseif",In.NOTHING) ) {
513 elseBlock = IfStmt2();
514 } else {
515 elseBlock = Keyword("else",In.NOTHING) ? RequiredBlock() : Stmt.EMPTY;
516 RequiredKeyword("end",In.NOTHING);
517 }
518 return new IfStmt(se(start),cnd,thenBlock,elseBlock);
519 }
520
521 private Stmt SetStmt() throws ParseException {
522 parser.begin();
523 List<Settable> vars = new ArrayList<Settable>();
524 Settable s = SettableVar();
525 if( s == null )
526 return parser.failure(null);
527 vars.add(s);
528 while( parser.match( ',' ) ) {
529 Spaces(In.NOTHING);
530 s = SettableVar();
531 if( s == null )
532 return parser.failure(null);
533 vars.add(s);
534 }
535 if( !parser.match( '=' ) )
536 return parser.failure(null);
537 Spaces(In.NOTHING);
538 Expressions values = ExpList(In.NOTHING);
539 if( values==null )
540 throw parser.exception("Expressions expected");
541 return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) );
542 }
543
544 private Stmt ExpressionsStmt() throws ParseException {
545 parser.begin();
546 Expressions exp = Expr(In.NOTHING);
547 if( exp instanceof FnCall || exp instanceof AndExpr || exp instanceof OrExpr )
548 return parser.success( new ExpressionsStmt(exp) );
549 return parser.failure(null);
550 }
551
552 private Settable SettableVar() throws ParseException {
553 int start = parser.begin();
554 Var var = VarZ(In.NOTHING);
555 if( var==null )
556 return parser.failure(null);
557 return parser.success( var.settable() );
558 }
559
560 private Expressions RequiredExpr(In in) throws ParseException {
561 parser.begin();
562 return parser.success(required(Expr(in),"Bad expression"));
563 }
564
565 private Expressions Expr(In in) throws ParseException {
566 parser.begin();
567 Expressions exp;
568 return (exp = VarArgs(in)) != null
569 || (exp = OrExpr(in)) != null
570 ? parser.success(exp)
571 : parser.failure((Expressions)null)
572 ;
573 }
574
575 private Expressions OrExpr(In in) throws ParseException {
576 int start = parser.begin();
577 Expressions exp = AndExpr(in);
578 if( exp==null )
579 return parser.failure(null);
580 while( Keyword("or",in) ) {
581 exp = new OrExpr( se(start), expr(exp), required(expr(AndExpr(in))) );
582 }
583 return parser.success(exp);
584 }
585
586 private Expressions AndExpr(In in) throws ParseException {
587 int start = parser.begin();
588 Expressions exp = RelExpr(in);
589 if( exp==null )
590 return parser.failure(null);
591 while( Keyword("and",in) ) {
592 exp = new AndExpr( se(start), expr(exp), required(expr(RelExpr(in))) );
593 }
594 return parser.success(exp);
595 }
596
597 private Expressions RelExpr(In in) throws ParseException {
598 int start = parser.begin();
599 Expressions exp = ConcatExpr(in);
600 if( exp==null )
601 return parser.failure(null);
602 while(true) {
603 if( parser.match("==") ) {
604 Spaces(in);
605 exp = new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) );
606 } else if( parser.match("~=") ) {
607 Spaces(in);
608 exp = new NotExpr( se(start), new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ) );
609 } else if( parser.match("<=") ) {
610 Spaces(in);
611 exp = new LeExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) );
612 } else if( parser.match(">=") ) {
613 Spaces(in);
614 exp = new LeExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) );
615 } else if( parser.match("<") ) {
616 Spaces(in);
617 exp = new LtExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) );
618 } else if( parser.match(">") ) {
619 Spaces(in);
620 exp = new LtExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) );
621 } else
622 break;
623 }
624 return parser.success(exp);
625 }
626
627 private Expressions ConcatExpr(In in) throws ParseException {
628 int start = parser.begin();
629 Expressions exp = SumExpr(in);
630 if( exp==null )
631 return parser.failure(null);
632 if( parser.match("..") ) {
633 Spaces(in);
634 exp = new ConcatExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) );
635 }
636 return parser.success(exp);
637 }
638
639 private Expressions SumExpr(In in) throws ParseException {
640 int start = parser.begin();
641 Expressions exp = TermExpr(in);
642 if( exp==null )
643 return parser.failure(null);
644 while(true) {
645 if( parser.match('+') ) {
646 Spaces(in);
647 exp = new AddExpr( se(start), expr(exp), required(expr(TermExpr(in))) );
648 } else if( Minus() ) {
649 Spaces(in);
650 exp = new SubExpr( se(start), expr(exp), required(expr(TermExpr(in))) );
651 } else
652 break;
653 }
654 return parser.success(exp);
655 }
656
657 private boolean Minus() {
658 parser.begin();
659 return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure();
660 }
661
662 private Expressions TermExpr(In in) throws ParseException {
663 int start = parser.begin();
664 Expressions exp = UnaryExpr(in);
665 if( exp==null )
666 return parser.failure(null);
667 while(true) {
668 if( parser.match('*') ) {
669 Spaces(in);
670 exp = new MulExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) );
671 } else if( parser.match('/') ) {
672 Spaces(in);
673 exp = new DivExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) );
674 } else if( Mod() ) {
675 Spaces(in);
676 exp = new ModExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) );
677 } else
678 break;
679 }
680 return parser.success(exp);
681 }
682
683 private boolean Mod() {
684 parser.begin();
685 return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure();
686 }
687
688 private Expressions UnaryExpr(In in) throws ParseException {
689 int start = parser.begin();
690 if( parser.match('#') ) {
691 Spaces(in);
692 return parser.success( new LenExpr( se(start), required(expr(UnaryExpr(in))) ) );
693 }
694 if( Minus() ) {
695 Spaces(in);
696 return parser.success( new UnmExpr( se(start), required(expr(UnaryExpr(in))) ) );
697 }
698 if( Keyword("not",in) ) {
699 Spaces(in);
700 return parser.success( new NotExpr( se(start), required(expr(UnaryExpr(in))) ) );
701 }
702 Expressions exp = PowExpr(in);
703 if( exp==null )
704 return parser.failure(null);
705 return parser.success(exp);
706 }
707
708 private Expressions PowExpr(In in) throws ParseException {
709 int start = parser.begin();
710 Expressions exp = SingleExpr(in);
711 if( exp==null )
712 return parser.failure(null);
713 if( parser.match('^') ) {
714 Spaces(in);
715 exp = new ConcatExpr( se(start), expr(exp), required(expr(PowExpr(in))) );
716 }
717 return parser.success(exp);
718 }
719
720 private Expressions SingleExpr(In in) throws ParseException {
721 parser.begin();
722 Expressions exp;
723 exp = FunctionExpr(in);
724 if( exp != null )
725 return parser.success(exp);
726 exp = TableExpr(in);
727 if( exp != null )
728 return parser.success(exp);
729 exp = VarExp(in);
730 if( exp != null )
731 return parser.success(exp);
732 exp = Literal(in);
733 if( exp != null )
734 return parser.success(exp);
735 return parser.failure(null);
736 }
737
738 private Expr FunctionExpr(In in) throws ParseException {
739 if( !Keyword("function",in) )
740 return null;
741 return RequiredFunction(in);
742 }
743
744 private FnDef RequiredFunction(In in) throws ParseException {
745 int start = parser.begin();
746 RequiredMatch('(');
747 In inParens = in.parens();
748 Spaces(inParens);
749 frame = new Frame(frame);
750 List<String> names = NameList(in);
751 if( names != null ) {
752 addSymbols(names);
753 if( parser.match(',') ) {
754 Spaces(inParens);
755 if( !parser.match("...") )
756 throw parser.exception();
757 frame.isVarArg = true;
758 }
759 } else if( parser.match("...") ) {
760 Spaces(inParens);
761 frame.isVarArg = true;
762 }
763 RequiredMatch(')');
764 Spaces(in);
765 Stmt block = RequiredBlock();
766 RequiredKeyword("end",in);
767 FnDef fnDef = newFnDef(start,block);
768 frame = frame.parent;
769 return parser.success(fnDef);
770 }
771
772 private VarArgs VarArgs(In in) throws ParseException {
773 int start = parser.begin();
774 if( !frame.isVarArg || !parser.match("...") )
775 return parser.failure(null);
776 Spaces(in);
777 return parser.success( new VarArgs(se(start)) );
778 }
779
780 private Expr TableExpr(In in) throws ParseException {
781 int start = parser.begin();
782 if( !parser.match('{') )
783 return parser.failure(null);
784 In inParens = in.parens();
785 Spaces(inParens);
786 List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>();
787 List<Expressions> builder = new ArrayList<Expressions>();
788 while( Field(fields,builder,in) && FieldSep(inParens) );
789 Spaces(inParens);
790 if( !parser.match('}') )
791 throw parser.exception("Expected table element or '}'");
792 return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), ExpList.build(builder) ) );
793 }
794
795 private boolean FieldSep(In in) throws ParseException {
796 if( !parser.anyOf(",;") )
797 return false;
798 Spaces(in);
799 return true;
800 }
801
802 private boolean Field(List<TableExpr.Field> fields,List<Expressions> builder,In in) throws ParseException {
803 parser.begin();
804 Expr exp = SubExpr(in);
805 if( exp==null )
806 exp = NameExpr(in);
807 if( exp!=null && parser.match('=') ) {
808 Spaces(in);
809 fields.add( new TableExpr.Field( exp, required(expr(Expr(in))) ) );
810 return parser.success();
811 }
812 parser.rollback();
813 Expressions exprs = Expr(in);
814 if( exprs != null ) {
815 builder.add(exprs);
816 return parser.success();
817 }
818 return parser.failure();
819 }
820
821 private Expressions VarExp(In in) throws ParseException {
822 Var var = VarZ(in);
823 return var==null ? null : var.expr();
824 }
825
826 private Var VarZ(In in) throws ParseException {
827 int start = parser.begin();
828 Var var = VarStart(in);
829 if( var==null )
830 return parser.failure(null);
831 Var var2;
832 while( (var2=Var2(in,start,var.expr())) != null ) {
833 var = var2;
834 }
835 return parser.success(var);
836 }
837
838 private Var Var2(In in,int start,Expressions exp1) throws ParseException {
839 parser.begin();
840 Var var = VarExt(in,start,exp1);
841 if( var != null )
842 return parser.success(var);
843 if( parser.match("->") ) {
844 Spaces(in);
845 List<Expressions> builder = new ArrayList<Expressions>();
846 builder.add(exp1);
847 Expr exp2 = expr(RequiredVarExpB(in));
848 FnCall fnCall = required(Args( in, start, exp2, builder ));
849 return parser.success(exprVar(fnCall));
850 }
851 FnCall fnCall = Args( in, start, expr(exp1), new ArrayList<Expressions>() );
852 if( fnCall != null )
853 return parser.success(exprVar(fnCall));
854 return parser.failure(null);
855 }
856
857 private Expressions RequiredVarExpB(In in) throws ParseException {
858 int start = parser.begin();
859 Var var = required(VarStart(in));
860 Var var2;
861 while( (var2=VarExt(in,start,var.expr())) != null ) {
862 var = var2;
863 }
864 return parser.success(var.expr());
865 }
866
867 private Var VarExt(In in,int start,Expressions exp1) throws ParseException {
868 parser.begin();
869 Expr exp2 = SubExpr(in);
870 if( exp2 != null )
871 return parser.success(indexVar(start,expr(exp1),exp2));
872 if( parser.match('.') ) {
873 Spaces(in);
874 exp2 = NameExpr(in);
875 if( exp2!=null )
876 return parser.success(indexVar(start,expr(exp1),exp2));
877 }
878 return parser.failure(null);
879 }
880
881 private Var VarStart(In in) throws ParseException {
882 int start = parser.begin();
883 if( parser.match('(') ) {
884 In inParens = in.parens();
885 Spaces(inParens);
886 Expr exp = expr(RequiredExpr(inParens));
887 RequiredMatch(')');
888 Spaces(in);
889 return parser.success(exprVar(exp));
890 }
891 String name = Name(in);
892 if( name != null )
893 return parser.success(nameVar(start,name));
894 return parser.failure(null);
895 }
896
897 private Expr env() {
898 int index = stackIndex(_ENV);
899 if( index != -1 )
900 return new GetLocalVar(null,index);
901 index = upValueIndex(_ENV);
902 if( index != -1 )
903 return new GetUpVar(null,index);
904 throw new RuntimeException("_ENV not found");
905 }
906
907 private interface Var {
908 public Expressions expr();
909 public Settable settable();
910 }
911
912 private Var nameVar(final int start,final String name) {
913 return nameVar(se(start),name);
914 }
915
916 private Var nameVar(final LuanSource.Element se,final String name) {
917 return new Var() {
918
919 public Expr expr() {
920 int index = stackIndex(name);
921 if( index != -1 )
922 return new GetLocalVar(se,index);
923 index = upValueIndex(name);
924 if( index != -1 )
925 return new GetUpVar(se,index);
926 return new IndexExpr( se, env(), new ConstExpr(name) );
927 }
928
929 public Settable settable() {
930 int index = stackIndex(name);
931 if( index != -1 )
932 return new SetLocalVar(index);
933 index = upValueIndex(name);
934 if( index != -1 )
935 return new SetUpVar(index);
936 return new SetTableEntry( se, env(), new ConstExpr(name) );
937 }
938 };
939 }
940
941 private Var exprVar(final Expressions expr) {
942 return new Var() {
943
944 public Expressions expr() {
945 return expr;
946 }
947
948 public Settable settable() {
949 return null;
950 }
951 };
952 }
953
954 private Var indexVar(final int start,final Expr table,final Expr key) {
955 return new Var() {
956
957 public Expr expr() {
958 return new IndexExpr( se(start), table, key );
959 }
960
961 public Settable settable() {
962 return new SetTableEntry(se(start),table,key);
963 }
964 };
965 }
966
967 private FnCall Args(In in,int start,Expr fn,List<Expressions> builder) throws ParseException {
968 parser.begin();
969 return args(in,builder)
970 ? parser.success( new FnCall( se(start), fn, ExpList.build(builder) ) )
971 : parser.failure((FnCall)null);
972 }
973
974 private boolean args(In in,List<Expressions> builder) throws ParseException {
975 if( parser.match('(') ) {
976 In inParens = in.parens();
977 Spaces(inParens);
978 ExpList(inParens,builder); // optional
979 if( !parser.match(')') )
980 throw parser.exception("Expression or ')' expected");
981 Spaces(in);
982 return true;
983 }
984 Expr exp = TableExpr(in);
985 if( exp != null ) {
986 builder.add(exp);
987 return true;
988 }
989 String s = StringLiteral(in);
990 if( s != null ) {
991 builder.add( new ConstExpr(s) );
992 return true;
993 }
994 Expressions exps = TemplateExpressions(in);
995 if( exps != null ) {
996 builder.add(exps);
997 return true;
998 }
999 return false;
1000 }
1001
1002 private Expressions ExpList(In in) throws ParseException {
1003 List<Expressions> builder = new ArrayList<Expressions>();
1004 return ExpList(in,builder) ? ExpList.build(builder) : null;
1005 }
1006
1007 private boolean ExpList(In in,List<Expressions> builder) throws ParseException {
1008 parser.begin();
1009 Expressions exp = TemplateExpressions(in);
1010 if( exp != null ) {
1011 builder.add(exp);
1012 return parser.success();
1013 }
1014 exp = Expr(in);
1015 if( exp==null )
1016 return parser.failure();
1017 builder.add(exp);
1018 while( parser.match(',') ) {
1019 Spaces(in);
1020 exp = TemplateExpressions(in);
1021 if( exp != null ) {
1022 builder.add(exp);
1023 return parser.success();
1024 }
1025 builder.add( RequiredExpr(in) );
1026 }
1027 return parser.success();
1028 }
1029
1030 private Expr SubExpr(In in) throws ParseException {
1031 parser.begin();
1032 if( !parser.match('[') )
1033 return parser.failure(null);
1034 In inParens = in.parens();
1035 Spaces(inParens);
1036 Expr exp = expr(RequiredExpr(inParens));
1037 RequiredMatch(']');
1038 Spaces(in);
1039 return parser.success(exp);
1040 }
1041
1042 private Expr NameExpr(In in) throws ParseException {
1043 String name = Name(in);
1044 return name==null ? null : new ConstExpr(name);
1045 }
1046
1047 private String RequiredName(In in) throws ParseException {
1048 parser.begin();
1049 String name = Name(in);
1050 if( name==null )
1051 throw parser.exception("Name expected");
1052 return parser.success(name);
1053 }
1054
1055 private String Name(In in) throws ParseException {
1056 int start = parser.begin();
1057 if( !NameFirstChar() )
1058 return parser.failure(null);
1059 while( NameChar() );
1060 String match = parser.textFrom(start);
1061 if( keywords.contains(match) )
1062 return parser.failure(null);
1063 Spaces(in);
1064 return parser.success(match);
1065 }
1066
1067 private boolean NameChar() {
1068 return NameFirstChar() || Digit();
1069 }
1070
1071 private boolean NameFirstChar() {
1072 return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_');
1073 }
1074
1075 private void RequiredMatch(char c) throws ParseException {
1076 if( !parser.match(c) )
1077 throw parser.exception("'"+c+"' expected");
1078 }
1079
1080 private void RequiredMatch(String s) throws ParseException {
1081 if( !parser.match(s) )
1082 throw parser.exception("'"+s+"' expected");
1083 }
1084
1085 private void RequiredKeyword(String keyword,In in) throws ParseException {
1086 if( !Keyword(keyword,in) )
1087 throw parser.exception("'"+keyword+"' expected");
1088 }
1089
1090 private boolean Keyword(String keyword,In in) throws ParseException {
1091 parser.begin();
1092 if( !parser.match(keyword) || NameChar() )
1093 return parser.failure();
1094 Spaces(in);
1095 return parser.success();
1096 }
1097
1098 private static final Set<String> keywords = new HashSet<String>(Arrays.asList(
1099 "and",
1100 "break",
1101 "catch",
1102 "do",
1103 "else",
1104 "elseif",
1105 "end",
1106 "false",
1107 "for",
1108 "function",
1109 "goto",
1110 "if",
1111 "import",
1112 "in",
1113 "local",
1114 "nil",
1115 "not",
1116 "or",
1117 "repeat",
1118 "return",
1119 "then",
1120 "true",
1121 "try",
1122 "until",
1123 "while"
1124 ));
1125
1126 private Expr Literal(In in) throws ParseException {
1127 if( NilLiteral(in) )
1128 return new ConstExpr(null);
1129 Boolean b = BooleanLiteral(in);
1130 if( b != null )
1131 return new ConstExpr(b);
1132 Number n = NumberLiteral(in);
1133 if( n != null )
1134 return new ConstExpr(n);
1135 String s = StringLiteral(in);
1136 if( s != null )
1137 return new ConstExpr(s);
1138 return null;
1139 }
1140
1141 private boolean NilLiteral(In in) throws ParseException {
1142 return Keyword("nil",in);
1143 }
1144
1145 private Boolean BooleanLiteral(In in) throws ParseException {
1146 if( Keyword("true",in) )
1147 return true;
1148 if( Keyword("false",in) )
1149 return false;
1150 return null;
1151 }
1152
1153 private Number NumberLiteral(In in) throws ParseException {
1154 parser.begin();
1155 Number n;
1156 if( parser.matchIgnoreCase("0x") ) {
1157 n = HexNumber();
1158 } else {
1159 n = DecNumber();
1160 }
1161 if( n==null || NameChar() )
1162 return parser.failure(null);
1163 Spaces(in);
1164 return parser.success(n);
1165 }
1166
1167 private Number DecNumber() {
1168 int start = parser.begin();
1169 if( Int() ) {
1170 if( parser.match('.') )
1171 Int(); // optional
1172 } else if( parser.match('.') && Int() ) {
1173 // ok
1174 } else
1175 return parser.failure(null);
1176 Exponent(); // optional
1177 return parser.success(Double.valueOf(parser.textFrom(start)));
1178 }
1179
1180 private boolean Exponent() {
1181 parser.begin();
1182 if( !parser.matchIgnoreCase("e") )
1183 return parser.failure();
1184 parser.anyOf("+-"); // optional
1185 if( !Int() )
1186 return parser.failure();
1187 return parser.success();
1188 }
1189
1190 private boolean Int() {
1191 if( !Digit() )
1192 return false;
1193 while( Digit() );
1194 return true;
1195 }
1196
1197 private boolean Digit() {
1198 return parser.inCharRange('0', '9');
1199 }
1200
1201 private Number HexNumber() {
1202 int start = parser.begin();
1203 double n;
1204 if( HexInt() ) {
1205 n = (double)Long.parseLong(parser.textFrom(start),16);
1206 if( parser.match('.') ) {
1207 start = parser.currentIndex();
1208 if( HexInt() ) {
1209 String dec = parser.textFrom(start);
1210 n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1211 }
1212 }
1213 } else if( parser.match('.') && HexInt() ) {
1214 String dec = parser.textFrom(start+1);
1215 n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1216 } else {
1217 return parser.failure(null);
1218 }
1219 if( parser.matchIgnoreCase("p") ) {
1220 parser.anyOf("+-"); // optional
1221 start = parser.currentIndex();
1222 if( !HexInt() )
1223 return parser.failure(null);
1224 n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start)));
1225 }
1226 return parser.success(Double.valueOf(n));
1227 }
1228
1229 private boolean HexInt() {
1230 if( !HexDigit() )
1231 return false;
1232 while( HexDigit() );
1233 return true;
1234 }
1235
1236
1237 private boolean HexDigit() {
1238 return Digit() || parser.anyOf("abcdefABCDEF");
1239 }
1240
1241 private String StringLiteral(In in) throws ParseException {
1242 String s;
1243 if( (s=QuotedString('"'))==null
1244 && (s=QuotedString('\''))==null
1245 && (s=LongString())==null
1246 )
1247 return null;
1248 Spaces(in);
1249 return s;
1250 }
1251
1252 private String LongString() throws ParseException {
1253 parser.begin();
1254 if( !parser.match('[') )
1255 return parser.failure(null);
1256 int start = parser.currentIndex();
1257 while( parser.match('=') );
1258 int nEquals = parser.currentIndex() - start;
1259 if( !parser.match('[') )
1260 return parser.failure(null);
1261 EndOfLine();
1262 start = parser.currentIndex();
1263 while( !LongBracketsEnd(nEquals) ) {
1264 if( !parser.anyChar() )
1265 throw parser.exception("Unclosed long string");
1266 }
1267 String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 );
1268 return parser.success(s);
1269 }
1270
1271 private String QuotedString(char quote) throws ParseException {
1272 parser.begin();
1273 if( !parser.match(quote) )
1274 return parser.failure(null);
1275 StringBuilder buf = new StringBuilder();
1276 while( !parser.match(quote) ) {
1277 Character c = EscSeq();
1278 if( c != null ) {
1279 buf.append(c);
1280 } else {
1281 if( !parser.anyChar() )
1282 throw parser.exception("Unclosed string");
1283 buf.append(parser.lastChar());
1284 }
1285 }
1286 return parser.success(buf.toString());
1287 }
1288
1289 private Character EscSeq() {
1290 parser.begin();
1291 if( !parser.match('\\') )
1292 return parser.failure(null);
1293 if( parser.match('a') ) return parser.success('\u0007');
1294 if( parser.match('b') ) return parser.success('\b');
1295 if( parser.match('f') ) return parser.success('\f');
1296 if( parser.match('n') ) return parser.success('\n');
1297 if( parser.match('r') ) return parser.success('\r');
1298 if( parser.match('t') ) return parser.success('\t');
1299 if( parser.match('v') ) return parser.success('\u000b');
1300 if( parser.match('\\') ) return parser.success('\\');
1301 if( parser.match('"') ) return parser.success('"');
1302 if( parser.match('\'') ) return parser.success('\'');
1303 int start = parser.currentIndex();
1304 if( parser.match('x') && HexDigit() && HexDigit() )
1305 return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16));
1306 if( Digit() ) {
1307 if( Digit() ) Digit(); // optional
1308 return parser.success((char)Integer.parseInt(parser.textFrom(start)));
1309 }
1310 return parser.failure(null);
1311 }
1312
1313 private void Spaces(In in) throws ParseException {
1314 while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && NewLine() );
1315 }
1316
1317 private boolean ContinueOnNextLine() {
1318 parser.begin();
1319 return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure();
1320 }
1321
1322 private boolean NewLine() {
1323 if( !EndOfLine() )
1324 return false;
1325 if( parser.match("--") ) {
1326 while( parser.noneOf("\r\n") );
1327 }
1328 return true;
1329 }
1330
1331 private boolean Comment() throws ParseException {
1332 parser.begin();
1333 if( !parser.match("--[") )
1334 return parser.failure();
1335 int start = parser.currentIndex();
1336 while( parser.match('=') );
1337 int nEquals = parser.currentIndex() - start;
1338 if( !parser.match('[') )
1339 return parser.failure();
1340 while( !LongBracketsEnd(nEquals) ) {
1341 if( !parser.anyChar() )
1342 throw parser.exception("Unclosed comment");
1343 }
1344 return parser.success();
1345 }
1346
1347 private boolean LongBracketsEnd(int nEquals) {
1348 parser.begin();
1349 if( !parser.match(']') )
1350 return parser.failure();
1351 while( nEquals-- > 0 ) {
1352 if( !parser.match('=') )
1353 return parser.failure();
1354 }
1355 if( !parser.match(']') )
1356 return parser.failure();
1357 return parser.success();
1358 }
1359
1360 }