comparison src/luan/impl/LuanParser.java @ 775:1a68fc55a80c

simplify dir structure
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 26 Aug 2016 14:36:40 -0600
parents core/src/luan/impl/LuanParser.java@47add8eeb513
children d69d3c51c44e
comparison
equal deleted inserted replaced
774:3e30cf310e56 775:1a68fc55a80c
1 package luan.impl;
2
3 //import java.io.StringWriter;
4 //import java.io.PrintWriter;
5 import java.util.Set;
6 import java.util.HashSet;
7 import java.util.Arrays;
8 import java.util.List;
9 import java.util.ArrayList;
10 import java.util.concurrent.atomic.AtomicInteger;
11 import luan.Luan;
12 import luan.LuanState;
13 import luan.LuanTable;
14 import luan.modules.PackageLuan;
15
16
17 final class LuanParser {
18
19 private interface Sym {
20 public Expr exp();
21 }
22
23 private int symCounter = 0;
24
25 private class LocalSym implements Sym {
26 final String name;
27 final String javaName;
28 boolean isPointer = false;
29
30 LocalSym(String name) {
31 this.name = name;
32 this.javaName = name + "_" + (++symCounter);
33 }
34
35 Stmts declaration(Expr value) {
36 Stmts stmt = new Stmts();
37 if( value==null ) {
38 stmt.add( new Object() {
39 @Override public String toString() {
40 if( !isPointer )
41 return "Object " + javaName + "; ";
42 else
43 return "final Pointer " + javaName + " = new Pointer(); ";
44 }
45 } );
46 } else {
47 if( value.valType != Val.SINGLE ) throw new RuntimeException();
48 stmt.add( new Object() {
49 @Override public String toString() {
50 if( !isPointer )
51 return "Object " + javaName + " = ";
52 else
53 return "final Pointer " + javaName + " = new Pointer(";
54 }
55 } );
56 stmt.addAll(value);
57 stmt.add( new Object() {
58 @Override public String toString() {
59 if( !isPointer )
60 return "; ";
61 else
62 return "); ";
63 }
64 } );
65 }
66 return stmt;
67 }
68
69 @Override public Expr exp() {
70 Expr exp = new Expr(Val.SINGLE,false);
71 exp.add( new Object() {
72 @Override public String toString() {
73 if( !isPointer )
74 return javaName;
75 else
76 return javaName + ".o";
77 }
78 } );
79 return exp;
80 }
81 }
82
83 private class UpSym implements Sym {
84 final String name;
85 final int i;
86 final String value;
87
88 UpSym(String name,int i,String value) {
89 this.name = name;
90 this.i = i;
91 this.value = value;
92 }
93
94 String init() {
95 return "upValues[" + i + "] = " + value + "; ";
96 }
97
98 @Override public Expr exp() {
99 Expr exp = new Expr(Val.SINGLE,false);
100 exp.add( new Object() {
101 @Override public String toString() {
102 return "upValues[" + i + "].o";
103 }
104 } );
105 return exp;
106 }
107 }
108
109 private final class Frame {
110 final Frame parent;
111 final List<LocalSym> symbols = new ArrayList<LocalSym>();
112 int loops = 0;
113 boolean isVarArg = false;
114 final List<UpSym> upValueSymbols = new ArrayList<UpSym>();
115
116 Frame() {
117 this.parent = null;
118 }
119
120 Frame(Frame parent) {
121 this.parent = parent;
122 }
123
124 LocalSym addLocalSym(String name) {
125 LocalSym sym = new LocalSym(name);
126 symbols.add(sym);
127 return sym;
128 }
129
130 UpSym addUpSym(String name,String value) {
131 UpSym sym = new UpSym( name, upValueSymbols.size(), value );
132 upValueSymbols.add(sym);
133 return sym;
134 }
135
136 LocalSym getLocalSym(String name) {
137 int i = symbols.size();
138 while( --i >= 0 ) {
139 LocalSym sym = symbols.get(i);
140 if( sym.name.equals(name) )
141 return sym;
142 }
143 return null;
144 }
145
146 UpSym getUpSym(String name) {
147 for( UpSym upSym : upValueSymbols ) {
148 if( upSym.name.equals(name) )
149 return upSym;
150 }
151 if( parent != null ) {
152 LocalSym sym = parent.getLocalSym(name);
153 if( sym != null ) {
154 sym.isPointer = true;
155 return addUpSym(name,sym.javaName);
156 }
157 UpSym upSym = parent.getUpSym(name);
158 if( upSym != null ) {
159 return addUpSym(name,"parentUpValues["+upSym.i+"]");
160 }
161 }
162 return null;
163 }
164
165 Sym getSym(String name) {
166 Sym sym = getLocalSym(name);
167 return sym != null ? sym : getUpSym(name);
168 }
169
170 }
171
172 private static class In {
173 static final In NOTHING = new In(false);
174
175 final boolean template;
176
177 private In(boolean template) {
178 this.template = template;
179 }
180
181 In template() {
182 return template ? this : new In(true);
183 }
184 }
185
186 private Frame frame;
187 private final Parser parser;
188 private final Stmts top;
189
190 LuanParser(String sourceText,String sourceName) {
191 this.frame = new Frame();
192 this.parser = new Parser(sourceText,sourceName);
193 this.top = new Stmts();
194 }
195
196 void addVar(String name) {
197 UpSym upSym = frame.addUpSym( "-ADDED-" ,"new Pointer()");
198 LocalSym sym = frame.addLocalSym( name );
199 sym.isPointer = true;
200 top.add( "final Pointer " + sym.javaName + " = upValues[" + upSym.i + "]; " );
201 }
202
203 private int symbolsSize() {
204 return frame.symbols.size();
205 }
206
207 private Stmts addSymbol(String name,Expr value) {
208 final LocalSym sym = frame.addLocalSym(name);
209 return sym.declaration(value);
210 }
211
212 private Sym getSym(String name) {
213 return frame.getSym(name);
214 }
215
216 private void popSymbols(int n) {
217 List<LocalSym> symbols = frame.symbols;
218 while( n-- > 0 ) {
219 symbols.remove(symbols.size()-1);
220 }
221 }
222
223 private void incLoops() {
224 frame.loops++;
225 }
226
227 private void decLoops() {
228 frame.loops--;
229 }
230
231 private <T> T required(T t) throws ParseException {
232 if( t==null )
233 throw parser.exception();
234 return t;
235 }
236
237 private <T> T required(T t,String msg) throws ParseException {
238 if( t==null )
239 throw parser.exception(msg);
240 return t;
241 }
242
243 private Class newFnClass(Stmts stmt) {
244 return toFnClass( stmt, frame.upValueSymbols );
245 }
246
247 private Expr newFnExp(Stmts stmt,String name) {
248 return toFnExp( stmt, frame.upValueSymbols, name );
249 }
250 /*
251 Class Expression() throws ParseException {
252 Spaces();
253 parser.begin();
254 Expr expr = ExprZ(In.NOTHING);
255 if( expr != null && parser.endOfInput() ) {
256 top.add( "return " );
257 top.addAll( expr );
258 top.add( "; " );
259 top.hasReturn = true;
260 return parser.success(newFnClass(top));
261 }
262 return parser.failure(null);
263 }
264 */
265 Class RequiredModule() throws ParseException {
266 GetRequiredModule();
267 return newFnClass(top);
268 }
269
270 String RequiredModuleSource() throws ParseException {
271 GetRequiredModule();
272 return toFnString( top, frame.upValueSymbols );
273 }
274
275 void GetRequiredModule() throws ParseException {
276 Spaces();
277 parser.begin();
278 frame.isVarArg = true;
279 top.add( "final Object[] varArgs = LuanImpl.varArgs(args,0); " );
280 Stmts block = RequiredBlock();
281 top.addAll( block );
282 top.hasReturn = block.hasReturn;
283 if( !parser.endOfInput() )
284 throw parser.exception();
285 parser.success();
286 }
287
288 private Stmts RequiredBlock() throws ParseException {
289 Stmts stmts = new Stmts();
290 int stackStart = symbolsSize();
291 do {
292 Spaces();
293 stmts.addNewLines();
294 Stmts stmt = Stmt();
295 if( stmt != null ) {
296 stmts.addAll(stmt);
297 stmts.hasReturn = stmt.hasReturn;
298 }
299 } while( !stmts.hasReturn && (StmtSep() || TemplateSep(stmts)) );
300 Spaces();
301 while( StmtSep() )
302 Spaces();
303 stmts.addNewLines();
304 int stackEnd = symbolsSize();
305 popSymbols( stackEnd - stackStart );
306 return stmts;
307 }
308
309 private boolean StmtSep() throws ParseException {
310 return parser.match( ';' ) || EndOfLine();
311 }
312
313 private boolean TemplateSep(Stmts stmts) throws ParseException {
314 Stmts stmt = TemplateStmt();
315 if( stmt != null ) {
316 stmts.addAll(stmt);
317 return true;
318 }
319 return false;
320 }
321
322 private boolean EndOfLine() {
323 if( MatchEndOfLine() ) {
324 parser.sb().append('\n');
325 return true;
326 } else {
327 return false;
328 }
329 }
330
331 private boolean MatchEndOfLine() {
332 return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' );
333 }
334
335 private Stmts Stmt() throws ParseException {
336 Stmts stmt;
337 if( (stmt=ReturnStmt()) != null
338 || (stmt=FunctionStmt()) != null
339 || (stmt=LocalStmt()) != null
340 || (stmt=LocalFunctionStmt()) != null
341 || (stmt=BreakStmt()) != null
342 || (stmt=ForStmt()) != null
343 || (stmt=DoStmt()) != null
344 || (stmt=WhileStmt()) != null
345 || (stmt=RepeatStmt()) != null
346 || (stmt=IfStmt()) != null
347 || (stmt=SetStmt()) != null
348 || (stmt=ExpressionsStmt()) != null
349 ) {
350 return stmt;
351 }
352 return null;
353 }
354
355 private Expr indexExpStr(Expr exp1,Expr exp2) {
356 Expr exp = new Expr(Val.SINGLE,false);
357 exp.add( "luan.index(" );
358 exp.addAll( exp1.single() );
359 exp.add( "," );
360 exp.addAll( exp2.single() );
361 exp.add( ")" );
362 return exp;
363 }
364
365 private Expr callExpStr(Expr fn,Expr args) {
366 Expr exp = new Expr(null,true);
367 exp.add( "Luan.checkFunction(" );
368 exp.addAll( fn.single() );
369 exp.add( ").call(luan," );
370 exp.addAll( args.array() );
371 exp.add( ")" );
372 return exp;
373 }
374
375 private Stmts TemplateStmt() throws ParseException {
376 Expr exprs = TemplateExpressions(In.NOTHING);
377 if( exprs == null )
378 return null;
379 Stmts stmt = new Stmts();
380 stmt.add( "Luan.checkFunction(luan.index(PackageLuan.require(luan,\"luan:Io.luan\"),\"template_write\")).call(luan," );
381 stmt.addAll( exprs.array() );
382 stmt.add( "); " );
383 return stmt;
384 }
385
386 private Expr TemplateExpressions(In in) throws ParseException {
387 if( in.template )
388 return null;
389 int start = parser.begin();
390 if( !parser.match( "%>" ) )
391 return parser.failure(null);
392 EndOfLine();
393 In inTemplate = in.template();
394 List<Expr> builder = new ArrayList<Expr>();
395 while(true) {
396 if( parser.match( "<%=" ) ) {
397 Spaces();
398 Expr exp = new Expr(Val.SINGLE,false);
399 exp.addAll( RequiredExpr(inTemplate).single() );
400 builder.add(exp);
401 RequiredMatch( "%>" );
402 } else if( parser.match( "<%" ) ) {
403 Spaces();
404 return parser.success(expString(builder));
405 } else {
406 Expr exp = new Expr(Val.SINGLE,false);
407 int i = parser.currentIndex();
408 do {
409 if( parser.match( "%>" ) )
410 throw parser.exception("'%>' unexpected");
411 if( !(EndOfLine() || parser.anyChar()) )
412 throw parser.exception("Unclosed template expression");
413 } while( !parser.test( "<%" ) );
414 String match = parser.textFrom(i);
415 String rtns = parser.sb().toString();
416 parser.sb().setLength(0);
417 exp.addAll( constExpStr(match) );
418 if( rtns.length() > 0 )
419 exp.add(rtns);
420 builder.add(exp);
421 }
422 }
423 }
424
425 private Stmts ReturnStmt() throws ParseException {
426 parser.begin();
427 if( !Keyword("return") )
428 return parser.failure(null);
429 Expr exprs = ExpStringList(In.NOTHING);
430 Stmts stmt = new Stmts();
431 stmt.add( "return " );
432 if( exprs != null )
433 stmt.addAll( exprs );
434 else
435 stmt.add( "LuanFunction.NOTHING" );
436 stmt.add( "; " );
437 stmt.hasReturn = true;
438 return parser.success( stmt );
439 }
440
441 private Stmts FunctionStmt() throws ParseException {
442 parser.begin();
443 if( !Keyword("function") )
444 return parser.failure(null);
445
446 parser.currentIndex();
447 String name = RequiredName();
448 Var var = nameVar(name);
449 while( parser.match( '.' ) ) {
450 Spaces();
451 // Expr exp = NameExpr();
452 name = Name();
453 if( name==null )
454 return parser.failure(null);
455 var = indexVar( var.exp(), constExpStr(name) );
456 }
457
458 Expr fnDef = RequiredFunction(name);
459 return parser.success( var.set(fnDef) );
460 }
461
462 private Stmts LocalFunctionStmt() throws ParseException {
463 parser.begin();
464 if( !(Keyword("local") && Keyword("function")) )
465 return parser.failure(null);
466 Stmts stmt = new Stmts();
467 String name = RequiredName();
468 stmt.addAll( addSymbol(name,null) );
469 Expr fnDef = RequiredFunction(name);
470 stmt.addAll( nameVar(name).set(fnDef) );
471 return parser.success( stmt );
472 }
473
474 private Stmts BreakStmt() throws ParseException {
475 parser.begin();
476 if( !Keyword("break") )
477 return parser.failure(null);
478 if( frame.loops <= 0 )
479 throw parser.exception("'break' outside of loop");
480 Stmts stmt = new Stmts();
481 stmt.add( "break; " );
482 return parser.success( stmt );
483 }
484
485 int forCounter = 0;
486
487 private Stmts ForStmt() throws ParseException {
488 parser.begin();
489 int stackStart = symbolsSize();
490 if( !Keyword("for") )
491 return parser.failure(null);
492 List<String> names = RequiredNameList();
493 if( !Keyword("in") )
494 return parser.failure(null);
495 Expr expr = RequiredExpr(In.NOTHING).single();
496 RequiredKeyword("do");
497
498 String fnVar = "fn"+ ++forCounter;
499 Expr fnExp = new Expr(null,false);
500 fnExp.add( fnVar + ".call(luan)" );
501 Stmts stmt = new Stmts();
502 stmt.add( ""
503 +"LuanFunction "+fnVar+" = Luan.checkFunction("
504 );
505 stmt.addAll( expr );
506 stmt.add( "); " );
507 stmt.add( "while(true) { " );
508 stmt.addAll( makeLocalSetStmt(names,fnExp) );
509 stmt.add( "if( " );
510 stmt.addAll( nameVar(names.get(0)).exp() );
511 stmt.add( "==null ) break; " );
512 Stmts loop = RequiredLoopBlock();
513 RequiredKeyword("end");
514 stmt.addAll( loop );
515 stmt.add( "} " );
516 popSymbols( symbolsSize() - stackStart );
517 return parser.success(stmt);
518 }
519
520 private Stmts DoStmt() throws ParseException {
521 parser.begin();
522 if( !Keyword("do") )
523 return parser.failure(null);
524 Stmts stmt = RequiredBlock();
525 RequiredKeyword("end");
526 return parser.success(stmt);
527 }
528
529 private Stmts LocalStmt() throws ParseException {
530 parser.begin();
531 if( !Keyword("local") )
532 return parser.failure(null);
533 List<String> names = NameList();
534 if( names==null ) {
535 if( Keyword("function") )
536 return parser.failure(null); // handled later
537 throw parser.exception("Invalid local statement");
538 }
539 Stmts stmt = new Stmts();
540 if( parser.match( '=' ) ) {
541 Spaces();
542 Expr values = ExpStringList(In.NOTHING);
543 if( values==null )
544 throw parser.exception("Expressions expected");
545 stmt.addAll( makeLocalSetStmt(names,values) );
546 } else {
547 Expr value = new Expr(Val.SINGLE,false);
548 value.add( "null" );
549 for( String name : names ) {
550 stmt.addAll( addSymbol(name,value) );
551 }
552 }
553 return parser.success(stmt);
554 }
555
556 private List<String> RequiredNameList() throws ParseException {
557 parser.begin();
558 List<String> names = NameList();
559 if( names==null )
560 throw parser.exception("Name expected");
561 return parser.success(names);
562 }
563
564 private List<String> NameList() throws ParseException {
565 String name = Name();
566 if( name==null )
567 return null;
568 List<String> names = new ArrayList<String>();
569 names.add(name);
570 while( (name=anotherName()) != null ) {
571 names.add(name);
572 }
573 return names;
574 }
575
576 private String anotherName() throws ParseException {
577 parser.begin();
578 if( !parser.match( ',' ) )
579 return parser.failure(null);
580 Spaces();
581 String name = Name();
582 if( name==null )
583 return parser.failure(null);
584 return parser.success(name);
585 }
586
587 private Stmts WhileStmt() throws ParseException {
588 parser.begin();
589 if( !Keyword("while") )
590 return parser.failure(null);
591 Expr cnd = RequiredExpr(In.NOTHING).single();
592 RequiredKeyword("do");
593 Stmts loop = RequiredLoopBlock();
594 RequiredKeyword("end");
595 Stmts stmt = new Stmts();
596 stmt.add( "while( Luan.checkBoolean(" );
597 stmt.addAll( cnd );
598 stmt.add( ") ) { " );
599 stmt.addAll( loop );
600 stmt.add( "} " );
601 return parser.success( stmt );
602 }
603
604 private Stmts RepeatStmt() throws ParseException {
605 parser.begin();
606 if( !Keyword("repeat") )
607 return parser.failure(null);
608 Stmts loop =RequiredLoopBlock();
609 RequiredKeyword("until");
610 Expr cnd = RequiredExpr(In.NOTHING).single();
611 Stmts stmt = new Stmts();
612 stmt.add( "do { " );
613 stmt.addAll( loop );
614 stmt.add( "} while( !Luan.checkBoolean(" );
615 stmt.addAll( cnd );
616 stmt.add( ") ); " );
617 return parser.success( stmt );
618 }
619
620 private Stmts RequiredLoopBlock() throws ParseException {
621 incLoops();
622 Stmts stmt = RequiredBlock();
623 decLoops();
624 return stmt;
625 }
626
627 private Stmts IfStmt() throws ParseException {
628 parser.begin();
629 if( !Keyword("if") )
630 return parser.failure(null);
631 Stmts stmt = new Stmts();
632 Expr cnd;
633 Stmts block;
634 boolean hasReturn = true;
635 cnd = RequiredExpr(In.NOTHING).single();
636 RequiredKeyword("then");
637 block = RequiredBlock();
638 stmt.add( "if( Luan.checkBoolean(" );
639 stmt.addAll( cnd );
640 stmt.add( ") ) { " );
641 stmt.addAll( block );
642 if( !block.hasReturn )
643 hasReturn = false;
644 while( Keyword("elseif") ) {
645 cnd = RequiredExpr(In.NOTHING).single();
646 RequiredKeyword("then");
647 block = RequiredBlock();
648 stmt.add( "} else if( Luan.checkBoolean(" );
649 stmt.addAll( cnd );
650 stmt.add( ") ) { " );
651 stmt.addAll( block );
652 if( !block.hasReturn )
653 hasReturn = false;
654 }
655 if( Keyword("else") ) {
656 block = RequiredBlock();
657 stmt.add( "} else { " );
658 stmt.addAll( block );
659 if( !block.hasReturn )
660 hasReturn = false;
661 } else {
662 hasReturn = false;
663 }
664 RequiredKeyword("end");
665 stmt.add( "} " );
666 stmt.hasReturn = hasReturn;
667 return parser.success( stmt );
668 }
669
670 private Stmts SetStmt() throws ParseException {
671 parser.begin();
672 List<Var> vars = new ArrayList<Var>();
673 Var v = SettableVar();
674 if( v == null )
675 return parser.failure(null);
676 vars.add(v);
677 while( parser.match( ',' ) ) {
678 Spaces();
679 v = SettableVar();
680 if( v == null )
681 return parser.failure(null);
682 vars.add(v);
683 }
684 if( !parser.match( '=' ) )
685 return parser.failure(null);
686 Spaces();
687 Expr values = ExpStringList(In.NOTHING);
688 if( values==null )
689 // throw parser.exception("Expressions expected");
690 return parser.failure(null);
691 return parser.success( makeSetStmt(vars,values) );
692 }
693
694 private Stmts makeSetStmt(List<Var> vars,Expr values) throws ParseException {
695 int n = vars.size();
696 if( n == 1 )
697 return vars.get(0).set(values);
698 Stmts stmt = new Stmts();
699 String varName = values.valType==Val.ARRAY ? "a" : "t";
700 stmt.add( varName + " = " );
701 stmt.addAll( values );
702 stmt.add( "; " );
703 Expr t = new Expr(values.valType,false);
704 t.add( varName );
705 t = t.single();
706 stmt.addAll( vars.get(0).set(t) );
707 for( int i=1; i<n; i++ ) {
708 t.clear();
709 t.add( "LuanImpl.pick(" + varName + ","+i+")" );
710 stmt.addAll( vars.get(i).set(t) );
711 }
712 return stmt;
713 }
714
715 private Stmts makeLocalSetStmt(List<String> names,Expr values) throws ParseException {
716 int n = names.size();
717 if( n == 1 )
718 return addSymbol(names.get(0),values.single());
719 Stmts stmt = new Stmts();
720 String varName = values.valType==Val.ARRAY ? "a" : "t";
721 stmt.add( varName + " = " );
722 stmt.addAll( values );
723 stmt.add( "; " );
724 Expr t = new Expr(values.valType,false);
725 t.add( varName );
726 t = t.single();
727 stmt.addAll( addSymbol(names.get(0),t) );
728 for( int i=1; i<n; i++ ) {
729 t.clear();
730 t.add( "LuanImpl.pick(" + varName + ","+i+")" );
731 stmt.addAll( addSymbol(names.get(i),t) );
732 }
733 return stmt;
734 }
735
736 private Stmts ExpressionsStmt() throws ParseException {
737 parser.begin();
738 Expr exp = ExprZ(In.NOTHING);
739 if( exp != null && exp.isStmt ) {
740 Stmts stmt = new Stmts();
741 if( exp.valType==Val.SINGLE ) {
742 stmt.add( "LuanImpl.nop(" );
743 stmt.addAll( exp );
744 stmt.add( ")" );
745 } else {
746 stmt.addAll( exp );
747 }
748 stmt.add( "; " );
749 return parser.success( stmt );
750 }
751 return parser.failure(null);
752 }
753
754 private Var SettableVar() throws ParseException {
755 int start = parser.begin();
756 Var var = VarZ(In.NOTHING);
757 if( var==null || !var.isSettable() )
758 return parser.failure(null);
759 return parser.success( var );
760 }
761
762 private Expr RequiredExpr(In in) throws ParseException {
763 parser.begin();
764 return parser.success(required(ExprZ(in),"Bad expression"));
765 }
766
767 private Expr ExprZ(In in) throws ParseException {
768 return OrExpr(in);
769 }
770
771 private Expr OrExpr(In in) throws ParseException {
772 parser.begin();
773 Expr exp = AndExpr(in);
774 if( exp==null )
775 return parser.failure(null);
776 while( Keyword("or") ) {
777 exp = exp.single();
778 Expr exp2 = required(AndExpr(in)).single();
779 Expr newExp = new Expr(Val.SINGLE,true);
780 newExp.add( "(LuanImpl.cnd(t = " );
781 newExp.addAll( exp );
782 newExp.add( ") ? t : (" );
783 newExp.addAll( exp2 );
784 newExp.add( "))" );
785 exp = newExp;
786 }
787 return parser.success(exp);
788 }
789
790 private Expr AndExpr(In in) throws ParseException {
791 parser.begin();
792 Expr exp = RelExpr(in);
793 if( exp==null )
794 return parser.failure(null);
795 while( Keyword("and") ) {
796 exp = exp.single();
797 Expr exp2 = required(RelExpr(in)).single();
798 Expr newExp = new Expr(Val.SINGLE,true);
799 newExp.add( "(LuanImpl.cnd(t = " );
800 newExp.addAll( exp );
801 newExp.add( ") ? (" );
802 newExp.addAll( exp2 );
803 newExp.add( ") : t)" );
804 exp = newExp;
805 }
806 return parser.success(exp);
807 }
808
809 private Expr RelExpr(In in) throws ParseException {
810 parser.begin();
811 Expr exp = ConcatExpr(in);
812 if( exp==null )
813 return parser.failure(null);
814 while(true) {
815 if( parser.match("==") ) {
816 Spaces();
817 exp = exp.single();
818 Expr exp2 = required(ConcatExpr(in)).single();
819 Expr newExp = new Expr(Val.SINGLE,false);
820 newExp.add( "LuanImpl.eq(luan," );
821 newExp.addAll( exp );
822 newExp.add( "," );
823 newExp.addAll( exp2 );
824 newExp.add( ")" );
825 exp = newExp;
826 } else if( parser.match("~=") ) {
827 Spaces();
828 exp = exp.single();
829 Expr exp2 = required(ConcatExpr(in)).single();
830 Expr newExp = new Expr(Val.SINGLE,false);
831 newExp.add( "!LuanImpl.eq(luan," );
832 newExp.addAll( exp );
833 newExp.add( "," );
834 newExp.addAll( exp2 );
835 newExp.add( ")" );
836 exp = newExp;
837 } else if( parser.match("<=") ) {
838 Spaces();
839 exp = exp.single();
840 Expr exp2 = required(ConcatExpr(in)).single();
841 Expr newExp = new Expr(Val.SINGLE,false);
842 newExp.add( "LuanImpl.le(luan," );
843 newExp.addAll( exp );
844 newExp.add( "," );
845 newExp.addAll( exp2 );
846 newExp.add( ")" );
847 exp = newExp;
848 } else if( parser.match(">=") ) {
849 Spaces();
850 exp = exp.single();
851 Expr exp2 = required(ConcatExpr(in)).single();
852 Expr newExp = new Expr(Val.SINGLE,false);
853 newExp.add( "LuanImpl.le(luan," );
854 newExp.addAll( exp2 );
855 newExp.add( "," );
856 newExp.addAll( exp );
857 newExp.add( ")" );
858 exp = newExp;
859 } else if( parser.match("<") ) {
860 Spaces();
861 exp = exp.single();
862 Expr exp2 = required(ConcatExpr(in)).single();
863 Expr newExp = new Expr(Val.SINGLE,false);
864 newExp.add( "LuanImpl.lt(luan," );
865 newExp.addAll( exp );
866 newExp.add( "," );
867 newExp.addAll( exp2 );
868 newExp.add( ")" );
869 exp = newExp;
870 } else if( parser.match(">") ) {
871 Spaces();
872 exp = exp.single();
873 Expr exp2 = required(ConcatExpr(in)).single();
874 Expr newExp = new Expr(Val.SINGLE,false);
875 newExp.add( "LuanImpl.lt(luan," );
876 newExp.addAll( exp2 );
877 newExp.add( "," );
878 newExp.addAll( exp );
879 newExp.add( ")" );
880 exp = newExp;
881 } else
882 break;
883 }
884 return parser.success(exp);
885 }
886
887 private Expr ConcatExpr(In in) throws ParseException {
888 parser.begin();
889 Expr exp = SumExpr(in);
890 if( exp==null )
891 return parser.failure(null);
892 if( parser.match("..") ) {
893 Spaces();
894 exp = exp.single();
895 Expr exp2 = required(ConcatExpr(in)).single();
896 Expr newExp = new Expr(Val.SINGLE,false);
897 newExp.add( "LuanImpl.concat(luan," );
898 newExp.addAll( exp );
899 newExp.add( "," );
900 newExp.addAll( exp2 );
901 newExp.add( ")" );
902 exp = newExp;
903 }
904 return parser.success(exp);
905 }
906
907 private Expr SumExpr(In in) throws ParseException {
908 parser.begin();
909 Expr exp = TermExpr(in);
910 if( exp==null )
911 return parser.failure(null);
912 while(true) {
913 if( parser.match('+') ) {
914 Spaces();
915 exp = exp.single();
916 Expr exp2 = required(TermExpr(in)).single();
917 Expr newExp = new Expr(Val.SINGLE,false);
918 newExp.add( "LuanImpl.add(luan," );
919 newExp.addAll( exp );
920 newExp.add( "," );
921 newExp.addAll( exp2 );
922 newExp.add( ")" );
923 exp = newExp;
924 } else if( Minus() ) {
925 Spaces();
926 exp = exp.single();
927 Expr exp2 = required(TermExpr(in)).single();
928 Expr newExp = new Expr(Val.SINGLE,false);
929 newExp.add( "LuanImpl.sub(luan," );
930 newExp.addAll( exp );
931 newExp.add( "," );
932 newExp.addAll( exp2 );
933 newExp.add( ")" );
934 exp = newExp;
935 } else
936 break;
937 }
938 return parser.success(exp);
939 }
940
941 private boolean Minus() {
942 parser.begin();
943 return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure();
944 }
945
946 private Expr TermExpr(In in) throws ParseException {
947 parser.begin();
948 Expr exp = UnaryExpr(in);
949 if( exp==null )
950 return parser.failure(null);
951 while(true) {
952 if( parser.match('*') ) {
953 Spaces();
954 exp = exp.single();
955 Expr exp2 = required(UnaryExpr(in)).single();
956 Expr newExp = new Expr(Val.SINGLE,false);
957 newExp.add( "LuanImpl.mul(luan," );
958 newExp.addAll( exp );
959 newExp.add( "," );
960 newExp.addAll( exp2 );
961 newExp.add( ")" );
962 exp = newExp;
963 } else if( parser.match('/') ) {
964 Spaces();
965 exp = exp.single();
966 Expr exp2 = required(UnaryExpr(in)).single();
967 Expr newExp = new Expr(Val.SINGLE,false);
968 newExp.add( "LuanImpl.div(luan," );
969 newExp.addAll( exp );
970 newExp.add( "," );
971 newExp.addAll( exp2 );
972 newExp.add( ")" );
973 exp = newExp;
974 } else if( Mod() ) {
975 Spaces();
976 exp = exp.single();
977 Expr exp2 = required(UnaryExpr(in)).single();
978 Expr newExp = new Expr(Val.SINGLE,false);
979 newExp.add( "LuanImpl.mod(luan," );
980 newExp.addAll( exp );
981 newExp.add( "," );
982 newExp.addAll( exp2 );
983 newExp.add( ")" );
984 exp = newExp;
985 } else
986 break;
987 }
988 return parser.success(exp);
989 }
990
991 private boolean Mod() {
992 parser.begin();
993 return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure();
994 }
995
996 private Expr UnaryExpr(In in) throws ParseException {
997 parser.begin();
998 if( parser.match('#') ) {
999 Spaces();
1000 Expr exp = required(UnaryExpr(in)).single();
1001 Expr newExp = new Expr(Val.SINGLE,false);
1002 newExp.add( "LuanImpl.len(luan," );
1003 newExp.addAll( exp );
1004 newExp.add( ")" );
1005 return parser.success(newExp);
1006 }
1007 if( Minus() ) {
1008 Spaces();
1009 Expr exp = required(UnaryExpr(in)).single();
1010 Expr newExp = new Expr(Val.SINGLE,false);
1011 newExp.add( "LuanImpl.unm(luan," );
1012 newExp.addAll( exp );
1013 newExp.add( ")" );
1014 return parser.success(newExp);
1015 }
1016 if( Keyword("not") ) {
1017 Spaces();
1018 Expr exp = required(UnaryExpr(in)).single();
1019 Expr newExp = new Expr(Val.SINGLE,false);
1020 newExp.add( "!Luan.checkBoolean(" );
1021 newExp.addAll( exp );
1022 newExp.add( ")" );
1023 return parser.success(newExp);
1024 }
1025 Expr exp = PowExpr(in);
1026 if( exp==null )
1027 return parser.failure(null);
1028 return parser.success(exp);
1029 }
1030
1031 private Expr PowExpr(In in) throws ParseException {
1032 parser.begin();
1033 Expr exp1 = SingleExpr(in);
1034 if( exp1==null )
1035 return parser.failure(null);
1036 if( parser.match('^') ) {
1037 Spaces();
1038 Expr exp2 = required(PowExpr(in));
1039 Expr newExp = new Expr(Val.SINGLE,false);
1040 newExp.add( "LuanImpl.pow(luan," );
1041 newExp.addAll( exp1.single() );
1042 newExp.add( "," );
1043 newExp.addAll( exp2.single() );
1044 newExp.add( ")" );
1045 exp1 = newExp;
1046 }
1047 return parser.success(exp1);
1048 }
1049
1050 private Expr SingleExpr(In in) throws ParseException {
1051 parser.begin();
1052 Expr exp = FunctionExpr();
1053 if( exp != null )
1054 return parser.success(exp);
1055 exp = VarExp(in);
1056 if( exp != null )
1057 return parser.success(exp);
1058 exp = VarArgs();
1059 if( exp != null )
1060 return parser.success(exp);
1061 return parser.failure(null);
1062 }
1063
1064 private Expr FunctionExpr() throws ParseException {
1065 if( !Keyword("function") )
1066 return null;
1067 return RequiredFunction(null);
1068 }
1069
1070 private Expr RequiredFunction(String name) throws ParseException {
1071 parser.begin();
1072 RequiredMatch('(');
1073 Spaces();
1074 frame = new Frame(frame);
1075 Stmts stmt = new Stmts();
1076 List<String> names = NameList();
1077 if( names != null ) {
1078 Expr args = new Expr(Val.ARRAY,false);
1079 args.add( "args" );
1080 stmt.addAll( makeLocalSetStmt(names,args) );
1081 if( parser.match(',') ) {
1082 Spaces();
1083 if( !parser.match("...") )
1084 throw parser.exception();
1085 Spaces();
1086 frame.isVarArg = true;
1087 stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args," + names.size() + "); " );
1088 }
1089 } else if( parser.match("...") ) {
1090 Spaces();
1091 frame.isVarArg = true;
1092 stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args,0); " );
1093 }
1094 RequiredMatch(')');
1095 Spaces();
1096 Stmts block = RequiredBlock();
1097 stmt.addAll( block );
1098 stmt.hasReturn = block.hasReturn;
1099 Expr fnDef = newFnExp(stmt,name);
1100 RequiredKeyword("end");
1101 frame = frame.parent;
1102 return parser.success(fnDef);
1103 }
1104
1105 private Expr VarArgs() throws ParseException {
1106 parser.begin();
1107 if( !frame.isVarArg || !parser.match("...") )
1108 return parser.failure(null);
1109 Spaces();
1110 Expr exp = new Expr(Val.ARRAY,false);
1111 exp.add("varArgs");
1112 return parser.success(exp);
1113 }
1114
1115 private Expr TableExpr() throws ParseException {
1116 parser.begin();
1117 if( !parser.match('{') )
1118 return parser.failure(null);
1119 Expr tblExp = new Expr(Val.SINGLE,false);
1120 tblExp.add( "LuanImpl.table(" );
1121 Expr lastExp = tblExp;
1122 List<Expr> builder = new ArrayList<Expr>();
1123 /*
1124 Spaces();
1125 Field(builder);
1126 while( FieldSep() ) {
1127 Spaces();
1128 Field(builder);
1129 }
1130 */
1131 do {
1132 Spaces(); lastExp.addNewLines();
1133 Expr exp = Field();
1134 if( exp != null ) {
1135 builder.add(exp);
1136 lastExp = exp;
1137 Spaces(); lastExp.addNewLines();
1138 }
1139 } while( FieldSep() );
1140 Expr exp = TemplateExpressions(In.NOTHING);
1141 if( exp != null )
1142 builder.add(exp);
1143 if( !parser.match('}') )
1144 throw parser.exception("Expected table element or '}'");
1145 tblExp.addAll( expString(builder).array() );
1146 tblExp.add( ")" );
1147 Spaces();
1148 tblExp.addNewLines();
1149 return parser.success( tblExp );
1150 }
1151
1152 private boolean FieldSep() throws ParseException {
1153 return parser.anyOf(",;") || EndOfLine();
1154 }
1155
1156 private Expr Field() throws ParseException {
1157 parser.begin();
1158 Expr exp = SubExpr(In.NOTHING);
1159 if( exp==null )
1160 exp = NameExpr();
1161 if( exp!=null && parser.match('=') ) {
1162 Spaces();
1163 Expr val = RequiredExpr(In.NOTHING).single();
1164 Expr newExp = new Expr(Val.SINGLE,false);
1165 newExp.add( "new TableField(" );
1166 newExp.addAll( exp );
1167 newExp.add( "," );
1168 newExp.addAll( val );
1169 newExp.add( ")" );
1170 return parser.success(newExp);
1171 }
1172 parser.rollback();
1173 Expr exprs = ExprZ(In.NOTHING);
1174 if( exprs != null ) {
1175 return parser.success(exprs);
1176 }
1177 return parser.failure(null);
1178 }
1179
1180 private Expr VarExp(In in) throws ParseException {
1181 Var var = VarZ(in);
1182 return var==null ? null : var.exp();
1183 }
1184
1185 private Var VarZ(In in) throws ParseException {
1186 parser.begin();
1187 Var var = VarStart(in);
1188 if( var==null )
1189 return parser.failure(null);
1190 Var var2;
1191 while( (var2=Var2(in,var.exp())) != null ) {
1192 var = var2;
1193 }
1194 return parser.success(var);
1195 }
1196
1197 private Var VarStart(In in) throws ParseException {
1198 if( parser.match('(') ) {
1199 Spaces();
1200 Expr exp = RequiredExpr(in).single();
1201 RequiredMatch(')');
1202 Spaces();
1203 return exprVar(exp);
1204 }
1205 String name = Name();
1206 if( name != null )
1207 return nameVar(name);
1208 Expr exp;
1209 exp = TableExpr();
1210 if( exp != null )
1211 return exprVar(exp);
1212 exp = Literal();
1213 if( exp != null )
1214 return exprVar(exp);
1215 return null;
1216 }
1217
1218 private Var Var2(In in,Expr exp1) throws ParseException {
1219 parser.begin();
1220 Expr exp2 = SubExpr(in);
1221 if( exp2 != null )
1222 return parser.success(indexVar(exp1,exp2));
1223 if( parser.match('.') ) {
1224 Spaces();
1225 exp2 = NameExpr();
1226 if( exp2!=null )
1227 return parser.success(indexVar(exp1,exp2));
1228 return parser.failure(null);
1229 }
1230 Expr fnCall = Args( in, exp1, new ArrayList<Expr>() );
1231 if( fnCall != null )
1232 return parser.success(exprVar(fnCall));
1233 return parser.failure(null);
1234 }
1235
1236 private interface Var {
1237 public Expr exp() throws ParseException;
1238 // public Settable settable() throws ParseException;
1239 public boolean isSettable();
1240 public Stmts set(Expr val) throws ParseException;
1241 }
1242
1243 private Expr env() {
1244 Sym sym = getSym("_ENV");
1245 if( sym != null )
1246 return sym.exp();
1247 return null;
1248 }
1249
1250 private Var nameVar(final String name) {
1251 return new Var() {
1252
1253 public Expr exp() throws ParseException {
1254 Sym sym = getSym(name);
1255 if( sym != null )
1256 return sym.exp();
1257 Expr envExpr = env();
1258 if( envExpr != null )
1259 return indexExpStr( envExpr, constExpStr(name) );
1260 parser.failure(null);
1261 throw parser.exception("name '"+name+"' not defined");
1262 }
1263
1264 public boolean isSettable() {
1265 return true;
1266 }
1267
1268 public Stmts set(Expr val) throws ParseException {
1269 Sym sym = getSym(name);
1270 if( sym != null ) {
1271 Stmts stmt = new Stmts();
1272 stmt.addAll( sym.exp() );
1273 stmt.add( " = " );
1274 stmt.addAll( val.single() );
1275 stmt.add( "; " );
1276 return stmt;
1277 }
1278 Expr envExpr = env();
1279 if( envExpr != null )
1280 return indexVar( envExpr, constExpStr(name) ).set(val);
1281 parser.failure(null);
1282 throw parser.exception("name '"+name+"' not defined");
1283 }
1284 };
1285 }
1286
1287 private Var exprVar(final Expr expr) {
1288 return new Var() {
1289
1290 public Expr exp() {
1291 return expr;
1292 }
1293
1294 public boolean isSettable() {
1295 return false;
1296 }
1297
1298 public Stmts set(Expr val) {
1299 throw new RuntimeException();
1300 }
1301 };
1302 }
1303
1304 private Var indexVar(final Expr table,final Expr key) {
1305 return new Var() {
1306
1307 public Expr exp() {
1308 return indexExpStr( table, key );
1309 }
1310
1311 public boolean isSettable() {
1312 return true;
1313 }
1314
1315 public Stmts set(Expr val) {
1316 Stmts stmt = new Stmts();
1317 stmt.add( "LuanImpl.put(luan," );
1318 stmt.addAll( table.single() );
1319 stmt.add( "," );
1320 stmt.addAll( key.single() );
1321 stmt.add( "," );
1322 stmt.addAll( val.single() );
1323 stmt.add( "); " );
1324 return stmt;
1325 }
1326 };
1327 }
1328
1329 private Expr Args(In in,Expr fn,List<Expr> builder) throws ParseException {
1330 parser.begin();
1331 return args(in,builder)
1332 ? parser.success( callExpStr( fn, expString(builder) ) )
1333 : parser.failure((Expr)null);
1334 }
1335
1336 private boolean args(In in,List<Expr> builder) throws ParseException {
1337 parser.begin();
1338 if( parser.match('(') ) {
1339 Spaces();
1340 ExpList(in,builder); // optional
1341 if( !parser.match(')') )
1342 throw parser.exception("Expression or ')' expected");
1343 Spaces();
1344 return parser.success();
1345 }
1346 Expr exp = TableExpr();
1347 if( exp != null ) {
1348 builder.add(exp);
1349 return parser.success();
1350 }
1351 exp = StringLiteral();
1352 if( exp != null ) {
1353 builder.add(exp);
1354 return parser.success();
1355 }
1356 return parser.failure();
1357 }
1358
1359 private Expr ExpStringList(In in) throws ParseException {
1360 List<Expr> builder = new ArrayList<Expr>();
1361 return ExpList(in,builder) ? expString(builder) : null;
1362 }
1363
1364 private boolean ExpList(In in,List<Expr> builder) throws ParseException {
1365 parser.begin();
1366 Expr exp = TemplateExpressions(in);
1367 if( exp != null ) {
1368 builder.add(exp);
1369 return parser.success();
1370 }
1371 exp = ExprZ(in);
1372 if( exp==null )
1373 return parser.failure();
1374 exp.addNewLines();
1375 builder.add(exp);
1376 while( parser.match(',') ) {
1377 Spaces();
1378 exp = TemplateExpressions(in);
1379 if( exp != null ) {
1380 builder.add(exp);
1381 return parser.success();
1382 }
1383 exp = RequiredExpr(in);
1384 exp.addNewLines();
1385 builder.add(exp);
1386 }
1387 return parser.success();
1388 }
1389
1390 private Expr SubExpr(In in) throws ParseException {
1391 parser.begin();
1392 if( !parser.match('[') || parser.test("[") || parser.test("=") )
1393 return parser.failure(null);
1394 Spaces();
1395 Expr exp = RequiredExpr(In.NOTHING).single();
1396 RequiredMatch(']');
1397 Spaces();
1398 return parser.success(exp);
1399 }
1400
1401 private Expr NameExpr() throws ParseException {
1402 parser.begin();
1403 String name = Name();
1404 if( name==null )
1405 return parser.failure(null);
1406 return parser.success(constExpStr(name));
1407 }
1408
1409 private String RequiredName() throws ParseException {
1410 parser.begin();
1411 String name = Name();
1412 if( name==null )
1413 throw parser.exception("Name expected");
1414 return parser.success(name);
1415 }
1416
1417 private String Name() throws ParseException {
1418 int start = parser.begin();
1419 if( !NameFirstChar() )
1420 return parser.failure(null);
1421 while( NameChar() );
1422 String match = parser.textFrom(start);
1423 if( keywords.contains(match) )
1424 return parser.failure(null);
1425 Spaces();
1426 return parser.success(match);
1427 }
1428
1429 private boolean NameChar() {
1430 return NameFirstChar() || Digit();
1431 }
1432
1433 private boolean NameFirstChar() {
1434 return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_');
1435 }
1436
1437 private void RequiredMatch(char c) throws ParseException {
1438 if( !parser.match(c) )
1439 throw parser.exception("'"+c+"' expected");
1440 }
1441
1442 private void RequiredMatch(String s) throws ParseException {
1443 if( !parser.match(s) )
1444 throw parser.exception("'"+s+"' expected");
1445 }
1446
1447 private void RequiredKeyword(String keyword) throws ParseException {
1448 if( !Keyword(keyword) )
1449 throw parser.exception("'"+keyword+"' expected");
1450 }
1451
1452 private boolean Keyword(String keyword) throws ParseException {
1453 parser.begin();
1454 if( !parser.match(keyword) || NameChar() )
1455 return parser.failure();
1456 Spaces();
1457 return parser.success();
1458 }
1459
1460 private static final Set<String> keywords = new HashSet<String>(Arrays.asList(
1461 "and",
1462 "break",
1463 "do",
1464 "else",
1465 "elseif",
1466 "end",
1467 "false",
1468 "for",
1469 "function",
1470 "goto",
1471 "if",
1472 "in",
1473 "local",
1474 "nil",
1475 "not",
1476 "or",
1477 "repeat",
1478 "return",
1479 "then",
1480 "true",
1481 "until",
1482 "while"
1483 ));
1484
1485 private Expr Literal() throws ParseException {
1486 parser.begin();
1487 if( NilLiteral() ) {
1488 Expr exp = new Expr(Val.SINGLE,false);
1489 exp.add( "null" );
1490 return parser.success(exp);
1491 }
1492 Boolean b = BooleanLiteral();
1493 if( b != null ) {
1494 Expr exp = new Expr(Val.SINGLE,false);
1495 exp.add( b.toString() );
1496 return parser.success(exp);
1497 }
1498 Number n = NumberLiteral();
1499 if( n != null ) {
1500 String s = n.toString();
1501 if( n instanceof Long )
1502 s += "L";
1503 Expr exp = new Expr(Val.SINGLE,false);
1504 exp.add( s );
1505 return parser.success(exp);
1506 }
1507 Expr s = StringLiteral();
1508 if( s != null )
1509 return parser.success(s);
1510 return parser.failure(null);
1511 }
1512
1513 private static int STR_LIM = 65000;
1514
1515 private Expr constExpStr(String s) {
1516 s = s
1517 .replace("\\","\\\\")
1518 .replace("\"","\\\"")
1519 .replace("\n","\\n")
1520 .replace("\r","\\r")
1521 .replace("\t","\\t")
1522 .replace("\b","\\b")
1523 ;
1524 if( s.length() > STR_LIM ) {
1525 int len = s.length();
1526 StringBuilder sb = new StringBuilder();
1527 sb.append( "LuanImpl.strconcat(" );
1528 int start = 0;
1529 while(true) {
1530 int end = start + STR_LIM;
1531 if( end >= len )
1532 break;
1533 sb.append( "\"" ).append( s.substring(start,end) ).append( "\"," );
1534 start = end;
1535 }
1536 sb.append( "\"" ).append( s.substring(start) ).append( "\")" );
1537 s = sb.toString();
1538 } else
1539 s = "\"" + s + "\"";
1540 Expr exp = new Expr(Val.SINGLE,false);
1541 exp.add( s );
1542 return exp;
1543 }
1544
1545 private boolean NilLiteral() throws ParseException {
1546 return Keyword("nil");
1547 }
1548
1549 private Boolean BooleanLiteral() throws ParseException {
1550 if( Keyword("true") )
1551 return true;
1552 if( Keyword("false") )
1553 return false;
1554 return null;
1555 }
1556
1557 private Number NumberLiteral() throws ParseException {
1558 parser.begin();
1559 Number n;
1560 if( parser.matchIgnoreCase("0x") ) {
1561 n = HexNumber();
1562 } else {
1563 n = DecNumber();
1564 }
1565 if( n==null || NameChar() )
1566 return parser.failure(null);
1567 Spaces();
1568 return parser.success(n);
1569 }
1570
1571 private Number DecNumber() {
1572 int start = parser.begin();
1573 boolean isInt = true;
1574 if( Int() ) {
1575 if( parser.match('.') ) {
1576 isInt = false;
1577 Int(); // optional
1578 }
1579 } else if( parser.match('.') && Int() ) {
1580 // ok
1581 isInt = false;
1582 } else
1583 return parser.failure(null);
1584 if( Exponent() ) // optional
1585 isInt = false;
1586 String s = parser.textFrom(start);
1587 if( isInt ) {
1588 try {
1589 return parser.success(Integer.valueOf(s));
1590 } catch(NumberFormatException e) {}
1591 try {
1592 return parser.success(Long.valueOf(s));
1593 } catch(NumberFormatException e) {}
1594 }
1595 return parser.success(Double.valueOf(s));
1596 }
1597
1598 private boolean Exponent() {
1599 parser.begin();
1600 if( !parser.matchIgnoreCase("e") )
1601 return parser.failure();
1602 parser.anyOf("+-"); // optional
1603 if( !Int() )
1604 return parser.failure();
1605 return parser.success();
1606 }
1607
1608 private boolean Int() {
1609 if( !Digit() )
1610 return false;
1611 while( Digit() );
1612 return true;
1613 }
1614
1615 private boolean Digit() {
1616 return parser.inCharRange('0', '9');
1617 }
1618
1619 private Number HexNumber() {
1620 int start = parser.begin();
1621 long nLong = 0;
1622 double n;
1623 if( HexInt() ) {
1624 nLong = Long.parseLong(parser.textFrom(start),16);
1625 n = (double)nLong;
1626 if( parser.match('.') ) {
1627 start = parser.currentIndex();
1628 if( HexInt() ) {
1629 String dec = parser.textFrom(start);
1630 n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1631 }
1632 }
1633 } else if( parser.match('.') && HexInt() ) {
1634 String dec = parser.textFrom(start+1);
1635 n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1636 } else {
1637 return parser.failure(null);
1638 }
1639 if( parser.matchIgnoreCase("p") ) {
1640 parser.anyOf("+-"); // optional
1641 start = parser.currentIndex();
1642 if( !HexInt() )
1643 return parser.failure(null);
1644 n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start)));
1645 }
1646 if( nLong == n ) {
1647 int nInt = (int)nLong;
1648 if( nInt == nLong )
1649 return parser.success(Integer.valueOf(nInt));
1650 return parser.success(Long.valueOf(nLong));
1651 }
1652 return parser.success(Double.valueOf(n));
1653 }
1654
1655 private boolean HexInt() {
1656 if( !HexDigit() )
1657 return false;
1658 while( HexDigit() );
1659 return true;
1660 }
1661
1662
1663 private boolean HexDigit() {
1664 return Digit() || parser.anyOf("abcdefABCDEF");
1665 }
1666
1667 private Expr StringLiteral() throws ParseException {
1668 Expr s;
1669 if( (s=QuotedString('"'))==null
1670 && (s=QuotedString('\''))==null
1671 && (s=LongString())==null
1672 )
1673 return null;
1674 Spaces();
1675 return s;
1676 }
1677
1678 private Expr LongString() throws ParseException {
1679 parser.begin();
1680 if( !parser.match('[') )
1681 return parser.failure(null);
1682 int start = parser.currentIndex();
1683 while( parser.match('=') );
1684 int nEquals = parser.currentIndex() - start;
1685 if( !parser.match('[') )
1686 return parser.failure(null);
1687 EndOfLine();
1688 start = parser.currentIndex();
1689 while( !LongBracketsEnd(nEquals) ) {
1690 if( !(EndOfLine() || parser.anyChar()) )
1691 throw parser.exception("Unclosed long string");
1692 }
1693 String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 );
1694 String rtns = parser.sb().toString();
1695 parser.sb().setLength(0);
1696 Expr exp = constExpStr(s);
1697 if( rtns.length() > 0 )
1698 exp.add(rtns);
1699 return parser.success(exp);
1700 }
1701
1702 private Expr QuotedString(char quote) throws ParseException {
1703 parser.begin();
1704 if( !parser.match(quote) )
1705 return parser.failure(null);
1706 StringBuilder buf = new StringBuilder();
1707 while( !parser.match(quote) ) {
1708 Character c = EscSeq();
1709 if( c != null ) {
1710 buf.append(c);
1711 } else {
1712 if( parser.test('\r') || parser.test('\n') || !parser.anyChar() )
1713 throw parser.exception("Unclosed string");
1714 buf.append(parser.lastChar());
1715 }
1716 }
1717 return parser.success(constExpStr(buf.toString()));
1718 }
1719
1720 private Character EscSeq() {
1721 parser.begin();
1722 if( !parser.match('\\') )
1723 return parser.failure(null);
1724 if( parser.match('a') ) return parser.success('\u0007');
1725 if( parser.match('b') ) return parser.success('\b');
1726 if( parser.match('f') ) return parser.success('\f');
1727 if( parser.match('n') ) return parser.success('\n');
1728 if( parser.match('r') ) return parser.success('\r');
1729 if( parser.match('t') ) return parser.success('\t');
1730 if( parser.match('v') ) return parser.success('\u000b');
1731 if( parser.match('\\') ) return parser.success('\\');
1732 if( parser.match('"') ) return parser.success('"');
1733 if( parser.match('\'') ) return parser.success('\'');
1734 int start = parser.currentIndex();
1735 if( parser.match('x') && HexDigit() && HexDigit() )
1736 return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16));
1737 if( parser.match('u') && HexDigit() && HexDigit() && HexDigit() && HexDigit() )
1738 return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16));
1739 if( Digit() ) {
1740 if( Digit() ) Digit(); // optional
1741 return parser.success((char)Integer.parseInt(parser.textFrom(start)));
1742 }
1743 if( MatchEndOfLine() ) {
1744 return parser.success('\n');
1745 }
1746 return parser.failure(null);
1747 }
1748
1749 private void Spaces() throws ParseException {
1750 while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() );
1751 }
1752
1753 private boolean ContinueOnNextLine() {
1754 parser.begin();
1755 if( parser.match('\\') && EndOfLine() ) {
1756 parser.upSb();
1757 return parser.success();
1758 } else
1759 return parser.failure();
1760 }
1761
1762 private boolean Comment() throws ParseException {
1763 if( LongComment() )
1764 return true;
1765 if( parser.match("--") ) {
1766 while( parser.noneOf("\r\n") );
1767 return true;
1768 }
1769 return false;
1770 }
1771
1772 private boolean LongComment() throws ParseException {
1773 parser.begin();
1774 if( !parser.match("--[") )
1775 return parser.failure();
1776 int start = parser.currentIndex();
1777 while( parser.match('=') );
1778 int nEquals = parser.currentIndex() - start;
1779 if( !parser.match('[') )
1780 return parser.failure();
1781 while( !LongBracketsEnd(nEquals) ) {
1782 if( !(EndOfLine() || parser.anyChar()) )
1783 throw parser.exception("Unclosed comment");
1784 }
1785 parser.upSb();
1786 return parser.success();
1787 }
1788
1789 private boolean LongBracketsEnd(int nEquals) {
1790 parser.begin();
1791 if( !parser.match(']') )
1792 return parser.failure();
1793 while( nEquals-- > 0 ) {
1794 if( !parser.match('=') )
1795 return parser.failure();
1796 }
1797 if( !parser.match(']') )
1798 return parser.failure();
1799 return parser.success();
1800 }
1801
1802
1803
1804 private class ParseList extends ArrayList {
1805
1806 void addNewLines() {
1807 if( parser.sb().length() > 0 ) {
1808 add( parser.sb().toString() );
1809 parser.sb().setLength(0);
1810 /*
1811 if( parser.sourceName.equals("stdin") ) {
1812 StringWriter sw = new StringWriter();
1813 new Throwable().printStackTrace(new PrintWriter(sw,true));
1814 // add(sw.toString());
1815 }
1816 */
1817 }
1818 }
1819
1820 ParseList() {
1821 addNewLines();
1822 }
1823
1824 @Override public boolean add(Object obj) {
1825 if( obj instanceof List ) throw new RuntimeException();
1826 return super.add(obj);
1827 }
1828
1829 @Override public void add(int index,Object obj) {
1830 if( obj instanceof List ) throw new RuntimeException();
1831 super.add(index,obj);
1832 }
1833
1834 @Override public String toString() {
1835 StringBuilder sb = new StringBuilder();
1836 for( Object o : this ) {
1837 sb.append( o.toString() );
1838 }
1839 return sb.toString();
1840 }
1841 }
1842
1843
1844 private static AtomicInteger classCounter = new AtomicInteger();
1845
1846 private enum Val { SINGLE, ARRAY }
1847
1848 private class Expr extends ParseList {
1849 final Val valType;
1850 final boolean isStmt;
1851
1852 Expr(Val valType,boolean isStmt) {
1853 this.valType = valType;
1854 this.isStmt = isStmt;
1855 }
1856
1857 Expr single() {
1858 if( valType==Val.SINGLE )
1859 return this;
1860 Expr exp = new Expr(Val.SINGLE,isStmt);
1861 exp.add( valType==Val.ARRAY ? "LuanImpl.first(" : "Luan.first(" );
1862 exp.addAll( this );
1863 exp.add( ")" );
1864 return exp;
1865 }
1866
1867 Expr array() {
1868 if( valType==Val.ARRAY )
1869 return this;
1870 Expr exp = new Expr(Val.ARRAY,isStmt);
1871 if( valType==Val.SINGLE ) {
1872 exp.add( "new Object[]{" );
1873 exp.addAll( this );
1874 exp.add( "}" );
1875 } else {
1876 exp.add( "Luan.array(" );
1877 exp.addAll( this );
1878 exp.add( ")" );
1879 }
1880 return exp;
1881 }
1882
1883 }
1884
1885 private Expr expString(List<Expr> list) {
1886 Expr exp = new Expr(Val.ARRAY,false);
1887 switch(list.size()) {
1888 case 0:
1889 exp.add("LuanFunction.NOTHING");
1890 return exp;
1891 case 1:
1892 return list.get(0);
1893 default:
1894 int lastI = list.size() - 1;
1895 exp.add( "new Object[]{" );
1896 for( int i=0; i<lastI; i++ ) {
1897 exp.addAll( list.get(i).single() );
1898 exp.add( "," );
1899 }
1900 Expr last = list.get(lastI);
1901 if( last.valType==Val.SINGLE ) {
1902 exp.addAll( last );
1903 exp.add( "}" );
1904 } else {
1905 exp.add( "}" );
1906 exp.add( 0, "LuanImpl.concatArgs(" );
1907 exp.add( "," );
1908 exp.addAll( last );
1909 exp.add( ")" );
1910 }
1911 return exp;
1912 }
1913 }
1914
1915 private class Stmts extends ParseList {
1916 boolean hasReturn = false;
1917 }
1918
1919 private Class toFnClass(Stmts stmts,List<UpSym> upValueSymbols) {
1920 String className = "EXP" + classCounter.incrementAndGet();
1921 String classCode = toFnString(stmts,upValueSymbols,className);
1922 try {
1923 //System.out.println(parser.sourceName);
1924 //System.out.println(classCode);
1925 return LuanJavaCompiler.compile("luan.impl."+className,parser.sourceName,classCode);
1926 } catch(ClassNotFoundException e) {
1927 throw new RuntimeException(e);
1928 }
1929 }
1930
1931 private String toFnString(Stmts stmts,List<UpSym> upValueSymbols) {
1932 String className = "EXP" + classCounter.incrementAndGet();
1933 return toFnString(stmts,upValueSymbols,className);
1934 }
1935
1936 private String toFnString(Stmts stmts,List<UpSym> upValueSymbols,String className) {
1937 if( !stmts.hasReturn )
1938 stmts.add( "\nreturn LuanFunction.NOTHING;" );
1939 return ""
1940 +"package luan.impl; "
1941 +"import luan.Luan; "
1942 +"import luan.LuanFunction; "
1943 +"import luan.LuanState; "
1944 +"import luan.LuanJava; "
1945 +"import luan.LuanException; "
1946 +"import luan.modules.PackageLuan; "
1947
1948 +"public class " + className +" extends Closure { "
1949 +"public "+className+"(LuanJava java) throws LuanException { "
1950 +"super("+upValueSymbols.size()+",java); "
1951 + init(upValueSymbols)
1952 +"} "
1953
1954 +"@Override public Object doCall(LuanState luan,Object[] args) throws LuanException { "
1955 +"final Pointer[] parentUpValues = upValues; "
1956 +"Object t; "
1957 +"Object[] a; "
1958 + stmts
1959 +"\n} "
1960 +"}\n"
1961 ;
1962 }
1963
1964 private Expr toFnExp(Stmts stmt,List<UpSym> upValueSymbols,String name) {
1965 stmt.addNewLines();
1966 if( !stmt.hasReturn )
1967 stmt.add( "return LuanFunction.NOTHING; " );
1968 Expr exp = new Expr(Val.SINGLE,false);
1969 exp.add( ""
1970 +"new Closure("+upValueSymbols.size()+",java) { "
1971 +"{ "
1972 + init(upValueSymbols)
1973 +"} "
1974 +"@Override public Object doCall(LuanState luan,Object[] args) throws LuanException { "
1975 );
1976 if( name != null ) {
1977 exp.add( ""
1978 +"return _" + name + "(luan,args); "
1979 +"} "
1980 +"private Object _" + name + "(LuanState luan,Object[] args) throws LuanException { "
1981 );
1982 }
1983 exp.add( ""
1984 +"final Pointer[] parentUpValues = upValues; "
1985 +"Object t; "
1986 +"Object[] a; "
1987 );
1988 exp.addAll( stmt );
1989 exp.add( ""
1990 +"} "
1991 +"} "
1992 );
1993 return exp;
1994 }
1995
1996 private static String init(List<UpSym> upValueSymbols) {
1997 StringBuilder sb = new StringBuilder();
1998 for( UpSym upSym : upValueSymbols ) {
1999 sb.append( upSym.init() );
2000 }
2001 return sb.toString();
2002 }
2003
2004 }