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