Mercurial Hosting > luan
view core/src/luan/impl/LuanParser.java @ 670:58ebfec6178b
all luan now compiles
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 12 Apr 2016 01:05:57 -0600 |
parents | e320488819b6 |
children | 82f130eba7b0 |
line wrap: on
line source
package luan.impl; import java.util.Set; import java.util.HashSet; import java.util.Arrays; import java.util.List; import java.util.ArrayList; import luan.Luan; import luan.LuanState; import luan.LuanTable; import luan.modules.PackageLuan; final class LuanParser { private interface Sym { public ExpString exp(); } private int symCounter = 0; private class LocalSym implements Sym { final String name; final String javaName; String pointer = null; LocalSym(String name) { this.name = name; this.javaName = name + "_" + (++symCounter); } String declaration() { if( pointer==null ) return "Object " + javaName + " = null;\n"; else return "final Pointer " + javaName + " = " + pointer + ";\n"; } String ref() { if( pointer==null ) return javaName; else return javaName + ".o"; } @Override public ExpString exp() { ExpString exp = new ExpString(true,false); exp.list.add( new Object() { @Override public String toString() { return ref(); } } ); return exp; } } private class UpSym implements Sym { final String name; final int i; final String value; UpSym(String name,int i,String value) { this.name = name; this.i = i; this.value = value; } String init() { return "upValues[" + i + "] = " + value + ";\n"; } String ref() { return "upValues[" + i + "].o"; } @Override public ExpString exp() { ExpString exp = new ExpString(true,false); exp.list.add( new Object() { @Override public String toString() { return ref(); } } ); return exp; } } private final class Frame { final Frame parent; final List<LocalSym> symbols = new ArrayList<LocalSym>(); int loops = 0; boolean isVarArg = false; final List<UpSym> upValueSymbols = new ArrayList<UpSym>(); Frame() { this.parent = null; } Frame(Frame parent) { this.parent = parent; } LocalSym addLocalSym(String name) { LocalSym sym = new LocalSym(name); symbols.add(sym); return sym; } UpSym addUpSym(String name,String value) { UpSym sym = new UpSym( name, upValueSymbols.size(), value ); upValueSymbols.add(sym); return sym; } LocalSym getLocalSym(String name) { int i = symbols.size(); while( --i >= 0 ) { LocalSym sym = symbols.get(i); if( sym.name.equals(name) ) return sym; } return null; } UpSym getUpSym(String name) { for( UpSym upSym : upValueSymbols ) { if( upSym.name.equals(name) ) return upSym; } for( Frame f=parent; f!=null; f=f.parent ) { LocalSym sym = f.getLocalSym(name); if( sym != null ) { sym.pointer = "new Pointer()"; return addUpSym(name,sym.javaName); } } return null; } Sym getSym(String name) { Sym sym = getLocalSym(name); return sym != null ? sym : getUpSym(name); } } private static class In { static final In NOTHING = new In(false,false); final boolean parens; final boolean template; private In(boolean parens,boolean template) { this.parens = parens; this.template = template; } In parens() { return parens ? this : new In(true,false); } In template() { return template ? this : new In(false,true); } } // final LuanSource source; private Frame frame; private final Parser parser; private final StmtString top = new StmtString(); LuanParser(String sourceName,String sourceText) { // this.source = source; this.frame = new Frame(); this.parser = new Parser(sourceName,sourceText); } void addVar(String name) { UpSym upSym = frame.addUpSym( "-ADDED-" ,"new Pointer()"); if( name != null ) { LocalSym sym = frame.addLocalSym( name ); sym.pointer = "upValues[" + upSym.i + "]"; top.list.add( sym.declaration() ); } } private int symbolsSize() { return frame.symbols.size(); } private void addSymbol(String name,StmtString stmt) { final LocalSym sym = frame.addLocalSym(name); stmt.list.add( new Object() { @Override public String toString() { return sym.declaration(); } } ); } private void addSymbols(List<String> names,StmtString stmt) { for( String name : names ) { addSymbol(name,stmt); } } private Sym getSym(String name) { return frame.getSym(name); } private void popSymbols(int n) { List<LocalSym> symbols = frame.symbols; while( n-- > 0 ) { symbols.remove(symbols.size()-1); } } private void incLoops() { frame.loops++; } private void decLoops() { frame.loops--; } private <T> T required(T t) throws ParseException { if( t==null ) throw parser.exception(); return t; } private <T> T required(T t,String msg) throws ParseException { if( t==null ) throw parser.exception(msg); return t; } private static Expr expr(Expressions exprs) { if( exprs==null ) return null; if( exprs instanceof Expr ) return (Expr)exprs; return new ExpressionsExpr(exprs); } private Class newFnClass(int start,StmtString stmt) { if( !stmt.hasReturn ) stmt.list.add( "return LuanFunction.NOTHING;\n" ); return toFnClass( stmt, frame.upValueSymbols ); } private ExpString newFnExpStr(int start,StmtString stmt) { if( !stmt.hasReturn ) stmt.list.add( "return LuanFunction.NOTHING;\n" ); return toFnExpStr( stmt, frame.upValueSymbols ); } Class Expression() throws ParseException { Spaces(In.NOTHING); int start = parser.begin(); ExpString expr = ExprZ(In.NOTHING); if( expr != null && parser.endOfInput() ) { top.list.add( "return " ); top.list.addAll( expr.list ); top.list.add( ";\n" ); top.hasReturn = true; return parser.success(newFnClass(start,top)); } return parser.failure(null); } Class RequiredModule() throws ParseException { Spaces(In.NOTHING); int start = parser.begin(); frame.isVarArg = true; top.list.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);\n" ); StmtString block = RequiredBlock(); top.list.addAll( block.list ); top.hasReturn = block.hasReturn; if( parser.endOfInput() ) return parser.success(newFnClass(start,top)); throw parser.exception(); } private StmtString RequiredBlock() throws ParseException { StmtString stmts = new StmtString(); int stackStart = symbolsSize(); boolean isReturn = Stmt(stmts); while( !isReturn && StmtSep(stmts) ) { Spaces(In.NOTHING); isReturn = Stmt(stmts); } while( StmtSep(null) ) Spaces(In.NOTHING); int stackEnd = symbolsSize(); popSymbols( stackEnd - stackStart ); stmts.hasReturn = isReturn; return stmts; } private boolean StmtSep(StmtString stmts) throws ParseException { parser.begin(); if( parser.match( ';' ) ) return parser.success(); if( EndOfLine() ) return parser.success(); if( stmts != null ) { // parser.rollback(); StmtString stmt = TemplateStmt(); if( stmt != null ) { stmts.list.addAll(stmt.list); return parser.success(); } } return parser.failure(); } private boolean EndOfLine() { return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); } private boolean Stmt(StmtString stmts) throws ParseException { StmtString stmt; if( (stmt=ReturnStmt()) != null ) { stmts.list.addAll(stmt.list); return true; } if( (stmt=FunctionStmt()) != null || (stmt=LocalStmt()) != null || (stmt=LocalFunctionStmt()) != null || (stmt=BreakStmt()) != null || (stmt=ForStmt()) != null || (stmt=DoStmt()) != null || (stmt=WhileStmt()) != null || (stmt=RepeatStmt()) != null || (stmt=IfStmt()) != null || (stmt=SetStmt()) != null || (stmt=ExpressionsStmt()) != null ) { stmts.list.addAll(stmt.list); } return false; } private ExpString indexExpStr(ExpString exp1,ExpString exp2) { ExpString exp = new ExpString(true,false); exp.list.add( "luan.index(" ); exp.list.addAll( exp1.expr().list ); exp.list.add( "," ); exp.list.addAll( exp2.expr().list ); exp.list.add( ")" ); return exp; } private ExpString callExpStr(ExpString fn,ExpString args) { ExpString exp = new ExpString(false,true); exp.list.add( "Luan.checkFunction(" ); exp.list.addAll( fn.expr().list ); exp.list.add( ").call(luan,Luan.array(" ); exp.list.addAll( args.list ); exp.list.add( "))" ); return exp; } private StmtString TemplateStmt() throws ParseException { ExpString exprs = TemplateExpressions(In.NOTHING); if( exprs == null ) return null; ExpString requireCall = new ExpString(true,false); requireCall.list.add( "PackageLuan.require(luan,\"luan:Io\")" ); ExpString stdoutExp = indexExpStr( requireCall.expr(), constExpStr("stdout") ); ExpString writeExp = indexExpStr( stdoutExp, constExpStr("write") ); ExpString writeCall = callExpStr( writeExp, exprs ); StmtString stmt = new StmtString(); stmt.list.addAll( writeCall.list ); stmt.list.add( ";\n" ); return stmt; } private ExpString TemplateExpressions(In in) throws ParseException { if( in.template ) return null; int start = parser.begin(); if( !parser.match( "%>" ) ) return parser.failure(null); EndOfLine(); In inTemplate = in.template(); List<ExpString> builder = new ArrayList<ExpString>(); while(true) { if( parser.match( "<%=" ) ) { Spaces(inTemplate); builder.add( RequiredExpr(inTemplate) ); RequiredMatch( "%>" ); } else if( parser.match( "<%" ) ) { Spaces(inTemplate); return parser.success(expString(builder)); } else { int i = parser.currentIndex(); do { if( parser.match( "%>" ) ) throw parser.exception("'%>' unexpected"); if( !parser.anyChar() ) throw parser.exception("Unclosed template expression"); } while( !parser.test( "<%" ) ); String match = parser.textFrom(i); builder.add( constExpStr(match) ); } } } private StmtString ReturnStmt() throws ParseException { parser.begin(); if( !Keyword("return",In.NOTHING) ) return parser.failure(null); ExpString exprs = ExpStringList(In.NOTHING); StmtString stmt = new StmtString(); stmt.list.add( "return " ); if( exprs != null ) stmt.list.addAll( exprs.list ); else stmt.list.add( "LuanFunction.NOTHING" ); stmt.list.add( ";\n" ); return parser.success( stmt ); } private StmtString FunctionStmt() throws ParseException { parser.begin(); if( !Keyword("function",In.NOTHING) ) return parser.failure(null); parser.currentIndex(); Var var = nameVar(RequiredName(In.NOTHING)); while( parser.match( '.' ) ) { Spaces(In.NOTHING); ExpString exp = NameExpr(In.NOTHING); if( exp==null ) return parser.failure(null); var = indexVar( var.exp(), exp ); } ExpString fnDef = RequiredFunction(In.NOTHING); return parser.success( var.set(fnDef) ); } private StmtString LocalFunctionStmt() throws ParseException { parser.begin(); if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) ) return parser.failure(null); StmtString stmt = new StmtString(); String name = RequiredName(In.NOTHING); addSymbol( name, stmt ); ExpString fnDef = RequiredFunction(In.NOTHING); stmt.list.addAll( nameVar(name).set( fnDef ).list ); /* Settable s = new SetLocalVar(symbolsSize()-1); StmtString stmt = new StmtString(); stmt.list.add( settableToString(s) ); stmt.list.add( ".set(luan," ); stmt.list.addAll( fnDef.list ); stmt.list.add( ");\n" ); */ return parser.success( stmt ); } private StmtString BreakStmt() throws ParseException { parser.begin(); if( !Keyword("break",In.NOTHING) ) return parser.failure(null); if( frame.loops <= 0 ) throw parser.exception("'break' outside of loop"); StmtString stmt = new StmtString(); stmt.list.add( "break;\n" ); return parser.success( stmt ); } int forCounter = 0; private StmtString ForStmt() throws ParseException { parser.begin(); int stackStart = symbolsSize(); if( !Keyword("for",In.NOTHING) ) return parser.failure(null); List<String> names = RequiredNameList(In.NOTHING); if( !Keyword("in",In.NOTHING) ) return parser.failure(null); ExpString expr = RequiredExpr(In.NOTHING).expr(); RequiredKeyword("do",In.NOTHING); String fnVar = "fn"+ ++forCounter; ExpString fnExp = new ExpString(false,false); fnExp.list.add( fnVar + ".call(luan)" ); StmtString stmt = new StmtString(); stmt.list.add( "" +"LuanFunction "+fnVar+" = Luan.checkFunction(" ); stmt.list.addAll( expr.list ); stmt.list.add( ");\n" ); stmt.list.add( "while(true) {\n" ); List<Var> vars = new ArrayList<Var>(); for( String name : names ) { addSymbol(name, stmt); vars.add(nameVar(name)); } ExpString firstVar = vars.get(0).exp(); stmt.list.addAll( makeSetStmt(vars,fnExp).list ); stmt.list.add( "if( " ); stmt.list.addAll( firstVar.list ); stmt.list.add( "==null ) break;\n" ); StmtString loop = RequiredLoopBlock(); RequiredKeyword("end",In.NOTHING); stmt.list.addAll( loop.list ); stmt.list.add( "}\n" ); popSymbols( symbolsSize() - stackStart ); return parser.success(stmt); } private StmtString DoStmt() throws ParseException { parser.begin(); if( !Keyword("do",In.NOTHING) ) return parser.failure(null); StmtString stmt = RequiredBlock(); RequiredKeyword("end",In.NOTHING); return parser.success(stmt); } private StmtString LocalStmt() throws ParseException { parser.begin(); if( !Keyword("local",In.NOTHING) ) return parser.failure(null); List<String> names = NameList(In.NOTHING); if( names==null ) { if( Keyword("function",In.NOTHING) ) return parser.failure(null); // handled later throw parser.exception("Invalid local statement"); } StmtString stmt = new StmtString(); addSymbols(names,stmt); if( parser.match( '=' ) ) { Spaces(In.NOTHING); ExpString values = ExpStringList(In.NOTHING); if( values==null ) throw parser.exception("Expressions expected"); List<Var> vars = new ArrayList<Var>(); for( String name : names ) { vars.add(nameVar(name)); } stmt.list.addAll( makeSetStmt(vars,values).list ); } return parser.success(stmt); } private List<String> RequiredNameList(In in) throws ParseException { parser.begin(); List<String> names = NameList(in); if( names==null ) throw parser.exception("Name expected"); return parser.success(names); } private List<String> NameList(In in) throws ParseException { String name = Name(in); if( name==null ) return null; List<String> names = new ArrayList<String>(); names.add(name); while( (name=anotherName(in)) != null ) { names.add(name); } return names; } private String anotherName(In in) throws ParseException { parser.begin(); if( !parser.match( ',' ) ) return parser.failure(null); Spaces(in); String name = Name(in); if( name==null ) return parser.failure(null); return parser.success(name); } private StmtString WhileStmt() throws ParseException { parser.begin(); if( !Keyword("while",In.NOTHING) ) return parser.failure(null); ExpString cnd = RequiredExpr(In.NOTHING).expr(); RequiredKeyword("do",In.NOTHING); StmtString loop = RequiredLoopBlock(); RequiredKeyword("end",In.NOTHING); StmtString stmt = new StmtString(); stmt.list.add( "while( Luan.checkBoolean(" ); stmt.list.addAll( cnd.list ); stmt.list.add( ") ) {\n" ); stmt.list.addAll( loop.list ); stmt.list.add( "}\n" ); return parser.success( stmt ); } private StmtString RepeatStmt() throws ParseException { parser.begin(); if( !Keyword("repeat",In.NOTHING) ) return parser.failure(null); StmtString loop =RequiredLoopBlock(); RequiredKeyword("until",In.NOTHING); ExpString cnd = RequiredExpr(In.NOTHING).expr(); StmtString stmt = new StmtString(); stmt.list.add( "do {\n" ); stmt.list.addAll( loop.list ); stmt.list.add( "} while( !Luan.checkBoolean(" ); stmt.list.addAll( cnd.list ); stmt.list.add( ") );\n" ); return parser.success( stmt ); } private StmtString RequiredLoopBlock() throws ParseException { incLoops(); StmtString stmt = RequiredBlock(); decLoops(); return stmt; } private StmtString IfStmt() throws ParseException { parser.begin(); if( !Keyword("if",In.NOTHING) ) return parser.failure(null); StmtString stmt = new StmtString(); ExpString cnd; StmtString block; cnd = RequiredExpr(In.NOTHING).expr(); RequiredKeyword("then",In.NOTHING); block = RequiredBlock(); stmt.list.add( "if( Luan.checkBoolean(" ); stmt.list.addAll( cnd.list ); stmt.list.add( ") ) {\n" ); stmt.list.addAll( block.list ); while( Keyword("elseif",In.NOTHING) ) { cnd = RequiredExpr(In.NOTHING).expr(); RequiredKeyword("then",In.NOTHING); block = RequiredBlock(); stmt.list.add( "} else if( Luan.checkBoolean(" ); stmt.list.addAll( cnd.list ); stmt.list.add( ") ) {\n" ); stmt.list.addAll( block.list ); } if( Keyword("else",In.NOTHING) ) { block = RequiredBlock(); stmt.list.add( "} else {\n" ); stmt.list.addAll( block.list ); } RequiredKeyword("end",In.NOTHING); stmt.list.add( "}\n" ); return parser.success( stmt ); } private StmtString SetStmt() throws ParseException { parser.begin(); List<Var> vars = new ArrayList<Var>(); Var v = SettableVar(); if( v == null ) return parser.failure(null); vars.add(v); while( parser.match( ',' ) ) { Spaces(In.NOTHING); v = SettableVar(); if( v == null ) return parser.failure(null); vars.add(v); } if( !parser.match( '=' ) ) return parser.failure(null); Spaces(In.NOTHING); ExpString values = ExpStringList(In.NOTHING); if( values==null ) // throw parser.exception("Expressions expected"); return parser.failure(null); return parser.success( makeSetStmt(vars,values) ); } private StmtString makeSetStmt(List<Var> vars,ExpString values) throws ParseException { int n = vars.size(); if( n == 1 ) return vars.get(0).set(values); StmtString stmt = new StmtString(); stmt.list.add( "t = " ); stmt.list.addAll( values.list ); stmt.list.add( ";\n" ); ExpString t = new ExpString(values.isExpr,false); t.list.add( "t" ); stmt.list.addAll( vars.get(0).set(t).list ); for( int i=1; i<n; i++ ) { t.list.clear(); t.list.add( "LuanImpl.pick(t,"+i+")" ); stmt.list.addAll( vars.get(i).set(t).list ); } return stmt; } /* private static String varsToString(Settable[] vars) { StringBuilder sb = new StringBuilder(); sb.append( "new Settable[]{" ); for( Settable v : vars ) { sb.append( settableToString(v) ).append( ',' ); } sb.append( "}" ); return sb.toString(); } */ private StmtString ExpressionsStmt() throws ParseException { parser.begin(); ExpString exp = ExprZ(In.NOTHING); if( exp != null && exp.isStmt ) { StmtString stmt = new StmtString(); if( exp.isExpr ) { stmt.list.add( "LuanImpl.nop(" ); stmt.list.addAll( exp.list ); stmt.list.add( ")" ); } else { stmt.list.addAll( exp.list ); } stmt.list.add( ";\n" ); return parser.success( stmt ); } return parser.failure(null); } private Var SettableVar() throws ParseException { int start = parser.begin(); Var var = VarZ(In.NOTHING); if( var==null || !var.isSettable() ) return parser.failure(null); return parser.success( var ); } private ExpString RequiredExpr(In in) throws ParseException { parser.begin(); return parser.success(required(ExprZ(in),"Bad expression")); } private ExpString ExprZ(In in) throws ParseException { return OrExpr(in); } private ExpString OrExpr(In in) throws ParseException { parser.begin(); ExpString exp = AndExpr(in); if( exp==null ) return parser.failure(null); while( Keyword("or",in) ) { exp = exp.expr(); ExpString exp2 = required(RelExpr(in)).expr(); ExpString newExp = new ExpString(true,true); newExp.list.add( "(LuanImpl.cnd(t = " ); newExp.list.addAll( exp.list ); newExp.list.add( ") ? t : (" ); newExp.list.addAll( exp2.list ); newExp.list.add( "))" ); exp = newExp; } return parser.success(exp); } private ExpString AndExpr(In in) throws ParseException { parser.begin(); ExpString exp = RelExpr(in); if( exp==null ) return parser.failure(null); while( Keyword("and",in) ) { exp = exp.expr(); ExpString exp2 = required(RelExpr(in)).expr(); ExpString newExp = new ExpString(true,true); newExp.list.add( "(LuanImpl.cnd(t = " ); newExp.list.addAll( exp.list ); newExp.list.add( ") ? (" ); newExp.list.addAll( exp2.list ); newExp.list.add( ") : t)" ); exp = newExp; } return parser.success(exp); } private ExpString RelExpr(In in) throws ParseException { parser.begin(); ExpString exp = ConcatExpr(in); if( exp==null ) return parser.failure(null); while(true) { if( parser.match("==") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.eq(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match("~=") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "!LuanImpl.eq(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match("<=") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.le(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match(">=") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.le(luan," ); newExp.list.addAll( exp2.list ); newExp.list.add( "," ); newExp.list.addAll( exp.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match("<") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.lt(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match(">") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.lt(luan," ); newExp.list.addAll( exp2.list ); newExp.list.add( "," ); newExp.list.addAll( exp.list ); newExp.list.add( ")" ); exp = newExp; } else break; } return parser.success(exp); } private ExpString ConcatExpr(In in) throws ParseException { parser.begin(); ExpString exp = SumExpr(in); if( exp==null ) return parser.failure(null); if( parser.match("..") ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(ConcatExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.concat(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } return parser.success(exp); } private ExpString SumExpr(In in) throws ParseException { parser.begin(); ExpString exp = TermExpr(in); if( exp==null ) return parser.failure(null); while(true) { if( parser.match('+') ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(TermExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.add(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( Minus() ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(TermExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.sub(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else break; } return parser.success(exp); } private boolean Minus() { parser.begin(); return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure(); } private ExpString TermExpr(In in) throws ParseException { parser.begin(); ExpString exp = UnaryExpr(in); if( exp==null ) return parser.failure(null); while(true) { if( parser.match('*') ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.mul(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( parser.match('/') ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.div(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else if( Mod() ) { Spaces(in); exp = exp.expr(); ExpString exp2 = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.mod(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( exp2.list ); newExp.list.add( ")" ); exp = newExp; } else break; } return parser.success(exp); } private boolean Mod() { parser.begin(); return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure(); } private ExpString UnaryExpr(In in) throws ParseException { parser.begin(); if( parser.match('#') ) { Spaces(in); ExpString exp = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.len(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( ")" ); return parser.success(newExp); } if( Minus() ) { Spaces(in); ExpString exp = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.unm(luan," ); newExp.list.addAll( exp.list ); newExp.list.add( ")" ); return parser.success(newExp); } if( Keyword("not",in) ) { Spaces(in); ExpString exp = required(UnaryExpr(in)).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "!Luan.checkBoolean(" ); newExp.list.addAll( exp.list ); newExp.list.add( ")" ); return parser.success(newExp); } ExpString exp = PowExpr(in); if( exp==null ) return parser.failure(null); return parser.success(exp); } private ExpString PowExpr(In in) throws ParseException { parser.begin(); ExpString exp1 = SingleExpr(in); if( exp1==null ) return parser.failure(null); if( parser.match('^') ) { Spaces(in); ExpString exp2 = required(PowExpr(in)); ExpString newExp = new ExpString(true,false); newExp.list.add( "LuanImpl.pow(luan," ); newExp.list.addAll( exp1.expr().list ); newExp.list.add( "," ); newExp.list.addAll( exp2.expr().list ); newExp.list.add( ")" ); exp1 = newExp; } return parser.success(exp1); } private ExpString SingleExpr(In in) throws ParseException { parser.begin(); ExpString exp = FunctionExpr(in); if( exp != null ) return parser.success(exp); exp = VarExp(in); if( exp != null ) return parser.success(exp); exp = VarArgs(in); if( exp != null ) return parser.success(exp); return parser.failure(null); } private ExpString FunctionExpr(In in) throws ParseException { if( !Keyword("function",in) ) return null; return RequiredFunction(in); } private ExpString RequiredFunction(In in) throws ParseException { int start = parser.begin(); RequiredMatch('('); In inParens = in.parens(); Spaces(inParens); frame = new Frame(frame); StmtString stmt = new StmtString(); List<String> names = NameList(in); if( names != null ) { addSymbols(names,stmt); List<Var> vars = new ArrayList<Var>(); for( String name : names ) { vars.add(nameVar(name)); } ExpString args = new ExpString(false,false); args.list.add( "args" ); stmt.list.addAll( makeSetStmt(vars,args).list ); if( parser.match(',') ) { Spaces(inParens); if( !parser.match("...") ) throw parser.exception(); Spaces(inParens); frame.isVarArg = true; stmt.list.add( "final Object[] varArgs = LuanImpl.varArgs(args," + vars.size() + ");\n" ); } } else if( parser.match("...") ) { Spaces(inParens); frame.isVarArg = true; stmt.list.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);\n" ); } RequiredMatch(')'); Spaces(in); StmtString block = RequiredBlock(); stmt.list.addAll( block.list ); stmt.hasReturn = block.hasReturn; RequiredKeyword("end",in); ExpString fnDef = newFnExpStr(start,stmt); frame = frame.parent; return parser.success(fnDef); } private ExpString VarArgs(In in) throws ParseException { parser.begin(); if( !frame.isVarArg || !parser.match("...") ) return parser.failure(null); Spaces(in); ExpString exp = new ExpString(false,false); exp.list.add("varArgs"); return parser.success(exp); } private ExpString TableExpr(In in) throws ParseException { parser.begin(); if( !parser.match('{') ) return parser.failure(null); Spaces(In.NOTHING); List<ExpString> builder = new ArrayList<ExpString>(); Field(builder); while( FieldSep() ) { Spaces(In.NOTHING); Field(builder); } ExpString exp = TemplateExpressions(In.NOTHING); if( exp != null ) builder.add(exp); if( !parser.match('}') ) throw parser.exception("Expected table element or '}'"); Spaces(in); exp = new ExpString(true,false); exp.list.add( "LuanImpl.table(" ); exp.list.addAll( expString(builder).list ); exp.list.add( ")" ); return parser.success( exp ); } private boolean FieldSep() throws ParseException { return parser.anyOf(",;") || EndOfLine(); } private boolean Field(List<ExpString> builder) throws ParseException { parser.begin(); ExpString exp = SubExpr(In.NOTHING); if( exp==null ) exp = NameExpr(In.NOTHING); if( exp!=null && parser.match('=') ) { Spaces(In.NOTHING); ExpString val = RequiredExpr(In.NOTHING).expr(); ExpString newExp = new ExpString(true,false); newExp.list.add( "new TableField(" ); newExp.list.addAll( exp.list ); newExp.list.add( "," ); newExp.list.addAll( val.list ); newExp.list.add( ")" ); builder.add( newExp ); return parser.success(); } parser.rollback(); ExpString exprs = ExprZ(In.NOTHING); if( exprs != null ) { builder.add(exprs); return parser.success(); } return parser.failure(); } private ExpString VarExp(In in) throws ParseException { Var var = VarZ(in); return var==null ? null : var.exp(); } private Var VarZ(In in) throws ParseException { parser.begin(); Var var = VarStart(in); if( var==null ) return parser.failure(null); Var var2; while( (var2=Var2(in,var.exp())) != null ) { var = var2; } return parser.success(var); } private Var VarStart(In in) throws ParseException { if( parser.match('(') ) { In inParens = in.parens(); Spaces(inParens); ExpString exp = RequiredExpr(inParens).expr(); RequiredMatch(')'); Spaces(in); return exprVar(exp); } String name = Name(in); if( name != null ) return nameVar(name); ExpString exp; exp = TableExpr(in); if( exp != null ) return exprVar(exp); exp = Literal(in); if( exp != null ) return exprVar(exp); return null; } private Var Var2(In in,ExpString exp1) throws ParseException { parser.begin(); ExpString exp2 = SubExpr(in); if( exp2 != null ) return parser.success(indexVar(exp1,exp2)); if( parser.match('.') ) { Spaces(in); exp2 = NameExpr(in); if( exp2!=null ) return parser.success(indexVar(exp1,exp2)); return parser.failure(null); } ExpString fnCall = Args( in, exp1, new ArrayList<ExpString>() ); if( fnCall != null ) return parser.success(exprVar(fnCall)); return parser.failure(null); } private interface Var { public ExpString exp() throws ParseException; // public Settable settable() throws ParseException; public boolean isSettable(); public StmtString set(ExpString val) throws ParseException; } private ExpString env() { Sym sym = getSym("_ENV"); if( sym != null ) return sym.exp(); return null; } private Var nameVar(final String name) { return new Var() { public ExpString exp() throws ParseException { Sym sym = getSym(name); if( sym != null ) return sym.exp(); ExpString envExpr = env(); if( envExpr != null ) return indexExpStr( envExpr, constExpStr(name) ); parser.failure(null); throw parser.exception("name '"+name+"' not defined"); } public boolean isSettable() { return true; } /* private Settable settable() throws ParseException { int index = stackIndex(name); if( index != -1 ) return new SetLocalVar(index); index = upValueIndex(name); if( index != -1 ) return new SetUpVar(index); Expr envExpr = env(); if( envExpr != null ) return new SetTableEntry( envExpr, new ConstExpr(name) ); parser.failure(null); throw parser.exception("name '"+name+"' not defined"); } */ public StmtString set(ExpString val) throws ParseException { Sym sym = getSym(name); if( sym != null ) { StmtString stmt = new StmtString(); stmt.list.addAll( sym.exp().list ); stmt.list.add( " = " ); stmt.list.addAll( val.expr().list ); stmt.list.add( ";\n" ); return stmt; } ExpString envExpr = env(); if( envExpr != null ) return indexVar( envExpr, constExpStr(name) ).set(val); throw new RuntimeException(); } }; } private Var exprVar(final ExpString expr) { return new Var() { public ExpString exp() { return expr; } public boolean isSettable() { return false; } public StmtString set(ExpString val) { throw new RuntimeException(); } }; } private Var indexVar(final ExpString table,final ExpString key) { return new Var() { public ExpString exp() { return indexExpStr( table, key ); } public boolean isSettable() { return true; } /* public Settable settable() { return new SetTableEntry(expr(LuanParser.exp(table)),expr(LuanParser.exp(key))); } */ public StmtString set(ExpString val) { StmtString stmt = new StmtString(); stmt.list.add( "LuanImpl.put(luan," ); stmt.list.addAll( table.expr().list ); stmt.list.add( "," ); stmt.list.addAll( key.expr().list ); stmt.list.add( "," ); stmt.list.addAll( val.expr().list ); stmt.list.add( ");\n" ); return stmt; } }; } private ExpString Args(In in,ExpString fn,List<ExpString> builder) throws ParseException { parser.begin(); return args(in,builder) ? parser.success( callExpStr( fn, expString(builder) ) ) : parser.failure((ExpString)null); } private boolean args(In in,List<ExpString> builder) throws ParseException { parser.begin(); if( parser.match('(') ) { In inParens = in.parens(); Spaces(inParens); ExpList(inParens,builder); // optional if( !parser.match(')') ) throw parser.exception("Expression or ')' expected"); Spaces(in); return parser.success(); } ExpString exp = TableExpr(in); if( exp != null ) { builder.add(exp); return parser.success(); } String s = StringLiteral(in); if( s != null ) { builder.add( constExpStr(s) ); return parser.success(); } /* Expressions exps = TemplateExpressions(in); if( exps != null ) { builder.add(exps); return parser.success(); } */ return parser.failure(); } private ExpString ExpStringList(In in) throws ParseException { List<ExpString> builder = new ArrayList<ExpString>(); return ExpList(in,builder) ? expString(builder) : null; } private boolean ExpList(In in,List<ExpString> builder) throws ParseException { parser.begin(); ExpString exp = TemplateExpressions(in); if( exp != null ) { builder.add(exp); return parser.success(); } exp = ExprZ(in); if( exp==null ) return parser.failure(); builder.add(exp); while( parser.match(',') ) { Spaces(in); exp = TemplateExpressions(in); if( exp != null ) { builder.add(exp); return parser.success(); } builder.add( RequiredExpr(in) ); } return parser.success(); } private ExpString SubExpr(In in) throws ParseException { parser.begin(); if( !parser.match('[') || parser.test("[") || parser.test("=") ) return parser.failure(null); Spaces(In.NOTHING); ExpString exp = RequiredExpr(In.NOTHING).expr(); RequiredMatch(']'); Spaces(in); return parser.success(exp); } private ExpString NameExpr(In in) throws ParseException { parser.begin(); String name = Name(in); if( name==null ) return parser.failure(null); return parser.success(constExpStr(name)); } private String RequiredName(In in) throws ParseException { parser.begin(); String name = Name(in); if( name==null ) throw parser.exception("Name expected"); return parser.success(name); } private String Name(In in) throws ParseException { int start = parser.begin(); if( !NameFirstChar() ) return parser.failure(null); while( NameChar() ); String match = parser.textFrom(start); if( keywords.contains(match) ) return parser.failure(null); Spaces(in); return parser.success(match); } private boolean NameChar() { return NameFirstChar() || Digit(); } private boolean NameFirstChar() { return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_'); } private void RequiredMatch(char c) throws ParseException { if( !parser.match(c) ) throw parser.exception("'"+c+"' expected"); } private void RequiredMatch(String s) throws ParseException { if( !parser.match(s) ) throw parser.exception("'"+s+"' expected"); } private void RequiredKeyword(String keyword,In in) throws ParseException { if( !Keyword(keyword,in) ) throw parser.exception("'"+keyword+"' expected"); } private boolean Keyword(String keyword,In in) throws ParseException { parser.begin(); if( !parser.match(keyword) || NameChar() ) return parser.failure(); Spaces(in); return parser.success(); } private static final Set<String> keywords = new HashSet<String>(Arrays.asList( "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" )); private ExpString Literal(In in) throws ParseException { parser.begin(); if( NilLiteral(in) ) { ExpString exp = new ExpString(true,false); exp.list.add( "null" ); return parser.success(exp); } Boolean b = BooleanLiteral(in); if( b != null ) { ExpString exp = new ExpString(true,false); exp.list.add( b.toString() ); return parser.success(exp); } Number n = NumberLiteral(in); if( n != null ) { String s = n.toString(); if( n instanceof Long ) s += "L"; ExpString exp = new ExpString(true,false); exp.list.add( s ); return parser.success(exp); } String s = StringLiteral(in); if( s != null ) return parser.success(constExpStr(s)); return parser.failure(null); } private ExpString constExpStr(String s) { s = s .replace("\\","\\\\") .replace("\"","\\\"") .replace("\n","\\n") .replace("\r","\\r") .replace("\t","\\t") .replace("\b","\\b") ; ExpString exp = new ExpString(true,false); exp.list.add( "\""+s+"\"" ); return exp; } private boolean NilLiteral(In in) throws ParseException { return Keyword("nil",in); } private Boolean BooleanLiteral(In in) throws ParseException { if( Keyword("true",in) ) return true; if( Keyword("false",in) ) return false; return null; } private Number NumberLiteral(In in) throws ParseException { parser.begin(); Number n; if( parser.matchIgnoreCase("0x") ) { n = HexNumber(); } else { n = DecNumber(); } if( n==null || NameChar() ) return parser.failure(null); Spaces(in); return parser.success(n); } private Number DecNumber() { int start = parser.begin(); boolean isInt = true; if( Int() ) { if( parser.match('.') ) { isInt = false; Int(); // optional } } else if( parser.match('.') && Int() ) { // ok isInt = false; } else return parser.failure(null); if( Exponent() ) // optional isInt = false; String s = parser.textFrom(start); if( isInt ) { try { return parser.success(Integer.valueOf(s)); } catch(NumberFormatException e) {} try { return parser.success(Long.valueOf(s)); } catch(NumberFormatException e) {} } return parser.success(Double.valueOf(s)); } private boolean Exponent() { parser.begin(); if( !parser.matchIgnoreCase("e") ) return parser.failure(); parser.anyOf("+-"); // optional if( !Int() ) return parser.failure(); return parser.success(); } private boolean Int() { if( !Digit() ) return false; while( Digit() ); return true; } private boolean Digit() { return parser.inCharRange('0', '9'); } private Number HexNumber() { int start = parser.begin(); long nLong = 0; double n; if( HexInt() ) { nLong = Long.parseLong(parser.textFrom(start),16); n = (double)nLong; if( parser.match('.') ) { start = parser.currentIndex(); if( HexInt() ) { String dec = parser.textFrom(start); n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); } } } else if( parser.match('.') && HexInt() ) { String dec = parser.textFrom(start+1); n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); } else { return parser.failure(null); } if( parser.matchIgnoreCase("p") ) { parser.anyOf("+-"); // optional start = parser.currentIndex(); if( !HexInt() ) return parser.failure(null); n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start))); } if( nLong == n ) { int nInt = (int)nLong; if( nInt == nLong ) return parser.success(Integer.valueOf(nInt)); return parser.success(Long.valueOf(nLong)); } return parser.success(Double.valueOf(n)); } private boolean HexInt() { if( !HexDigit() ) return false; while( HexDigit() ); return true; } private boolean HexDigit() { return Digit() || parser.anyOf("abcdefABCDEF"); } private String StringLiteral(In in) throws ParseException { String s; if( (s=QuotedString('"'))==null && (s=QuotedString('\''))==null && (s=LongString())==null ) return null; Spaces(in); return s; } private String LongString() throws ParseException { parser.begin(); if( !parser.match('[') ) return parser.failure(null); int start = parser.currentIndex(); while( parser.match('=') ); int nEquals = parser.currentIndex() - start; if( !parser.match('[') ) return parser.failure(null); EndOfLine(); start = parser.currentIndex(); while( !LongBracketsEnd(nEquals) ) { if( !parser.anyChar() ) throw parser.exception("Unclosed long string"); } String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 ); return parser.success(s); } private String QuotedString(char quote) throws ParseException { parser.begin(); if( !parser.match(quote) ) return parser.failure(null); StringBuilder buf = new StringBuilder(); while( !parser.match(quote) ) { Character c = EscSeq(); if( c != null ) { buf.append(c); } else { if( parser.test('\r') || parser.test('\n') || !parser.anyChar() ) throw parser.exception("Unclosed string"); buf.append(parser.lastChar()); } } return parser.success(buf.toString()); } private Character EscSeq() { parser.begin(); if( !parser.match('\\') ) return parser.failure(null); if( parser.match('a') ) return parser.success('\u0007'); if( parser.match('b') ) return parser.success('\b'); if( parser.match('f') ) return parser.success('\f'); if( parser.match('n') ) return parser.success('\n'); if( parser.match('r') ) return parser.success('\r'); if( parser.match('t') ) return parser.success('\t'); if( parser.match('v') ) return parser.success('\u000b'); if( parser.match('\\') ) return parser.success('\\'); if( parser.match('"') ) return parser.success('"'); if( parser.match('\'') ) return parser.success('\''); int start = parser.currentIndex(); if( parser.match('x') && HexDigit() && HexDigit() ) return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16)); if( Digit() ) { if( Digit() ) Digit(); // optional return parser.success((char)Integer.parseInt(parser.textFrom(start))); } if( EndOfLine() ) return parser.success('\n'); return parser.failure(null); } private void Spaces(In in) throws ParseException { while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && EndOfLine() ); } private boolean ContinueOnNextLine() { parser.begin(); return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure(); } private boolean Comment() throws ParseException { if( LongComment() ) return true; if( parser.match("--") ) { while( parser.noneOf("\r\n") ); return true; } return false; } private boolean LongComment() throws ParseException { parser.begin(); if( !parser.match("--[") ) return parser.failure(); int start = parser.currentIndex(); while( parser.match('=') ); int nEquals = parser.currentIndex() - start; if( !parser.match('[') ) return parser.failure(); while( !LongBracketsEnd(nEquals) ) { if( !parser.anyChar() ) throw parser.exception("Unclosed comment"); } return parser.success(); } private boolean LongBracketsEnd(int nEquals) { parser.begin(); if( !parser.match(']') ) return parser.failure(); while( nEquals-- > 0 ) { if( !parser.match('=') ) return parser.failure(); } if( !parser.match(']') ) return parser.failure(); return parser.success(); } private static int classCounter = 0; private class ExpString { final List list = new ArrayList(); final boolean isExpr; final boolean isStmt; /* ExpString(Expressions exp) { if( exp==null ) throw new NullPointerException(); int i = LuanImpl.addObj(exp); list.add( "((Expressions)LuanImpl.getObj(" + i + ")).eval(luan)" ); isExpr = exp instanceof Expr; isStmt = exp instanceof StmtExp; } */ ExpString(boolean isExpr,boolean isStmt) { this.isExpr = isExpr; this.isStmt = isStmt; } ExpString expr() { if( isExpr ) return this; ExpString exp = new ExpString(true,isStmt); exp.list.add( "Luan.first(" ); exp.list.addAll( list ); exp.list.add( ")" ); return exp; } } private ExpString expString(List<ExpString> list) { ExpString exp = new ExpString(false,false); switch(list.size()) { case 0: exp.list.add("LuanFunction.NOTHING"); return exp; case 1: return list.get(0); default: int lastI = list.size() - 1; exp.list.add( "new Object[]{" ); for( int i=0; i<lastI; i++ ) { exp.list.addAll( list.get(i).expr().list ); exp.list.add( "," ); } ExpString last = list.get(lastI); if( last.isExpr ) { exp.list.addAll( last.list ); exp.list.add( "}" ); } else { exp.list.add( "}" ); exp.list.add( 0, "LuanImpl.concatArgs(" ); exp.list.add( "," ); exp.list.addAll( last.list ); exp.list.add( ")" ); } return exp; } } private static class StmtString { final List list = new ArrayList(); boolean hasReturn = false; } private static String concat(List list) { StringBuilder sb = new StringBuilder(); for( Object o : list ) { if( o instanceof List ) throw new RuntimeException(); if( o instanceof ExpString ) throw new RuntimeException(); if( o instanceof StmtString ) throw new RuntimeException(); sb.append( o.toString() ); } return sb.toString(); } private Class toFnClass(StmtString stmt,List<UpSym> upValueSymbols) { String code = concat(stmt.list); //System.out.println("code:\n"+code); String className = "EXP" + ++classCounter; String classCode = "" +"package luan.impl;\n" +"import luan.Luan;\n" +"import luan.LuanFunction;\n" +"import luan.LuanState;\n" +"import luan.LuanException;\n" +"import luan.modules.PackageLuan;\n" +"\n" +"public class " + className +" extends Closure {\n" +" public "+className+"(LuanState luan) throws LuanException {\n" +" super("+upValueSymbols.size()+");\n" + init(upValueSymbols) +" }\n" +"\n" +" @Override public Object doCall(LuanState luan,Object[] args) throws LuanException {\n" +" Object t;\n" +" " + code +" }\n" +"}\n" ; try { System.out.println(parser.sourceName); System.out.println(classCode); return LuanJavaCompiler.compile("luan.impl."+className,parser.sourceName,classCode); } catch(ClassNotFoundException e) { throw new RuntimeException(e); } } private ExpString toFnExpStr(StmtString stmt,List<UpSym> upValueSymbols) { ExpString exp = new ExpString(true,false); exp.list.add( "" +"\n" +"new Closure("+upValueSymbols.size()+") {\n" +"{\n" + init(upValueSymbols) +"}\n" +" @Override public Object doCall(LuanState luan,Object[] args) throws LuanException {\n" +" Object t;\n" +" " ); exp.list.addAll( stmt.list ); exp.list.add( "" +" }\n" +"}\n" ); return exp; } private static String init(List<UpSym> upValueSymbols) { StringBuilder sb = new StringBuilder(); for( UpSym upSym : upValueSymbols ) { sb.append( upSym.init() ); } return sb.toString(); } /* private static String settableToString(Settable settable) { if( settable==null ) throw new NullPointerException(); int i = LuanImpl.addObj(settable); return"((Settable)LuanImpl.getObj(" + i + "))"; } */ }