Mercurial Hosting > luan
changeset 17:09d41f7490a8
add local variables
git-svn-id: https://luan-java.googlecode.com/svn/trunk@18 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Fri, 30 Nov 2012 11:46:34 +0000 |
parents | 2a30281ef47c |
children | 3971113699b8 |
files | src/luan/LuaState.java src/luan/interp/Block.java src/luan/interp/Chunk.java src/luan/interp/GetLocalVar.java src/luan/interp/LuaParser.java src/luan/interp/SetLocalVar.java src/luan/interp/SetStmt.java src/luan/interp/SetTableEntry.java src/luan/interp/Settable.java |
diffstat | 9 files changed, 313 insertions(+), 118 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/LuaState.java Thu Nov 29 10:36:38 2012 +0000 +++ b/src/luan/LuaState.java Fri Nov 30 11:46:34 2012 +0000 @@ -8,4 +8,29 @@ return env; } + + private static class LuaStack { + final LuaStack previousStack; + final Object[] a; + + LuaStack( LuaStack previousStack, int stackSize) { + this.previousStack = previousStack; + this.a = new Object[stackSize]; + } + } + + private LuaStack stack = null; + + public void newStack(int stackSize) { + stack = new LuaStack(stack,stackSize); + } + + public void popStack() { + stack = stack.previousStack; + } + + public Object[] stack() { + return stack.a; + } + }
--- a/src/luan/interp/Block.java Thu Nov 29 10:36:38 2012 +0000 +++ b/src/luan/interp/Block.java Fri Nov 30 11:46:34 2012 +0000 @@ -6,14 +6,25 @@ final class Block implements Stmt { private final Stmt[] stmts; + private final int stackStart; + private final int stackEnd; - Block(Stmt[] stmts) { + Block(Stmt[] stmts,int stackStart,int stackEnd) { this.stmts = stmts; + this.stackStart = stackStart; + this.stackEnd = stackEnd; } @Override public void eval(LuaState lua) throws LuaException { - for( Stmt stmt : stmts ) { - stmt.eval(lua); + try { + for( Stmt stmt : stmts ) { + stmt.eval(lua); + } + } finally { + Object[] stack = lua.stack(); + for( int i=stackStart; i<stackEnd; i++ ) { + stack[i] = null; + } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/Chunk.java Fri Nov 30 11:46:34 2012 +0000 @@ -0,0 +1,25 @@ +package luan.interp; + +import luan.LuaState; +import luan.LuaException; + + +final class Chunk implements Stmt { + private final Stmt block; + private final int stackSize; + + Chunk(Stmt block,int stackSize) { + this.block = block; + this.stackSize = stackSize; + } + + @Override public void eval(LuaState lua) throws LuaException { + lua.newStack(stackSize); + try { + block.eval(lua); + } finally { + lua.popStack(); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/GetLocalVar.java Fri Nov 30 11:46:34 2012 +0000 @@ -0,0 +1,16 @@ +package luan.interp; + +import luan.LuaState; + + +final class GetLocalVar implements Expr { + private final int index; + + GetLocalVar(int index) { + this.index = index; + } + + @Override public Object eval(LuaState lua) { + return lua.stack()[index]; + } +}
--- a/src/luan/interp/LuaParser.java Thu Nov 29 10:36:38 2012 +0000 +++ b/src/luan/interp/LuaParser.java Fri Nov 30 11:46:34 2012 +0000 @@ -13,6 +13,7 @@ import org.parboiled.support.ParsingResult; import org.parboiled.support.Var; import org.parboiled.support.StringVar; +import org.parboiled.support.StringBuilderVar; import org.parboiled.support.ValueStack; import org.parboiled.errors.ErrorUtils; import luan.Lua; @@ -23,6 +24,8 @@ public class LuaParser extends BaseParser<Object> { int nEquals; int parens = 0; + List<String> symbols = new ArrayList<String>(); + int stackSize = 0; boolean nEquals(int n) { nEquals = n; @@ -39,6 +42,15 @@ return true; } + int index(String name) { + int i = symbols.size(); + while( --i >= 0 ) { + if( symbols.get(i).equals(name) ) + return i; + } + return -1; + } + public Rule Target() { return Sequence( Spaces(), @@ -51,35 +63,36 @@ Rule Chunk() { return Sequence( - push(new ArrayList<Stmt>()), - Optional( Stmt() ), - ZeroOrMore( - StmtSep(), - Optional( Stmt() ) - ), - push( newChunk() ) + Block(), + push( new Chunk( (Stmt)pop(), stackSize ) ) ); } - boolean addStmt() { - Stmt stmt = (Stmt)pop(); - @SuppressWarnings("unchecked") - List<Stmt> stmts = (List<Stmt>)peek(); - stmts.add(stmt); - return true; + Rule Block() { + Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>()); + return Sequence( + push(0), // stackCount + Optional( Stmt(stmts) ), + ZeroOrMore( + StmtSep(), + Optional( Stmt(stmts) ) + ), + push( newBlock(stmts.get()) ) + ); } - Stmt newChunk() { - @SuppressWarnings("unchecked") - List<Stmt> stmts = (List<Stmt>)pop(); - switch( stmts.size() ) { - case 0: + Stmt newBlock(List<Stmt> stmts) { + if( stackSize < symbols.size() ) + stackSize = symbols.size(); + int stackN = (Integer)pop(); + for( int i=0; i<stackN; i++ ) { + symbols.remove(symbols.size()-1); // pop + } + if( stmts.isEmpty() ) return Stmt.EMPTY; - case 1: + if( stmts.size()==1 && stackN==0 ) return stmts.get(0); - default: - return new Block(stmts.toArray(new Stmt[0])); - } + return new Block( stmts.toArray(new Stmt[0]), symbols.size(), symbols.size()+stackN ); } Rule StmtSep() { @@ -99,29 +112,74 @@ return FirstOf("\r\n", '\r', '\n'); } - Rule Stmt() { + Rule Stmt(Var<List<Stmt>> stmts) { + return FirstOf( + LocalStmt(stmts), + Sequence( + FirstOf( + DoStmt(), + WhileStmt(), + RepeatStmt(), + IfStmt(), + SetStmt(), + ExpressionsStmt() + ), + stmts.get().add( (Stmt)pop() ) + ) + ); + } + + Rule DoStmt() { + return Sequence( + Keyword("do"), Block(), Keyword("end") + ); + } + + Rule LocalStmt(Var<List<Stmt>> stmts) { + Var<List<String>> names = new Var<List<String>>(new ArrayList<String>()); return Sequence( - FirstOf( - WhileStmt(), - RepeatStmt(), - IfStmt(), - SetStmt(), - ExpressionsStmt() + Keyword("local"), + Name(), + newName(names.get()), + ZeroOrMore( + ',', Spaces(), Name(), + newName(names.get()) ), - addStmt() + Optional( + '=', Spaces(), + ExpList(), + stmts.get().add( newSetLocalStmt(names.get()) ) + ) ); } + boolean newName(List<String> names) { + String name = (String)pop(); + names.add(name); + symbols.add(name); + push( ((Integer)pop()) + 1 ); + return true; + } + + SetStmt newSetLocalStmt(List<String> names) { + Expressions values = (Expressions)pop(); + SetLocalVar[] vars = new SetLocalVar[names.size()]; + for( int i=0; i<vars.length; i++ ) { + vars[i] = new SetLocalVar(index(names.get(i))); + } + return new SetStmt( vars, values ); + } + Rule WhileStmt() { return Sequence( - "while", Spaces(), Expr(), "do", Spaces(), Chunk(), "end", Spaces(), + Keyword("while"), Expr(), Keyword("do"), Block(), Keyword("end"), push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) ) ); } Rule RepeatStmt() { return Sequence( - "repeat", Spaces(), Chunk(), "until", Spaces(), Expr(), + Keyword("repeat"), Block(), Keyword("until"), Expr(), push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) ) ); } @@ -129,17 +187,17 @@ Rule IfStmt() { Var<Integer> n = new Var<Integer>(1); return Sequence( - "if", Spaces(), Expr(), "then", Spaces(), Chunk(), + Keyword("if"), Expr(), Keyword("then"), Block(), push(Stmt.EMPTY), ZeroOrMore( - "elseif", Spaces(), drop(), Expr(), "then", Spaces(), Chunk(), + Keyword("elseif"), drop(), Expr(), Keyword("then"), Block(), push(Stmt.EMPTY), n.set(n.get()+1) ), Optional( - "else", Spaces(), drop(), Chunk() + Keyword("else"), drop(), Block() ), - "end", Spaces(), + Keyword("end"), buildIfStmt(n.get()) ); } @@ -173,13 +231,13 @@ SetStmt newSetStmt() { Expressions values = (Expressions)pop(); @SuppressWarnings("unchecked") - List<SetStmt.Var> vars = (List<SetStmt.Var>)pop(); - return new SetStmt( vars.toArray(new SetStmt.Var[0]), values ); + List<Settable> vars = (List<Settable>)pop(); + return new SetStmt( vars.toArray(new Settable[0]), values ); } Rule VarList() { return Sequence( - push(new ArrayList<SetStmt.Var>()), + push(new ArrayList<Settable>()), Var(), addToVarList(), ZeroOrMore( @@ -190,14 +248,25 @@ } boolean addToVarList() { - Object obj = pop(); - if( obj==null ) + Object obj2 = pop(); + if( obj2==null ) return false; - Expr key = expr(obj); - Expr table = expr(pop()); + Object obj1 = pop(); @SuppressWarnings("unchecked") - List<SetStmt.Var> vars = (List<SetStmt.Var>)peek(); - vars.add( new SetStmt.Var(table,key) ); + List<Settable> vars = (List<Settable>)peek(); + if( obj1==null ) { + String name = (String)obj2; + int index = index(name); + if( index == -1 ) { + vars.add( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) ); + } else { + vars.add( new SetLocalVar(index) ); + } + } else { + Expr key = expr(obj2); + Expr table = expr(obj1); + vars.add( new SetTableEntry(table,key) ); + } return true; } @@ -324,7 +393,7 @@ Rule Field() { return FirstOf( Sequence( - FirstOf( SubExpr(), Name() ), + FirstOf( SubExpr(), NameExpr() ), '=', Spaces(), Expr(), addField() ), @@ -376,7 +445,7 @@ push(null) // marker ), Sequence( - push(EnvExpr.INSTANCE), + push(null), // marker Name() ) ), @@ -384,7 +453,7 @@ makeVarExp(), FirstOf( SubExpr(), - Sequence( '.', Spaces(), Name() ), + Sequence( '.', Spaces(), NameExpr() ), Sequence( Args(), push(null) // marker @@ -395,10 +464,20 @@ } boolean makeVarExp() { - Object obj = pop(); - if( obj==null ) + Object obj2 = pop(); + if( obj2==null ) return true; - return push( new GetExpr( expr(pop()), expr(obj) ) ); + Object obj1 = pop(); + if( obj1==null ) { + String name = (String)obj2; + int index = index(name); + if( index == -1 ) { + return push( new GetExpr( EnvExpr.INSTANCE, new ConstExpr(name) ) ); + } else { + return push( new GetLocalVar(index) ); + } + } + return push( new GetExpr( expr(obj1), expr(obj2) ) ); } // function should be on top of the stack @@ -429,21 +508,20 @@ } Rule ExpList() { + Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder()); return Sequence( - push(new ExpList.Builder()), Expr(), - addToExpList(), + addToExpList(builder.get()), ZeroOrMore( ',', Spaces(), Expr(), - addToExpList() + addToExpList(builder.get()) ), - push( ((ExpList.Builder)pop()).build() ) + push( builder.get().build() ) ); } - boolean addToExpList() { + boolean addToExpList(ExpList.Builder bld) { Object obj = pop(); - ExpList.Builder bld = (ExpList.Builder)peek(); if( obj instanceof Expressions ) { bld.add( (Expressions)obj ); } else { @@ -452,24 +530,35 @@ return true; } + Rule SubExpr() { return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() ); } + Rule NameExpr() { + return Sequence( + Name(), + push( new ConstExpr((String)pop()) ) + ); + } + Rule Name() { return Sequence( Sequence( - NameStart(), - ZeroOrMore( - FirstOf( NameStart(), Digit() ) - ) + NameFirstChar(), + ZeroOrMore( NameChar() ) ), - pushNameExpr(), + !keywords.contains(match()), + push(match()), Spaces() ); } - Rule NameStart() { + Rule NameChar() { + return FirstOf( NameFirstChar(), Digit() ); + } + + Rule NameFirstChar() { return FirstOf( CharRange('a', 'z'), CharRange('A', 'Z'), @@ -477,14 +566,15 @@ ); } - boolean pushNameExpr() { - String name = match(); - if( keywords.contains(name) ) - return false; - return push( new ConstExpr(name) ); + Rule Keyword(String keyword) { + return Sequence( + keyword, + TestNot( NameChar() ), + Spaces() + ); } - private static final Set<String> keywords = new HashSet<String>(Arrays.asList( + static final Set<String> keywords = new HashSet<String>(Arrays.asList( "and", "break", "do", @@ -635,7 +725,7 @@ Rule LongString() { return Sequence( - "[", + '[', ZeroOrMore('='), nEquals(matchLength()), '[', @@ -649,41 +739,41 @@ } Rule QuotedString(char quote) { + StringBuilderVar buf = new StringBuilderVar(); return Sequence( quote, - push(new StringBuffer()), ZeroOrMore( FirstOf( Sequence( NoneOf("\\\n"+quote), - append(matchedChar()) + buf.append(matchedChar()) ), - EscSeq() + EscSeq(buf) ) ), quote, - push(((StringBuffer)pop()).toString()) + push( buf.getString() ) ); } - Rule EscSeq() { + Rule EscSeq(StringBuilderVar buf) { return Sequence( '\\', FirstOf( - Sequence( 'a', append('\u0007') ), - Sequence( 'b', append('\b') ), - Sequence( 'f', append('\f') ), - Sequence( 'n', append('\n') ), - Sequence( 'r', append('\r') ), - Sequence( 't', append('\t') ), - Sequence( 'v', append('\u000b') ), - Sequence( '\\', append('\\') ), - Sequence( '"', append('"') ), - Sequence( '\'', append('\'') ), + Sequence( 'a', buf.append('\u0007') ), + Sequence( 'b', buf.append('\b') ), + Sequence( 'f', buf.append('\f') ), + Sequence( 'n', buf.append('\n') ), + Sequence( 'r', buf.append('\r') ), + Sequence( 't', buf.append('\t') ), + Sequence( 'v', buf.append('\u000b') ), + Sequence( '\\', buf.append('\\') ), + Sequence( '"', buf.append('"') ), + Sequence( '\'', buf.append('\'') ), Sequence( 'x', Sequence( HexDigit(), HexDigit() ), - append( (char)Integer.parseInt(match(),16) ) + buf.append( (char)Integer.parseInt(match(),16) ) ), Sequence( Sequence( @@ -695,18 +785,12 @@ ) ) ), - append( (char)Integer.parseInt(match()) ) + buf.append( (char)Integer.parseInt(match()) ) ) ) ); } - boolean append(char ch) { - StringBuffer sb = (StringBuffer)peek(); - sb.append(ch); - return true; - } - Rule Spaces() { return ZeroOrMore( FirstOf(
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/SetLocalVar.java Fri Nov 30 11:46:34 2012 +0000 @@ -0,0 +1,16 @@ +package luan.interp; + +import luan.LuaState; + + +final class SetLocalVar implements Settable { + private final int index; + + SetLocalVar(int index) { + this.index = index; + } + + @Override public void set(LuaState lua,Object value) { + lua.stack()[index] = value; + } +}
--- a/src/luan/interp/SetStmt.java Thu Nov 29 10:36:38 2012 +0000 +++ b/src/luan/interp/SetStmt.java Fri Nov 30 11:46:34 2012 +0000 @@ -1,28 +1,15 @@ package luan.interp; -import java.util.List; import luan.Lua; import luan.LuaState; import luan.LuaException; -import luan.LuaTable; final class SetStmt implements Stmt { - - static class Var { - final Expr table; - final Expr key; - - Var(Expr table,Expr key) { - this.table = table; - this.key = key; - } - } - - private final Var[] vars; + private final Settable[] vars; private final Expressions expressions; - SetStmt(Var[] vars,Expressions expressions) { + SetStmt(Settable[] vars,Expressions expressions) { this.vars = vars; this.expressions = expressions; } @@ -30,14 +17,9 @@ @Override public void eval(LuaState lua) throws LuaException { final Object[] vals = expressions.eval(lua); for( int i=0; i<vars.length; i++ ) { - Var var = vars[i]; - Object t = var.table.eval(lua); - if( !(t instanceof LuaTable) ) - throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); - LuaTable tbl = (LuaTable)t; - Object key = var.key.eval(lua); + Settable var = vars[i]; Object val = i < vals.length ? vals[i] : null; - tbl.set(key,val); + var.set(lua,val); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/SetTableEntry.java Fri Nov 30 11:46:34 2012 +0000 @@ -0,0 +1,27 @@ +package luan.interp; + +import luan.LuaState; +import luan.LuaException; +import luan.LuaTable; +import luan.Lua; + + +final class SetTableEntry implements Settable { + private final Expr tableExpr; + private final Expr keyExpr; + + SetTableEntry(Expr tableExpr,Expr keyExpr) { + this.tableExpr = tableExpr; + this.keyExpr = keyExpr; + } + + @Override public void set(LuaState lua,Object value) throws LuaException { + Object t = tableExpr.eval(lua); + if( !(t instanceof LuaTable) ) + throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); + LuaTable table = (LuaTable)t; + Object key = keyExpr.eval(lua); + table.set(key,value); + } + +}