Mercurial Hosting > luan
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 } |