Mercurial Hosting > luan
comparison core/src/luan/impl/LuanParser.java @ 652:067d9470184d
compile SetStmt and ForStmt
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 04 Apr 2016 23:26:06 -0600 |
parents | 140cc5191b7a |
children | 538b0ae08faa |
comparison
equal
deleted
inserted
replaced
651:140cc5191b7a | 652:067d9470184d |
---|---|
247 return; | 247 return; |
248 StmtString stmt; | 248 StmtString stmt; |
249 if( (stmt=stmtStr(ReturnStmt())) != null | 249 if( (stmt=stmtStr(ReturnStmt())) != null |
250 || (stmt=stmtStr(FunctionStmt())) != null | 250 || (stmt=stmtStr(FunctionStmt())) != null |
251 || (stmt=stmtStr(LocalFunctionStmt())) != null | 251 || (stmt=stmtStr(LocalFunctionStmt())) != null |
252 || (stmt=stmtStr(BreakStmt())) != null | 252 || (stmt=BreakStmt()) != null |
253 || (stmt=stmtStr(ForStmt())) != null | 253 || (stmt=ForStmt()) != null |
254 || (stmt=DoStmt()) != null | 254 || (stmt=DoStmt()) != null |
255 || (stmt=WhileStmt()) != null | 255 || (stmt=WhileStmt()) != null |
256 || (stmt=RepeatStmt()) != null | 256 || (stmt=RepeatStmt()) != null |
257 || (stmt=stmtStr(IfStmt())) != null | 257 || (stmt=stmtStr(IfStmt())) != null |
258 || (stmt=stmtStr(SetStmt())) != null | 258 || (stmt=SetStmt()) != null |
259 || (stmt=ExpressionsStmt()) != null | 259 || (stmt=ExpressionsStmt()) != null |
260 ) { | 260 ) { |
261 stmts.append(stmt.code); | 261 stmts.append(stmt.code); |
262 } | 262 } |
263 } | 263 } |
343 addSymbol( name ); | 343 addSymbol( name ); |
344 FnDef fnDef = RequiredFunction(In.NOTHING); | 344 FnDef fnDef = RequiredFunction(In.NOTHING); |
345 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); | 345 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); |
346 } | 346 } |
347 | 347 |
348 private Stmt BreakStmt() throws ParseException { | 348 private StmtString BreakStmt() throws ParseException { |
349 parser.begin(); | 349 parser.begin(); |
350 if( !Keyword("break",In.NOTHING) ) | 350 if( !Keyword("break",In.NOTHING) ) |
351 return parser.failure(null); | 351 return parser.failure(null); |
352 if( frame.loops <= 0 ) | 352 if( frame.loops <= 0 ) |
353 throw parser.exception("'break' outside of loop"); | 353 throw parser.exception("'break' outside of loop"); |
354 return parser.success( new BreakStmt() ); | 354 // return parser.success( new StmtString("break;\n") ); |
355 } | 355 return parser.success( new StmtString(new BreakStmt()) ); |
356 | 356 } |
357 private Stmt ForStmt() throws ParseException { | 357 |
358 int forCounter = 0; | |
359 | |
360 private StmtString ForStmt() throws ParseException { | |
358 parser.begin(); | 361 parser.begin(); |
359 int stackStart = symbolsSize(); | 362 int stackStart = symbolsSize(); |
360 if( !Keyword("for",In.NOTHING) ) | 363 if( !Keyword("for",In.NOTHING) ) |
361 return parser.failure(null); | 364 return parser.failure(null); |
362 List<String> names = RequiredNameList(In.NOTHING); | 365 List<String> names = RequiredNameList(In.NOTHING); |
363 if( !Keyword("in",In.NOTHING) ) | 366 if( !Keyword("in",In.NOTHING) ) |
364 return parser.failure(null); | 367 return parser.failure(null); |
365 Expr expr = expr(exp(RequiredExpr(In.NOTHING))); | 368 ExpString expr = RequiredExpr(In.NOTHING).expr(); |
366 RequiredKeyword("do",In.NOTHING); | 369 RequiredKeyword("do",In.NOTHING); |
370 | |
371 SetLocalVar[] vars = new SetLocalVar[names.size()]; | |
372 for( int i=0; i<vars.length; i++ ) { | |
373 vars[i] = new SetLocalVar(stackStart+i); | |
374 } | |
375 String varsStr = varsToString(vars); | |
376 | |
377 ExpString firstVar = new ExpString(new GetLocalVar(stackStart)); | |
367 addSymbols(names); | 378 addSymbols(names); |
368 Stmt loop = stmt(RequiredLoopBlock()); | 379 StmtString loop = RequiredLoopBlock(); |
369 RequiredKeyword("end",In.NOTHING); | 380 RequiredKeyword("end",In.NOTHING); |
370 Stmt stmt = new ForStmt( stackStart, symbolsSize() - stackStart, expr, loop ); | 381 String fnVar = "$fn"+ ++forCounter; |
382 String code = "" | |
383 +"try {\n" | |
384 +"LuanFunction "+fnVar+" = $Luan.checkFunction(" + expr.code + ");\n" | |
385 +"while(true) {\n" | |
386 +"for( int i="+stackStart+"; i<"+symbolsSize()+"; i++ ) {\n" | |
387 +"$luan.stackSet(i,null);\n" | |
388 +"}\n" | |
389 +"$Luan.set($luan," + varsStr + ", "+fnVar+".call($luan) );\n" | |
390 +"if( " + firstVar.code + "==null ) break;\n" | |
391 + loop.code | |
392 +"}" | |
393 +"} catch(BreakException e) {\n" | |
394 +"} finally {\n" | |
395 +"$luan.stackClear("+stackStart+","+symbolsSize()+");\n" | |
396 +"}\n" | |
397 ; | |
398 StmtString stmt = new StmtString(code); | |
371 popSymbols( symbolsSize() - stackStart ); | 399 popSymbols( symbolsSize() - stackStart ); |
372 return parser.success(stmt); | 400 return parser.success(stmt); |
373 } | 401 } |
374 | 402 |
375 private StmtString DoStmt() throws ParseException { | 403 private StmtString DoStmt() throws ParseException { |
391 return parser.failure(); // handled later | 419 return parser.failure(); // handled later |
392 throw parser.exception("Invalid local statement"); | 420 throw parser.exception("Invalid local statement"); |
393 } | 421 } |
394 if( parser.match( '=' ) ) { | 422 if( parser.match( '=' ) ) { |
395 Spaces(In.NOTHING); | 423 Spaces(In.NOTHING); |
396 Expressions values = ExpList(In.NOTHING); | 424 ExpString values = ExpStringList(In.NOTHING); |
397 if( values==null ) | 425 if( values==null ) |
398 throw parser.exception("Expressions expected"); | 426 throw parser.exception("Expressions expected"); |
399 SetLocalVar[] vars = new SetLocalVar[names.size()]; | 427 SetLocalVar[] vars = new SetLocalVar[names.size()]; |
400 int stackStart = symbolsSize(); | 428 int stackStart = symbolsSize(); |
401 for( int i=0; i<vars.length; i++ ) { | 429 for( int i=0; i<vars.length; i++ ) { |
402 vars[i] = new SetLocalVar(stackStart+i); | 430 vars[i] = new SetLocalVar(stackStart+i); |
403 } | 431 } |
404 stmts.append( new StmtString(new SetStmt( vars, values )).code ); | 432 String varsStr = varsToString(vars); |
433 String code = "$Luan.set($luan," + varsStr + "," + values.code + ");\n"; | |
434 stmts.append(code); | |
405 } | 435 } |
406 addSymbols(names); | 436 addSymbols(names); |
407 return parser.success(); | 437 return parser.success(); |
408 } | 438 } |
409 | 439 |
500 RequiredKeyword("end",In.NOTHING); | 530 RequiredKeyword("end",In.NOTHING); |
501 } | 531 } |
502 return new IfStmt(cnd,thenBlock,elseBlock); | 532 return new IfStmt(cnd,thenBlock,elseBlock); |
503 } | 533 } |
504 | 534 |
505 private Stmt SetStmt() throws ParseException { | 535 private StmtString SetStmt() throws ParseException { |
506 parser.begin(); | 536 parser.begin(); |
507 List<Settable> vars = new ArrayList<Settable>(); | 537 List<Settable> vars = new ArrayList<Settable>(); |
508 Settable s = SettableVar(); | 538 Settable s = SettableVar(); |
509 if( s == null ) | 539 if( s == null ) |
510 return parser.failure(null); | 540 return parser.failure(null); |
517 vars.add(s); | 547 vars.add(s); |
518 } | 548 } |
519 if( !parser.match( '=' ) ) | 549 if( !parser.match( '=' ) ) |
520 return parser.failure(null); | 550 return parser.failure(null); |
521 Spaces(In.NOTHING); | 551 Spaces(In.NOTHING); |
522 Expressions values = ExpList(In.NOTHING); | 552 ExpString values = ExpStringList(In.NOTHING); |
523 if( values==null ) | 553 if( values==null ) |
524 // throw parser.exception("Expressions expected"); | 554 // throw parser.exception("Expressions expected"); |
525 return parser.failure(null); | 555 return parser.failure(null); |
526 return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) ); | 556 String varsStr = varsToString(vars.toArray(new Settable[0])); |
557 String code = "$Luan.set($luan," + varsStr + "," + values.code + "); "; | |
558 return parser.success( new StmtString(code) ); | |
559 //qqq | |
560 } | |
561 | |
562 private static String varsToString(Settable[] vars) { | |
563 StringBuilder sb = new StringBuilder(); | |
564 sb.append( "new Settable[]{" ); | |
565 for( Settable v : vars ) { | |
566 sb.append( new SettableString(v).code ).append( ',' ); | |
567 } | |
568 sb.append( "}" ); | |
569 return sb.toString(); | |
527 } | 570 } |
528 | 571 |
529 private StmtString ExpressionsStmt() throws ParseException { | 572 private StmtString ExpressionsStmt() throws ParseException { |
530 parser.begin(); | 573 parser.begin(); |
531 ExpString exp = ExprZ(In.NOTHING); | 574 ExpString exp = ExprZ(In.NOTHING); |
906 exp2 = NameExpr(in); | 949 exp2 = NameExpr(in); |
907 if( exp2!=null ) | 950 if( exp2!=null ) |
908 return parser.success(indexVar(expr(exp1),exp2)); | 951 return parser.success(indexVar(expr(exp1),exp2)); |
909 return parser.failure(null); | 952 return parser.failure(null); |
910 } | 953 } |
911 FnCall fnCall = Args( in, expr(exp1), new ArrayList<Expressions>() ); | 954 FnCall fnCall = Args( in, expr(exp1), new ArrayList<ExpString>() ); |
912 if( fnCall != null ) | 955 if( fnCall != null ) |
913 return parser.success(exprVar(fnCall)); | 956 return parser.success(exprVar(fnCall)); |
914 return parser.failure(null); | 957 return parser.failure(null); |
915 } | 958 } |
916 | 959 |
986 return new SetTableEntry(table,key); | 1029 return new SetTableEntry(table,key); |
987 } | 1030 } |
988 }; | 1031 }; |
989 } | 1032 } |
990 | 1033 |
991 private FnCall Args(In in,Expr fn,List<Expressions> builder) throws ParseException { | 1034 private FnCall Args(In in,Expr fn,List<ExpString> builder) throws ParseException { |
992 parser.begin(); | 1035 parser.begin(); |
993 return args(in,builder) | 1036 return args(in,builder) |
994 ? parser.success( new FnCall( fn, ExpList.build(builder) ) ) | 1037 ? parser.success( new FnCall( fn, ExpList.build(expList(builder)) ) ) |
995 : parser.failure((FnCall)null); | 1038 : parser.failure((FnCall)null); |
996 } | 1039 } |
997 | 1040 |
998 private boolean args(In in,List<Expressions> builder) throws ParseException { | 1041 private boolean args(In in,List<ExpString> builder) throws ParseException { |
999 parser.begin(); | 1042 parser.begin(); |
1000 if( parser.match('(') ) { | 1043 if( parser.match('(') ) { |
1001 In inParens = in.parens(); | 1044 In inParens = in.parens(); |
1002 Spaces(inParens); | 1045 Spaces(inParens); |
1003 ExpList(inParens,builder); // optional | 1046 ExpList(inParens,builder); // optional |
1006 Spaces(in); | 1049 Spaces(in); |
1007 return parser.success(); | 1050 return parser.success(); |
1008 } | 1051 } |
1009 Expr exp = TableExpr(in); | 1052 Expr exp = TableExpr(in); |
1010 if( exp != null ) { | 1053 if( exp != null ) { |
1011 builder.add(exp); | 1054 builder.add(new ExpString(exp)); |
1012 return parser.success(); | 1055 return parser.success(); |
1013 } | 1056 } |
1014 String s = StringLiteral(in); | 1057 String s = StringLiteral(in); |
1015 if( s != null ) { | 1058 if( s != null ) { |
1016 builder.add( new ConstExpr(s) ); | 1059 builder.add( new ExpString(new ConstExpr(s)) ); |
1017 return parser.success(); | 1060 return parser.success(); |
1018 } | 1061 } |
1019 /* | 1062 /* |
1020 Expressions exps = TemplateExpressions(in); | 1063 Expressions exps = TemplateExpressions(in); |
1021 if( exps != null ) { | 1064 if( exps != null ) { |
1025 */ | 1068 */ |
1026 return parser.failure(); | 1069 return parser.failure(); |
1027 } | 1070 } |
1028 | 1071 |
1029 private Expressions ExpList(In in) throws ParseException { | 1072 private Expressions ExpList(In in) throws ParseException { |
1030 List<Expressions> builder = new ArrayList<Expressions>(); | 1073 List<ExpString> builder = new ArrayList<ExpString>(); |
1031 return ExpList(in,builder) ? ExpList.build(builder) : null; | 1074 return ExpList(in,builder) ? ExpList.build(expList(builder)) : null; |
1032 } | 1075 } |
1033 | 1076 |
1034 private boolean ExpList(In in,List<Expressions> builder) throws ParseException { | 1077 private ExpString ExpStringList(In in) throws ParseException { |
1078 List<ExpString> builder = new ArrayList<ExpString>(); | |
1079 return ExpList(in,builder) ? exp(builder) : null; | |
1080 } | |
1081 | |
1082 private boolean ExpList(In in,List<ExpString> builder) throws ParseException { | |
1035 parser.begin(); | 1083 parser.begin(); |
1036 Expressions exp = TemplateExpressions(in); | 1084 Expressions exp = TemplateExpressions(in); |
1037 if( exp != null ) { | 1085 if( exp != null ) { |
1038 builder.add(exp); | 1086 builder.add(new ExpString(exp)); |
1039 return parser.success(); | 1087 return parser.success(); |
1040 } | 1088 } |
1041 exp = exp(ExprZ(in)); | 1089 ExpString es = ExprZ(in); |
1042 if( exp==null ) | 1090 if( es==null ) |
1043 return parser.failure(); | 1091 return parser.failure(); |
1044 builder.add(exp); | 1092 builder.add(es); |
1045 while( parser.match(',') ) { | 1093 while( parser.match(',') ) { |
1046 Spaces(in); | 1094 Spaces(in); |
1047 exp = TemplateExpressions(in); | 1095 exp = TemplateExpressions(in); |
1048 if( exp != null ) { | 1096 if( exp != null ) { |
1049 builder.add(exp); | 1097 builder.add(new ExpString(exp)); |
1050 return parser.success(); | 1098 return parser.success(); |
1051 } | 1099 } |
1052 builder.add( exp(RequiredExpr(in)) ); | 1100 builder.add( RequiredExpr(in) ); |
1053 } | 1101 } |
1054 return parser.success(); | 1102 return parser.success(); |
1055 } | 1103 } |
1056 | 1104 |
1057 private Expr SubExpr(In in) throws ParseException { | 1105 private Expr SubExpr(In in) throws ParseException { |
1467 | 1515 |
1468 private static Expressions exp(ExpString expStr) { | 1516 private static Expressions exp(ExpString expStr) { |
1469 return expStr==null ? null : expStr.toExpressions(); | 1517 return expStr==null ? null : expStr.toExpressions(); |
1470 } | 1518 } |
1471 | 1519 |
1520 private ExpString exp(List<ExpString> list) { | |
1521 switch(list.size()) { | |
1522 case 0: | |
1523 return new ExpString("null",true,false); | |
1524 case 1: | |
1525 return list.get(0).expr(); | |
1526 default: | |
1527 int lastI = list.size() - 1; | |
1528 StringBuilder sb = new StringBuilder(); | |
1529 sb.append( "new Object[]{" ); | |
1530 for( int i=0; i<lastI; i++ ) { | |
1531 sb.append( list.get(i).expr().code ).append( ',' ); | |
1532 } | |
1533 ExpString last = list.get(lastI); | |
1534 if( last.isExpr ) { | |
1535 sb.append( last.code ).append( '}' ); | |
1536 return new ExpString(sb.toString(),false,false); | |
1537 } else { | |
1538 sb.append( '}' ); | |
1539 String s = "$Luan.concatArgs(" + sb + "," + last.code + ")"; | |
1540 return new ExpString(s,false,false); | |
1541 } | |
1542 } | |
1543 } | |
1544 | |
1545 private static List<Expressions> expList(List<ExpString> esList) { | |
1546 List<Expressions> list = new ArrayList<Expressions>(); | |
1547 for( ExpString es : esList ) { | |
1548 list.add(exp(es)); | |
1549 } | |
1550 return list; | |
1551 } | |
1472 | 1552 |
1473 private static class StmtString { | 1553 private static class StmtString { |
1474 final String code; | 1554 final String code; |
1475 | 1555 |
1476 StmtString(Stmt stmt) { | 1556 StmtString(Stmt stmt) { |
1479 code = "$Luan.getStmt(" + i + ").eval($luan);\n"; | 1559 code = "$Luan.getStmt(" + i + ").eval($luan);\n"; |
1480 } | 1560 } |
1481 | 1561 |
1482 StmtString(String code) { | 1562 StmtString(String code) { |
1483 this.code = code; | 1563 this.code = code; |
1564 if( code.contains("LuanParser") ) throw new RuntimeException("\n"+code); | |
1484 } | 1565 } |
1485 | 1566 |
1486 Stmt toStmt() { | 1567 Stmt toStmt() { |
1487 String className = "EXP" + ++classCounter; | 1568 String className = "EXP" + ++classCounter; |
1488 String classCode = "" | 1569 String classCode = "" |
1489 +"package luan.impl;\n" | 1570 +"package luan.impl;\n" |
1571 +"import luan.LuanFunction;\n" | |
1490 +"import luan.LuanException;\n" | 1572 +"import luan.LuanException;\n" |
1491 +"\n" | 1573 +"\n" |
1492 +"public class " + className +" implements Stmt {\n" | 1574 +"public class " + className +" implements Stmt {\n" |
1493 +" @Override public void eval(LuanStateImpl $luan) throws LuanException {\n" | 1575 +" @Override public void eval(LuanStateImpl $luan) throws LuanException {\n" |
1494 +" Object $cnd;\n" | 1576 +" Object $cnd;\n" |
1496 +" }\n" | 1578 +" }\n" |
1497 +"}\n" | 1579 +"}\n" |
1498 ; | 1580 ; |
1499 //System.out.println(code); | 1581 //System.out.println(code); |
1500 try { | 1582 try { |
1501 Class cls = LuanJavaCompiler.compile("luan.impl."+className,code,classCode); | 1583 Class cls = LuanJavaCompiler.compile("luan.impl."+className,"code",classCode); |
1502 return (Stmt)cls.newInstance(); | 1584 return (Stmt)cls.newInstance(); |
1503 } catch(ClassNotFoundException e) { | 1585 } catch(ClassNotFoundException e) { |
1504 throw new RuntimeException(e); | 1586 throw new RuntimeException(e); |
1505 } catch(InstantiationException e) { | 1587 } catch(InstantiationException e) { |
1506 throw new RuntimeException(e); | 1588 throw new RuntimeException(e); |
1518 | 1600 |
1519 private static StmtString stmtStr(Stmt stmt) { | 1601 private static StmtString stmtStr(Stmt stmt) { |
1520 return stmt==null ? null : new StmtString(stmt); | 1602 return stmt==null ? null : new StmtString(stmt); |
1521 } | 1603 } |
1522 | 1604 |
1605 | |
1606 private static class SettableString { | |
1607 final String code; | |
1608 | |
1609 SettableString(Settable settable) { | |
1610 if( settable==null ) throw new NullPointerException(); | |
1611 int i = $Luan.addSettable(settable); | |
1612 code = "$Luan.getSettable(" + i + ")"; | |
1613 } | |
1614 | |
1615 SettableString(String code) { | |
1616 this.code = code; | |
1617 } | |
1618 | |
1619 } | |
1620 | |
1523 } | 1621 } |