Add lua2java too to compile from lua source to java source

This commit is contained in:
James Roseborough
2010-07-19 14:56:32 +00:00
parent 400fd91482
commit c537e5b124
15 changed files with 6033 additions and 9 deletions

197
src/jse/lua2java.java Normal file
View File

@@ -0,0 +1,197 @@
/*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.luaj.vm2.Lua;
import org.luaj.vm2.ast.Chunk;
import org.luaj.vm2.lua2java.JavaCodeGen;
import org.luaj.vm2.parser.LuaParser;
/**
* Compile lua sources into java sources.
*/
public class lua2java {
private static final String version = Lua._VERSION + "Copyright (C) 2010 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar lua2java [options] [filenames].\n" +
"Available options are:\n" +
" - process stdin\n" +
" -s src source directory\n" +
" -d dir destination directory\n" +
" -p pkg package prefix to apply to all classes\n" +
" -r recursively compile all\n" +
" -v verbose\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private String srcdir = null;
private String destdir = null;
private String pkgprefix = null;
private boolean recurse = false;
private boolean verbose = false;
private List<InputFile> files = new ArrayList<InputFile>();
public static void main( String[] args ) throws IOException {
new lua2java( args );
}
private lua2java( String[] args ) throws IOException {
// process args
try {
List<String> seeds = new ArrayList<String> ();
// get stateful args
for ( int i=0; i<args.length; i++ ) {
if ( ! args[i].startsWith("-") ) {
seeds.add(args[i]);
} else {
switch ( args[i].charAt(1) ) {
case 's':
if ( ++i >= args.length )
usageExit();
srcdir = args[i];
break;
case 'd':
if ( ++i >= args.length )
usageExit();
destdir = args[i];
break;
case 'p':
if ( ++i >= args.length )
usageExit();
pkgprefix = args[i];
break;
case 'r':
recurse = true;
break;
case 'v':
verbose = true;
break;
default:
usageExit();
break;
}
}
}
// echo version
if ( verbose ) {
System.out.println(version);
System.out.println("srcdir: "+srcdir);
System.out.println("destdir: "+destdir);
System.out.println("files: "+files);
System.out.println("recurse: "+recurse);
}
// collect up files to process
for ( int i=0; i<seeds.size(); i++ )
collectFiles( seeds.get(i) );
// check for at least one file
if ( files.size() <= 0 ) {
System.err.println("no files found in "+seeds);
System.exit(-1);
}
// process input files
for ( InputFile inf : files )
processFile( inf );
} catch ( Exception ioe ) {
System.err.println( ioe.toString() );
System.exit(-2);
}
}
private void collectFiles(String path) {
File f = new File(path);
if ( f.isDirectory() && recurse )
scandir(f,pkgprefix);
else if ( f.isFile() ) {
File dir = f.getAbsoluteFile().getParentFile();
if ( dir != null )
scanfile( dir, f, pkgprefix );
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for ( int i=0; i<f.length; i++ )
scanfile( dir, f[i], javapackage );
}
private void scanfile(File dir, File f, String javapackage) {
if ( f.exists() ) {
if ( f.isDirectory() && recurse )
scandir( f, (javapackage!=null? javapackage+"."+f.getName(): f.getName()) );
else if ( f.isFile() && f.getName().endsWith(".lua") )
files.add( new InputFile(dir,f,javapackage) );
}
}
class InputFile {
public File infile;
public File outdir;
public File outfile;
public String javapackage;
public String javaclassname;
public InputFile(File dir, File f, String javapackage) {
String outdirpath = javapackage!=null? destdir+"/"+javapackage.replace('.', '/'): destdir;
this.javaclassname = f.getName().substring(0,f.getName().lastIndexOf('.'));
this.javapackage = javapackage;
this.infile = f;
this.outdir = new File(outdirpath);
this.outfile = new File(outdirpath+"/"+this.javaclassname+".java");
}
}
private void processFile( InputFile inf ) {
inf.outdir.mkdirs();
try {
if ( verbose )
System.out.println(
"pkg="+inf.javapackage+" file="+inf.javaclassname+".java dest="+inf.outfile+" src="+inf.infile);
FileInputStream in = new FileInputStream(inf.infile);
FileOutputStream out = new FileOutputStream(inf.outfile);
PrintWriter pw = new PrintWriter(out);
LuaParser parser = new LuaParser(in);
Chunk chunk = parser.Chunk();
new JavaCodeGen(chunk,pw,inf.javapackage,inf.javaclassname);
pw.close();
out.close();
in.close();
} catch ( Throwable t ) {
t.printStackTrace( System.err );
}
}
}

View File

@@ -21,6 +21,7 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.ast; package org.luaj.vm2.ast;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
abstract abstract
@@ -40,13 +41,59 @@ public class Exp {
} }
public static Exp unaryexp(int op, Exp rhs) { public static Exp unaryexp(int op, Exp rhs) {
if ( rhs instanceof BinopExp ) {
BinopExp b = (BinopExp) rhs;
if ( precedence(op) > precedence(b.op) )
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
}
return new UnopExp(op, rhs); return new UnopExp(op, rhs);
} }
public static Exp binaryexp(Exp lhs, int op, Exp rhs) { public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
if ( lhs instanceof UnopExp ) {
UnopExp u = (UnopExp) lhs;
if ( precedence(op) > precedence(u.op) )
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
}
// TODO: cumulate string concatenations together
// TODO: constant folding
if ( lhs instanceof BinopExp ) {
BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
return binaryexp( b.lhs, b.op, binaryexp( b.rhs, op, rhs ) );
}
if ( rhs instanceof BinopExp ) {
BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
return binaryexp( binaryexp( lhs, op, b.lhs ), b.op, b.rhs );
}
return new BinopExp(lhs, op, rhs); return new BinopExp(lhs, op, rhs);
} }
static boolean isrightassoc(int op) {
switch ( op ) {
case Lua.OP_CONCAT:
case Lua.OP_POW: return true;
default: return false;
}
}
static int precedence(int op) {
switch ( op ) {
case Lua.OP_OR: return 0;
case Lua.OP_AND: return 1;
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
case Lua.OP_CONCAT: return 3;
case Lua.OP_ADD: case Lua.OP_SUB: return 4;
case Lua.OP_MUL: case Lua.OP_DIV: return 5;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
case Lua.OP_POW: return 7;
default: throw new IllegalStateException("precedence of bad op "+op);
}
}
public static Exp anonymousfunction(FuncBody funcbody) { public static Exp anonymousfunction(FuncBody funcbody) {
return new AnonFuncDef(funcbody); return new AnonFuncDef(funcbody);
} }

View File

@@ -41,8 +41,9 @@ public class NameResolver extends Visitor {
pushScope(); pushScope();
scope.functionNestingCount++; scope.functionNestingCount++;
body.scope = scope; body.scope = scope;
for ( Name n : body.parlist.names ) if ( body.parlist.names != null )
defineLocalVar(n); for ( Name n : body.parlist.names )
defineLocalVar(n);
super.visit(body); super.visit(body);
popScope(); popScope();
} }

View File

@@ -135,6 +135,13 @@ public class Stat {
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit( this ); visitor.visit( this );
} }
public int nreturns() {
int n = values!=null? values.size(): 0;
if ( n>0 && values.get(n-1).isvarargexp() )
n = -1;
return n;
}
} }
public static class FuncCallStat extends Stat { public static class FuncCallStat extends Stat {

View File

@@ -21,6 +21,8 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.ast; package org.luaj.vm2.ast;
import java.io.ByteArrayOutputStream;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
public class Str { public class Str {
@@ -50,9 +52,39 @@ public class Str {
return LuaString.valueOf(s); return LuaString.valueOf(s);
} }
public static byte[] unquote(String s) { public static byte[] unquote(String s) {
// TODO: unquote string data ByteArrayOutputStream baos = new ByteArrayOutputStream();
return utf8decode(s); char[] c = s.toCharArray();
int n = c.length;
for ( int i=0; i<n; i++ ) {
if ( c[i] == '\\' && i<n ) {
switch ( c[++i] ) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
int d=(int) (c[i++]-'0');
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
d = d * 10 + (int) (c[i]-'0');
baos.write( (byte) d );
--i;
continue;
case 'a': baos.write( (byte) 7 ); continue;
case 'b': baos.write( (byte) '\b' ); continue;
case 'f': baos.write( (byte) '\f' ); continue;
case 'n': baos.write( (byte) '\n' ); continue;
case 'r': baos.write( (byte) '\r' ); continue;
case 't': baos.write( (byte) '\t' ); continue;
case 'v': baos.write( (byte) 11 ); continue;
case '"': baos.write( (byte) '"' ); continue;
case '\'': baos.write( (byte) '\'' ); continue;
case '\\': baos.write( (byte) '\\' ); continue;
default: baos.write( (byte) c[i] ); break;
}
} else {
baos.write( (byte) c[i] );
}
}
return baos.toByteArray();
} }
/*
private static byte[] utf8decode(String s) { private static byte[] utf8decode(String s) {
try { try {
return s.getBytes("UTF8"); return s.getBytes("UTF8");
@@ -60,4 +92,5 @@ public class Str {
throw new RuntimeException("utf8 not found: "+e); throw new RuntimeException("utf8 not found: "+e);
} }
} }
*/
} }

View File

@@ -33,11 +33,13 @@ abstract public class Visitor {
public void visit(Stat.IfThenElse stat) { public void visit(Stat.IfThenElse stat) {
stat.ifexp.accept(this); stat.ifexp.accept(this);
stat.ifblock.accept(this); stat.ifblock.accept(this);
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) { if ( stat.elseifblocks != null )
stat.elseifexps.get(i).accept(this); for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
stat.elseifblocks.get(i).accept(this); stat.elseifexps.get(i).accept(this);
} stat.elseifblocks.get(i).accept(this);
visit( stat.elseblock ); }
if ( stat.elseblock != null )
visit( stat.elseblock );
} }
public void visit(Stat.LocalAssign stat) { public void visit(Stat.LocalAssign stat) {
visitNames(stat.names); visitNames(stat.names);

View File

@@ -0,0 +1,754 @@
/*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lua2java;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.ast.Block;
import org.luaj.vm2.ast.Chunk;
import org.luaj.vm2.ast.Exp;
import org.luaj.vm2.ast.FuncArgs;
import org.luaj.vm2.ast.FuncBody;
import org.luaj.vm2.ast.Name;
import org.luaj.vm2.ast.NameResolver;
import org.luaj.vm2.ast.ParList;
import org.luaj.vm2.ast.Stat;
import org.luaj.vm2.ast.TableConstructor;
import org.luaj.vm2.ast.TableField;
import org.luaj.vm2.ast.Visitor;
import org.luaj.vm2.ast.Exp.AnonFuncDef;
import org.luaj.vm2.ast.Exp.BinopExp;
import org.luaj.vm2.ast.Exp.Constant;
import org.luaj.vm2.ast.Exp.FieldExp;
import org.luaj.vm2.ast.Exp.FuncCall;
import org.luaj.vm2.ast.Exp.IndexExp;
import org.luaj.vm2.ast.Exp.MethodCall;
import org.luaj.vm2.ast.Exp.NameExp;
import org.luaj.vm2.ast.Exp.ParensExp;
import org.luaj.vm2.ast.Exp.UnopExp;
import org.luaj.vm2.ast.Exp.VarExp;
import org.luaj.vm2.ast.Exp.VarargsExp;
import org.luaj.vm2.ast.Stat.Assign;
import org.luaj.vm2.ast.Stat.Break;
import org.luaj.vm2.ast.Stat.FuncCallStat;
import org.luaj.vm2.ast.Stat.FuncDef;
import org.luaj.vm2.ast.Stat.GenericFor;
import org.luaj.vm2.ast.Stat.IfThenElse;
import org.luaj.vm2.ast.Stat.LocalAssign;
import org.luaj.vm2.ast.Stat.LocalFuncDef;
import org.luaj.vm2.ast.Stat.NumericFor;
import org.luaj.vm2.ast.Stat.RepeatUntil;
import org.luaj.vm2.ast.Stat.Return;
import org.luaj.vm2.ast.Stat.WhileDo;
public class JavaCodeGen {
final Chunk chunk;
final String packagename;
final String classname;
Writer writer;
public JavaCodeGen( Chunk chunk, Writer writer,String packagename, String classname) {
this.chunk = chunk;
this.writer = writer;
this.packagename = packagename;
this.classname = classname;
chunk.accept( new NameResolver() );
chunk.accept( new JavaClassWriterVisitor() );
}
class JavaClassWriterVisitor extends Visitor {
JavaScope javascope = null;
List<String> constantDeclarations = new ArrayList<String>();
Map<String,String> stringConstants = new HashMap<String,String>();
Map<Double,String> numberConstants = new HashMap<Double,String>();
String indent = "";
void addindent() {
indent+=" ";
}
void subindent() {
indent = indent.substring(3);
}
void out(String s) {
try {
writer.write(s);
} catch (IOException e) {
throw new RuntimeException("write failed: "+e, e);
}
}
void outi(String s) {
out( indent );
out( s );
}
void outl(String s) {
outi( s );
out( "\n" );
}
void outr(String s) {
out( s );
out( "\n" );
}
void outb(String s) {
outl( s );
addindent();
}
void oute(String s) {
subindent();
outl( s );
}
public void visit(Chunk chunk) {
if ( packagename != null )
outl("package "+packagename+";");
outl("import org.luaj.vm2.*;");
outl("import org.luaj.vm2.lib.*;");
outb("public class "+classname+" extends VarArgFunction {");
outl("public Varargs invoke(Varargs arg) {");
addindent();
javascope = JavaScope.newJavaScope( chunk );
writeBodyBlock(chunk.block);
oute("}");
for ( String s : constantDeclarations )
outl( s );
subindent();
outi("}");
}
void writeBodyBlock(Block block) {
if ( javascope.needsbinoptmp )
outl( "LuaValue $b;" );
super.visit(block);
if ( !endsInReturn(block) )
outl( "return NONE;" );
}
public void visit(Block block) {
outb("{");
super.visit(block);
oute("}");
}
private boolean endsInReturn(Block block) {
int n = block.stats.size();
if ( n<=0 ) return false;
Stat s = block.stats.get(n-1);
return s instanceof Return || s instanceof Break;
}
public void visit(Stat.Return s) {
int n = s.nreturns();
switch ( n ) {
case 0: outl( "return NONE;" ); break;
case 1: outl( "return "+eval(s.values.get(0))+";" ); break;
default: outl( "return "+eval(s.values)+";" ); break;
}
}
public void visit(AnonFuncDef def) {
super.visit(def);
}
public void visit(LocalAssign stat) {
int n = stat.names.size();
int m = stat.values!=null? stat.values.size(): 0;
if ( n == 1 && m<=1 ) {
Name name = stat.names.get(0);
String javaname = javascope.getJavaName(name.variable);
String value = "NIL";
if ( m > 0 ) {
Exp val= stat.values.get(0);
value = eval(val) + (val.isvarargexp()? ".arg1()": "");
}
singleLocalDeclareAssign(name,value);
} else {
for ( Name name : stat.names )
singleLocalDeclareAssign(name,null);
multiAssign(stat.names, stat.values);
}
}
public void visit(Assign stat) {
multiAssign(stat.vars, stat.exps);
}
private void multiAssign(List varsOrNames, List<Exp> exps) {
int n = varsOrNames.size();
int m = exps != null? exps.size(): 0;
boolean varlist = m>0 && exps.get(m-1).isvarargexp() && n>m;
if ( n<=m ) {
for ( int i=1; i<=n; i++ )
singleAssign( varsOrNames.get(i-1), eval(exps.get(i-1)) );
for ( int i=n+1; i<=m; i++ )
outl( eval(exps.get(i-1))+";" );
} else {
outb( "{" );
for ( int i=1; i<=m; i++ ) {
boolean vtype = varlist && (i==m);
Exp e = exps.get(i-1);
String decl = (vtype? "Varargs": "LuaValue")+" $"+i;
String valu = eval(e)+(e.isvarexp() && !vtype? ".arg1()": "");
outl( decl+"="+valu+";" );
}
for ( int i=1; i<=n; i++ ) {
String valu;
if ( i < m ) valu = "$"+i;
else if ( i==m ) valu = (varlist? "$"+i+".arg1()": "$"+i);
else if ( varlist ) valu = "$"+m+".arg("+(i-m+1)+")";
else valu = "NIL";
singleAssign( varsOrNames.get(i-1), valu );
}
oute( "}" );
}
}
private void singleAssign(final Object varOrName, final String valu) {
Visitor v = new Visitor() {
public void visit(FieldExp exp) {
outl(eval(exp.lhs)+".set("+evalStringConstant(exp.name.name)+","+valu+");");
}
public void visit(IndexExp exp) {
outl(eval(exp.lhs)+".set("+eval(exp.exp)+","+valu+");");
}
public void visit(NameExp exp) {
if ( exp.name.variable.isLocal() )
singleLocalAssign(exp.name, valu);
else
outl( "env.set("+evalStringConstant(exp.name.name)+","+valu+");");
}
};
if ( varOrName instanceof VarExp )
((VarExp)varOrName).accept(v);
else if ( varOrName instanceof Name )
singleLocalAssign((Name) varOrName, valu);
else
throw new IllegalStateException("can't assign to "+varOrName.getClass());
}
private void singleLocalAssign(Name name, String valu) {
outi( javascope.getJavaName(name.variable) );
if ( name.variable.isupvalue )
out( "[0]" );
outr( " = "+valu+";");
}
private void singleLocalDeclareAssign(Name name, String value) {
String javaname = javascope.getJavaName(name.variable);
if ( name.variable.isupvalue )
outl( "final LuaValue[] "+javaname+" = {"+value+"};" );
else
outl( "LuaValue "+javaname+(value!=null? " = "+value: "")+";" );
}
public void visit(Break breakstat) {
// TODO: wrap in do {} while(false), or add label as nec
outl( "break;" );
}
private Writer pushWriter() {
Writer x = writer;
writer = new CharArrayWriter();
return x;
}
private String popWriter(Writer x) {
Writer c = writer;
writer = x;
return c.toString();
}
public String eval(List<Exp> values) {
int n = values.size();
switch ( n ) {
case 0: return "NONE";
case 1: return eval(values.get(0));
default:
Writer x = pushWriter();
out( n<=3? "varargsOf(": "varargsOf(new LuaValue[] {" );
for ( int i=0; i<n; i++ ) {
if ( i>0 ) out( "," );
out(eval(values.get(i)));
}
out( n<=3? ")": "})" );
return popWriter(x);
}
}
public String eval(Exp exp) {
Writer x = pushWriter();
exp.accept(this);
return popWriter(x);
}
public void visit(BinopExp exp) {
switch ( exp.op ) {
case Lua.OP_AND:
case Lua.OP_OR:
out(exp.op==Lua.OP_AND? "(!($b=": "(($b=");
exp.lhs.accept(this);
out(").toboolean()?$b:");
exp.rhs.accept(this);
out( ")" );
return;
}
exp.lhs.accept(this);
switch ( exp.op ) {
case Lua.OP_ADD: out(".add"); break;
case Lua.OP_SUB: out(".sub"); break;
case Lua.OP_MUL: out(".mul"); break;
case Lua.OP_DIV: out(".div"); break;
case Lua.OP_POW: out(".pow"); break;
case Lua.OP_MOD: out(".mod"); break;
case Lua.OP_GT: out(".gt"); break;
case Lua.OP_GE: out(".ge"); break;
case Lua.OP_LT: out(".lt"); break;
case Lua.OP_LE: out(".le"); break;
case Lua.OP_EQ: out(".eq"); break;
case Lua.OP_NEQ: out(".neq"); break;
case Lua.OP_CONCAT: out(".concat"); break;
default: throw new IllegalStateException("unknown bin op:"+exp.op);
}
out("(");
exp.rhs.accept(this);
out(")");
}
public void visit(UnopExp exp) {
exp.rhs.accept(this);
switch ( exp.op ) {
case Lua.OP_NOT: out(".not()"); break;
case Lua.OP_LEN: out(".len()"); break;
case Lua.OP_UNM: out(".neg()"); break;
}
}
public void visit(Constant exp) {
switch ( exp.value.type() ) {
case LuaValue.TSTRING: {
// TODO: non-UTF8 data
out( evalStringConstant(exp.value.tojstring()) );
break;
}
case LuaValue.TNIL:
out("NIL");
break;
case LuaValue.TBOOLEAN:
out(exp.value.toboolean()? "TRUE": "FALSE");
break;
case LuaValue.TNUMBER: {
out( evalNumberConstant(exp.value.todouble()) );
break;
}
default:
throw new IllegalStateException("unknown constant type: "+exp.value.typename());
}
}
private String evalStringConstant(String str) {
// TODO: quoting, data pooling
if ( stringConstants.containsKey(str) )
return stringConstants.get(str);
String declvalue = quotedStringInitializer(str.getBytes());
String javaname = javascope.createConstantName(str);
constantDeclarations.add( "static final LuaValue "+javaname+" = valueOf("+declvalue+");" );
stringConstants.put(str,javaname);
return javaname;
}
private String evalNumberConstant(double value) {
if ( value == 0 ) return "ZERO";
if ( value == -1 ) return "MINUSONE";
if ( value == 1 ) return "ONE";
if ( numberConstants.containsKey(value) )
return numberConstants.get(value);
int ivalue = (int) value;
String declvalue = value==ivalue? String.valueOf(ivalue): String.valueOf(value);
String javaname = javascope.createConstantName(declvalue);
constantDeclarations.add( "static final LuaValue "+javaname+" = valueOf("+declvalue+");" );
numberConstants.put(value,javaname);
return javaname;
}
public void visit(FieldExp exp) {
exp.lhs.accept(this);
out(".get("+evalStringConstant(exp.name.name)+")");
}
public void visit(IndexExp exp) {
exp.lhs.accept(this);
out(".get(");
exp.exp.accept(this);
out(")");
}
public void visit(NameExp exp) {
if ( exp.name.variable.isLocal() ) {
out( javascope.getJavaName(exp.name.variable) );
if ( exp.name.variable.isupvalue )
out( "[0]" );
} else {
out( "env.get("+evalStringConstant(exp.name.name)+")");
}
}
public void visit(ParensExp exp) {
exp.exp.accept(this);
out(".arg1()");
}
public void visit(VarargsExp exp) {
out( "arg" );
}
public void visit(MethodCall exp) {
int n = exp.args.exps != null? exp.args.exps.size(): 0;
exp.lhs.accept(this);
switch ( n ) {
case 0:
out(".method("+evalStringConstant(exp.name)+")");
break;
case 1: case 2: case 3:
out(".method("+evalStringConstant(exp.name)+",");
exp.args.accept(this);
out(")");
break;
default:
out(".invokemethod("+evalStringConstant(exp.name)+",varargsOf(new LuaValue[]{");
exp.args.accept(this);
out("})).arg1()");
break;
}
}
public void visit(FuncCall exp) {
int n = exp.args.exps != null? exp.args.exps.size(): 0;
exp.lhs.accept(this);
switch ( n ) {
case 0: case 1: case 2: case 3:
out(".call(");
exp.args.accept(this);
out(")");
break;
default:
out(".invoke("+eval(exp.args.exps)+").arg1()");
break;
}
}
public void visit(FuncArgs args) {
if ( args.exps != null ) {
int n = args.exps.size();
for ( int i=0; i<n; i++ ) {
if ( i > 0 ) out(",");
Exp e = args.exps.get(i);
out( eval( e ) );
// TODO: arg1(), varargs
}
}
}
public void visit(FuncBody body) {
javascope = javascope.pushJavaScope(body);
int n = javascope.nreturns;
int m = body.parlist.names!=null? body.parlist.names.size(): 0;
if ( n>=0 && n<=1 && m<=3 && ! body.parlist.isvararg ) {
switch ( m ) {
case 0:
outr("new ZeroArgFunction() {");
addindent();
outb("public LuaValue call() {");
break;
case 1:
outr("new OneArgFunction() {");
addindent();
outb("public LuaValue call("
+declareArg(body.parlist.names.get(0))+") {");
assignArg(body.parlist.names.get(0));
break;
case 2:
outr("new TwoArgFunction() {");
addindent();
outb("public LuaValue call("
+declareArg(body.parlist.names.get(0))+","
+declareArg(body.parlist.names.get(1))+") {");
assignArg(body.parlist.names.get(0));
assignArg(body.parlist.names.get(1));
break;
case 3:
outr("new ThreeArgFunction() {");
addindent();
outb("public LuaValue call("
+declareArg(body.parlist.names.get(0))+","
+declareArg(body.parlist.names.get(1))+","
+declareArg(body.parlist.names.get(2))+") {");
assignArg(body.parlist.names.get(0));
assignArg(body.parlist.names.get(1));
assignArg(body.parlist.names.get(2));
break;
}
} else {
outr("new VarArgFunction() {");
addindent();
outb("public Varargs invoke(Varargs arg) {");
for ( int i=0; i<m; i++ ) {
Name name = body.parlist.names.get(i);
String argname = javascope.getJavaName(name.variable);
String value = i>0? "arg.arg("+(i+1)+")": "arg.arg1()";
if ( name.variable.isupvalue )
outl( "final LuaValue[] "+argname+" = {"+value+"};" );
else
outl( "LuaValue "+argname+" = "+value+";" );
}
if ( body.parlist.isvararg && m > 0 )
outl( "arg = arg.arglist("+(m+1)+");" );
}
writeBodyBlock(body.block);
oute("}");
subindent();
outi("}");
javascope = javascope.popJavaScope();
}
private String declareArg(Name name) {
String argname = javascope.getJavaName(name.variable);
return "LuaValue "+argname+(name.variable.isupvalue? "$0": "");
}
private void assignArg(Name name) {
if ( name.variable.isupvalue ) {
String argname = javascope.getJavaName(name.variable);
outl( "final LuaValue[] "+argname+" = {"+argname+"$0};" );
}
}
public void visit(FuncCallStat stat) {
outl(eval(stat.funccall)+";");
}
public void visit(FuncDef stat) {
super.visit(stat);
}
public void visit(LocalFuncDef stat) {
String javaname = javascope.getJavaName(stat.name.variable);
if ( stat.name.variable.isupvalue )
outi("final LuaValue[] "+javaname+" = {");
else
outi("LuaValue "+javaname+" = ");
super.visit(stat);
outr( stat.name.variable.isupvalue? "};": ";" );
}
public void visit(NumericFor stat) {
String javaname = javascope.getJavaName(stat.name.variable);
outi("for ( LuaValue "
+javaname+"="+eval(stat.initial)+", "
+javaname+"$limit="+eval(stat.limit));
String stepname = "ONE";
if ( stat.step!=null )
out(", "+(stepname=javaname+"$step")+"="+eval(stat.step));
outr( "; "
+javaname+".testfor_b("+javaname+"$limit,"+stepname+"); "
+javaname+"="+javaname+".add("+stepname+") ) {" );
addindent();
super.visit(stat.block);
oute( "}" );
}
private Name tmpJavaVar(String s) {
Name n = new Name(s);
n.variable = javascope.define(s);
return n;
}
public void visit(GenericFor stat) {
Name f = tmpJavaVar("f");
Name s = tmpJavaVar("s");
Name var = tmpJavaVar("var");
Name v = tmpJavaVar("v");
String javaf = javascope.getJavaName(f.variable);
String javas = javascope.getJavaName(s.variable);
String javavar = javascope.getJavaName(var.variable);
String javav = javascope.getJavaName(v.variable);
outl("LuaValue "+javaf+","+javas+","+javavar+";");
outl("Varargs "+javav+";");
List<Name> fsvar = new ArrayList<Name>();
fsvar.add(f);
fsvar.add(s);
fsvar.add(var);
multiAssign(fsvar, stat.exps);
outb("while (true) {");
outl( javav+" = "+javaf+".invoke(varargsOf("+javas+","+javavar+"));");
outl( "if (("+javavar+"="+javav+".arg1()).isnil()) break;");
singleLocalDeclareAssign(stat.names.get(0),javavar);
for ( int i=1, n=stat.names.size(); i<n; i++ )
singleLocalDeclareAssign(stat.names.get(i),javav+".arg("+(i+1)+")");
super.visit(stat.block);
oute("}");
}
public void visit(ParList pars) {
super.visit(pars);
}
public void visit(IfThenElse stat) {
outb( "if ( "+eval(stat.ifexp)+".toboolean() ) {");
super.visit(stat.ifblock);
if ( stat.elseifblocks != null )
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
subindent();
outl( "} else if ( "+eval(stat.elseifexps.get(i))+".toboolean() ) {");
addindent();
super.visit(stat.elseifblocks.get(i));
}
if ( stat.elseblock != null ) {
subindent();
outl( "} else {");
addindent();
super.visit( stat.elseblock );
}
oute( "}" );
}
public void visit(RepeatUntil stat) {
outb( "do {");
super.visit(stat.block);
oute( "} while (!"+eval(stat.exp)+".toboolean());" );
}
public void visit(TableConstructor table) {
if ( table.fields == null ) {
out("LuaValue.tableOf()");
} else {
int n = table.fields.size();
out("LuaValue.tableOf(new LuaValue[]{");
for ( int i=0; i<n; i++ ) {
TableField f = table.fields.get(i);
if ( f.name == null && f.index == null )
continue;
if ( f.name != null )
out( evalStringConstant(f.name)+"," );
else
out( eval(f.index)+"," );
out( eval(f.rhs)+"," );
}
out("},new LuaValue[] {");
for ( int i=0; i<n; i++ ) {
TableField f = table.fields.get(i);
if ( f.name == null && f.index == null )
out( eval(f.rhs)+"," );
}
out("})");
}
}
public void visit(WhileDo stat) {
outb( "while ("+eval(stat.exp)+") {");
super.visit(stat.block);
oute( "}" );
}
public void visitExps(List<Exp> exps) {
super.visitExps(exps);
}
public void visitNames(List<Name> names) {
super.visitNames(names);
}
public void visitVars(List<VarExp> vars) {
super.visitVars(vars);
}
}
private static String quotedStringInitializer(byte[] bytes) {
int n = bytes.length;
StringBuffer sb = new StringBuffer(n+2);
// check for characters beyond ascii 128
for ( int i=0; i<n; i++ )
if (bytes[i]<0) {
sb.append( "new byte[]{" );
for ( int j=0; j<n; j++ ) {
if ( j>0 ) sb.append(",");
byte b = bytes[j];
switch ( b ) {
case '\n': sb.append( "'\\n'" ); break;
case '\r': sb.append( "'\\r'" ); break;
case '\t': sb.append( "'\\t'" ); break;
case '\\': sb.append( "'\\\\'" ); break;
default:
if ( b >= ' ' ) {
sb.append( '\'');
sb.append( (char) b );
sb.append( '\'');
} else {
sb.append( String.valueOf((int)b) );
}
break;
}
}
sb.append( "}" );
return sb.toString();
}
sb.append('"');
for ( int i=0; i<n; i++ ) {
byte b = bytes[i];
switch ( b ) {
case '\b': sb.append( "\\b" ); break;
case '\f': sb.append( "\\f" ); break;
case '\n': sb.append( "\\n" ); break;
case '\r': sb.append( "\\r" ); break;
case '\t': sb.append( "\\t" ); break;
case '"': sb.append( "\\\"" ); break;
case '\\': sb.append( "\\\\" ); break;
default:
if ( b >= ' ' ) {
sb.append( (char) b ); break;
} else {
// convert from UTF-8
int u = 0xff & (int) b;
if ( u>=0xc0 && i+1<n ) {
if ( u>=0xe0 && i+2<n ) {
u = ((u & 0xf) << 12) | ((0x3f & bytes[i+1]) << 6) | (0x3f & bytes[i+2]);
i+= 2;
} else {
u = ((u & 0x1f) << 6) | (0x3f & bytes[++i]);
}
}
sb.append( "\\u" );
sb.append( Integer.toHexString(0x10000+u).substring(1) );
}
}
}
sb.append('"');
return sb.toString();
}
}

View File

@@ -0,0 +1,165 @@
/*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lua2java;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.luaj.vm2.Lua;
import org.luaj.vm2.ast.Block;
import org.luaj.vm2.ast.Chunk;
import org.luaj.vm2.ast.FuncBody;
import org.luaj.vm2.ast.NameScope;
import org.luaj.vm2.ast.Visitor;
import org.luaj.vm2.ast.Exp.BinopExp;
import org.luaj.vm2.ast.Stat.Return;
public class JavaScope extends NameScope {
private static final int MAX_CONSTNAME_LEN = 8;
public static final Set<String> SPECIALS = new HashSet<String>();
private static final String[] specials = {
// keywords used by our code generator
"name", "opcode", "env",
// java keywords
"abstract", "continue", "for", "new", "switch",
"assert", "default", "goto", "package", "synchronized",
"boolean", "do", "if", "private", "this",
"break", "double", "implements", "protected", "throw",
"byte", "else", "import", "public", "throws",
"case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try",
"char", "final", "interface", "static", "void",
"class", "finally", "long", "strictfp", "volatile",
"const", "float", "native", "super", "while",
};
static {
for ( int i=0; i<specials.length; i++ )
SPECIALS.add(specials[i]);
// TODO: add any via reflection from LuaValue
}
public int nreturns;
public boolean needsbinoptmp;
final Set<String> staticnames;
final Set<String> javanames = new HashSet<String>();
final Map<Object,String> astele2javaname = new HashMap<Object,String>();
// final public List<String> tmpvars = new ArrayList<String>();
private JavaScope(Set<String> staticnames, JavaScope outerScope) {
super(outerScope);
this.staticnames = staticnames;
}
public static JavaScope newJavaScope(Chunk chunk) {
return new JavaScope(new HashSet<String>(), null).initialize(chunk.block, -1);
}
public JavaScope pushJavaScope(FuncBody body) {
return new JavaScope(staticnames, this).initialize(body.block, 0);
}
public JavaScope popJavaScope() {
return (JavaScope) outerScope;
}
final String getJavaName(NamedVariable nv) {
if ( astele2javaname.containsKey(nv) )
return astele2javaname.get(nv);
return allocateJavaName( nv, nv.name );
}
// public String getTempVar(BinopExp exp) {
// return astele2javaname.containsKey(exp)? astele2javaname.get(exp): "$t";
// }
//
// public void allocateTempVar(BinopExp exp) {
// tmpvars.add( allocateJavaName( exp, "t" ) );
// }
//
final private String allocateJavaName(Object astele, String proposal) {
for ( int i=0; true; i++ ) {
String jname = proposal+(i==0? "": "$"+i);
if ( ! javanames.contains(jname) && ! SPECIALS.contains(jname) ) {
javanames.add(jname);
astele2javaname.put(astele,jname);
return jname;
}
}
}
public String createConstantName(String proposal) {
proposal = toLegalJavaName(proposal);
for ( int i=0; true; i++ ) {
String jname = proposal+(i==0? "": "$"+i);
if ( ! javanames.contains(jname) && ! SPECIALS.contains(jname) && !staticnames.contains(jname) ) {
javanames.add(jname);
staticnames.add(jname);
return jname;
}
}
}
public static String toLegalJavaName(String string) {
String better = string.replaceAll("[^\\w]", "_");
if ( better.length() > MAX_CONSTNAME_LEN )
better = better.substring(0,MAX_CONSTNAME_LEN);
// if ( !Character.isJavaIdentifierStart( better.charAt(0) ) )
// better = "_"+better;
return "$"+better;
}
private JavaScope initialize(Block block, int nreturns) {
NewScopeVisitor v = new NewScopeVisitor(nreturns);
block.accept( v );
this.nreturns = v.nreturns;
this.needsbinoptmp = v.needsbinoptmp;
return this;
}
class NewScopeVisitor extends Visitor {
int nreturns = 0;
boolean needsbinoptmp = false;
NewScopeVisitor(int nreturns) {
this.nreturns = nreturns;
}
public void visit(FuncBody body) {}
public void visit(Return s) {
int n = s.nreturns();
nreturns = (nreturns<0||n<0? -1: Math.max(n,nreturns));
}
public void visit(BinopExp exp) {
switch ( exp.op ) {
case Lua.OP_AND: case Lua.OP_OR:
needsbinoptmp = true;
break;
}
super.visit(exp);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
/* Generated By:JavaCC: Do not edit this line. LuaParserConstants.java */
package org.luaj.vm2.parser;
/**
* Token literal values and constants.
* Generated by org.javacc.parser.OtherFilesGen#start()
*/
public interface LuaParserConstants {
/** End of File. */
int EOF = 0;
/** RegularExpression Id. */
int COMMENT = 17;
/** RegularExpression Id. */
int LONGCOMMENT0 = 18;
/** RegularExpression Id. */
int LONGCOMMENT1 = 19;
/** RegularExpression Id. */
int LONGCOMMENT2 = 20;
/** RegularExpression Id. */
int LONGCOMMENT3 = 21;
/** RegularExpression Id. */
int LONGCOMMENTN = 22;
/** RegularExpression Id. */
int LONGSTRING0 = 23;
/** RegularExpression Id. */
int LONGSTRING1 = 24;
/** RegularExpression Id. */
int LONGSTRING2 = 25;
/** RegularExpression Id. */
int LONGSTRING3 = 26;
/** RegularExpression Id. */
int LONGSTRINGN = 27;
/** RegularExpression Id. */
int AND = 29;
/** RegularExpression Id. */
int BREAK = 30;
/** RegularExpression Id. */
int DO = 31;
/** RegularExpression Id. */
int ELSE = 32;
/** RegularExpression Id. */
int ELSEIF = 33;
/** RegularExpression Id. */
int END = 34;
/** RegularExpression Id. */
int FALSE = 35;
/** RegularExpression Id. */
int FOR = 36;
/** RegularExpression Id. */
int FUNCTION = 37;
/** RegularExpression Id. */
int IF = 38;
/** RegularExpression Id. */
int IN = 39;
/** RegularExpression Id. */
int LOCAL = 40;
/** RegularExpression Id. */
int NIL = 41;
/** RegularExpression Id. */
int NOT = 42;
/** RegularExpression Id. */
int OR = 43;
/** RegularExpression Id. */
int RETURN = 44;
/** RegularExpression Id. */
int REPEAT = 45;
/** RegularExpression Id. */
int THEN = 46;
/** RegularExpression Id. */
int TRUE = 47;
/** RegularExpression Id. */
int UNTIL = 48;
/** RegularExpression Id. */
int WHILE = 49;
/** RegularExpression Id. */
int NAME = 50;
/** RegularExpression Id. */
int NUMBER = 51;
/** RegularExpression Id. */
int FLOAT = 52;
/** RegularExpression Id. */
int DIGIT = 53;
/** RegularExpression Id. */
int EXP = 54;
/** RegularExpression Id. */
int HEX = 55;
/** RegularExpression Id. */
int HEXDIGIT = 56;
/** RegularExpression Id. */
int STRING = 57;
/** RegularExpression Id. */
int CHARSTRING = 58;
/** RegularExpression Id. */
int QUOTED = 59;
/** RegularExpression Id. */
int DECIMAL = 60;
/** RegularExpression Id. */
int UNICODE = 61;
/** RegularExpression Id. */
int CHAR = 62;
/** RegularExpression Id. */
int LF = 63;
/** Lexical state. */
int DEFAULT = 0;
/** Lexical state. */
int IN_COMMENT = 1;
/** Lexical state. */
int IN_LC0 = 2;
/** Lexical state. */
int IN_LC1 = 3;
/** Lexical state. */
int IN_LC2 = 4;
/** Lexical state. */
int IN_LC3 = 5;
/** Lexical state. */
int IN_LCN = 6;
/** Lexical state. */
int IN_LS0 = 7;
/** Lexical state. */
int IN_LS1 = 8;
/** Lexical state. */
int IN_LS2 = 9;
/** Lexical state. */
int IN_LS3 = 10;
/** Lexical state. */
int IN_LSN = 11;
/** Literal token values. */
String[] tokenImage = {
"<EOF>",
"\" \"",
"\"\\t\"",
"\"\\n\"",
"\"\\r\"",
"\"\\f\"",
"\"--[[\"",
"\"--[=[\"",
"\"--[==[\"",
"\"--[===[\"",
"<token of kind 10>",
"\"[[\"",
"\"[=[\"",
"\"[==[\"",
"\"[===[\"",
"<token of kind 15>",
"\"--\"",
"<COMMENT>",
"\"]]\"",
"\"]=]\"",
"\"]==]\"",
"\"]===]\"",
"<LONGCOMMENTN>",
"\"]]\"",
"\"]=]\"",
"\"]==]\"",
"\"]===]\"",
"<LONGSTRINGN>",
"<token of kind 28>",
"\"and\"",
"\"break\"",
"\"do\"",
"\"else\"",
"\"elseif\"",
"\"end\"",
"\"false\"",
"\"for\"",
"\"function\"",
"\"if\"",
"\"in\"",
"\"local\"",
"\"nil\"",
"\"not\"",
"\"or\"",
"\"return\"",
"\"repeat\"",
"\"then\"",
"\"true\"",
"\"until\"",
"\"while\"",
"<NAME>",
"<NUMBER>",
"<FLOAT>",
"<DIGIT>",
"<EXP>",
"<HEX>",
"<HEXDIGIT>",
"<STRING>",
"<CHARSTRING>",
"<QUOTED>",
"<DECIMAL>",
"<UNICODE>",
"<CHAR>",
"<LF>",
"\";\"",
"\"=\"",
"\",\"",
"\".\"",
"\":\"",
"\"(\"",
"\")\"",
"\"[\"",
"\"]\"",
"\"...\"",
"\"{\"",
"\"}\"",
"\"+\"",
"\"-\"",
"\"*\"",
"\"/\"",
"\"^\"",
"\"%\"",
"\"..\"",
"\"<\"",
"\"<=\"",
"\">\"",
"\">=\"",
"\"==\"",
"\"~=\"",
"\"#\"",
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */
/* JavaCCOptions:KEEP_LINE_COL=null */
package org.luaj.vm2.parser;
/**
* This exception is thrown when parse errors are encountered.
* You can explicitly create objects of this exception type by
* calling the method generateParseException in the generated
* parser.
*
* You can modify this class to customize your error reporting
* mechanisms so long as you retain the public fields.
*/
public class ParseException extends Exception {
/**
* The version identifier for this Serializable class.
* Increment only if the <i>serialized</i> form of the
* class changes.
*/
private static final long serialVersionUID = 1L;
/**
* This constructor is used by the method "generateParseException"
* in the generated parser. Calling this constructor generates
* a new object of this type with the fields "currentToken",
* "expectedTokenSequences", and "tokenImage" set.
*/
public ParseException(Token currentTokenVal,
int[][] expectedTokenSequencesVal,
String[] tokenImageVal
)
{
super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
currentToken = currentTokenVal;
expectedTokenSequences = expectedTokenSequencesVal;
tokenImage = tokenImageVal;
}
/**
* The following constructors are for use by you for whatever
* purpose you can think of. Constructing the exception in this
* manner makes the exception behave in the normal way - i.e., as
* documented in the class "Throwable". The fields "errorToken",
* "expectedTokenSequences", and "tokenImage" do not contain
* relevant information. The JavaCC generated code does not use
* these constructors.
*/
public ParseException() {
super();
}
/** Constructor with message. */
public ParseException(String message) {
super(message);
}
/**
* This is the last token that has been consumed successfully. If
* this object has been created due to a parse error, the token
* followng this token will (therefore) be the first error token.
*/
public Token currentToken;
/**
* Each entry in this array is an array of integers. Each array
* of integers represents a sequence of tokens (by their ordinal
* values) that is expected at this point of the parse.
*/
public int[][] expectedTokenSequences;
/**
* This is a reference to the "tokenImage" array of the generated
* parser within which the parse error occurred. This array is
* defined in the generated ...Constants interface.
*/
public String[] tokenImage;
/**
* It uses "currentToken" and "expectedTokenSequences" to generate a parse
* error message and returns it. If this object has been created
* due to a parse error, and you do not catch it (it gets thrown
* from the parser) the correct error message
* gets displayed.
*/
private static String initialise(Token currentToken,
int[][] expectedTokenSequences,
String[] tokenImage) {
String eol = System.getProperty("line.separator", "\n");
StringBuffer expected = new StringBuffer();
int maxSize = 0;
for (int i = 0; i < expectedTokenSequences.length; i++) {
if (maxSize < expectedTokenSequences[i].length) {
maxSize = expectedTokenSequences[i].length;
}
for (int j = 0; j < expectedTokenSequences[i].length; j++) {
expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
}
if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
expected.append("...");
}
expected.append(eol).append(" ");
}
String retval = "Encountered \"";
Token tok = currentToken.next;
for (int i = 0; i < maxSize; i++) {
if (i != 0) retval += " ";
if (tok.kind == 0) {
retval += tokenImage[0];
break;
}
retval += " " + tokenImage[tok.kind];
retval += " \"";
retval += add_escapes(tok.image);
retval += " \"";
tok = tok.next;
}
retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
retval += "." + eol;
if (expectedTokenSequences.length == 1) {
retval += "Was expecting:" + eol + " ";
} else {
retval += "Was expecting one of:" + eol + " ";
}
retval += expected.toString();
return retval;
}
/**
* The end of line string for this machine.
*/
protected String eol = System.getProperty("line.separator", "\n");
/**
* Used to convert raw characters to their escaped version
* when these raw version cannot be used as part of an ASCII
* string literal.
*/
static String add_escapes(String str) {
StringBuffer retval = new StringBuffer();
char ch;
for (int i = 0; i < str.length(); i++) {
switch (str.charAt(i))
{
case 0 :
continue;
case '\b':
retval.append("\\b");
continue;
case '\t':
retval.append("\\t");
continue;
case '\n':
retval.append("\\n");
continue;
case '\f':
retval.append("\\f");
continue;
case '\r':
retval.append("\\r");
continue;
case '\"':
retval.append("\\\"");
continue;
case '\'':
retval.append("\\\'");
continue;
case '\\':
retval.append("\\\\");
continue;
default:
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
String s = "0000" + Integer.toString(ch, 16);
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
} else {
retval.append(ch);
}
continue;
}
}
return retval.toString();
}
}
/* JavaCC - OriginalChecksum=ef246095a930e4915c0d4bbf4c9880ad (do not edit this line) */

View File

@@ -0,0 +1,469 @@
/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.luaj.vm2.parser;
/**
* An implementation of interface CharStream, where the stream is assumed to
* contain only ASCII characters (without unicode processing).
*/
public class SimpleCharStream
{
/** Whether parser is static. */
public static final boolean staticFlag = false;
int bufsize;
int available;
int tokenBegin;
/** Position in buffer. */
public int bufpos = -1;
protected int bufline[];
protected int bufcolumn[];
protected int column = 0;
protected int line = 1;
protected boolean prevCharIsCR = false;
protected boolean prevCharIsLF = false;
protected java.io.Reader inputStream;
protected char[] buffer;
protected int maxNextCharInd = 0;
protected int inBuf = 0;
protected int tabSize = 8;
protected void setTabSize(int i) { tabSize = i; }
protected int getTabSize(int i) { return tabSize; }
protected void ExpandBuff(boolean wrapAround)
{
char[] newbuffer = new char[bufsize + 2048];
int newbufline[] = new int[bufsize + 2048];
int newbufcolumn[] = new int[bufsize + 2048];
try
{
if (wrapAround)
{
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
buffer = newbuffer;
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
bufline = newbufline;
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
bufcolumn = newbufcolumn;
maxNextCharInd = (bufpos += (bufsize - tokenBegin));
}
else
{
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
buffer = newbuffer;
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
bufline = newbufline;
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
bufcolumn = newbufcolumn;
maxNextCharInd = (bufpos -= tokenBegin);
}
}
catch (Throwable t)
{
throw new Error(t.getMessage());
}
bufsize += 2048;
available = bufsize;
tokenBegin = 0;
}
protected void FillBuff() throws java.io.IOException
{
if (maxNextCharInd == available)
{
if (available == bufsize)
{
if (tokenBegin > 2048)
{
bufpos = maxNextCharInd = 0;
available = tokenBegin;
}
else if (tokenBegin < 0)
bufpos = maxNextCharInd = 0;
else
ExpandBuff(false);
}
else if (available > tokenBegin)
available = bufsize;
else if ((tokenBegin - available) < 2048)
ExpandBuff(true);
else
available = tokenBegin;
}
int i;
try {
if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
{
inputStream.close();
throw new java.io.IOException();
}
else
maxNextCharInd += i;
return;
}
catch(java.io.IOException e) {
--bufpos;
backup(0);
if (tokenBegin == -1)
tokenBegin = bufpos;
throw e;
}
}
/** Start. */
public char BeginToken() throws java.io.IOException
{
tokenBegin = -1;
char c = readChar();
tokenBegin = bufpos;
return c;
}
protected void UpdateLineColumn(char c)
{
column++;
if (prevCharIsLF)
{
prevCharIsLF = false;
line += (column = 1);
}
else if (prevCharIsCR)
{
prevCharIsCR = false;
if (c == '\n')
{
prevCharIsLF = true;
}
else
line += (column = 1);
}
switch (c)
{
case '\r' :
prevCharIsCR = true;
break;
case '\n' :
prevCharIsLF = true;
break;
case '\t' :
column--;
column += (tabSize - (column % tabSize));
break;
default :
break;
}
bufline[bufpos] = line;
bufcolumn[bufpos] = column;
}
/** Read a character. */
public char readChar() throws java.io.IOException
{
if (inBuf > 0)
{
--inBuf;
if (++bufpos == bufsize)
bufpos = 0;
return buffer[bufpos];
}
if (++bufpos >= maxNextCharInd)
FillBuff();
char c = buffer[bufpos];
UpdateLineColumn(c);
return c;
}
/**
* @deprecated
* @see #getEndColumn
*/
public int getColumn() {
return bufcolumn[bufpos];
}
/**
* @deprecated
* @see #getEndLine
*/
public int getLine() {
return bufline[bufpos];
}
/** Get token end column number. */
public int getEndColumn() {
return bufcolumn[bufpos];
}
/** Get token end line number. */
public int getEndLine() {
return bufline[bufpos];
}
/** Get token beginning column number. */
public int getBeginColumn() {
return bufcolumn[tokenBegin];
}
/** Get token beginning line number. */
public int getBeginLine() {
return bufline[tokenBegin];
}
/** Backup a number of characters. */
public void backup(int amount) {
inBuf += amount;
if ((bufpos -= amount) < 0)
bufpos += bufsize;
}
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
inputStream = dstream;
line = startline;
column = startcolumn - 1;
available = bufsize = buffersize;
buffer = new char[buffersize];
bufline = new int[buffersize];
bufcolumn = new int[buffersize];
}
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn)
{
this(dstream, startline, startcolumn, 4096);
}
/** Constructor. */
public SimpleCharStream(java.io.Reader dstream)
{
this(dstream, 1, 1, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
inputStream = dstream;
line = startline;
column = startcolumn - 1;
if (buffer == null || buffersize != buffer.length)
{
available = bufsize = buffersize;
buffer = new char[buffersize];
bufline = new int[buffersize];
bufcolumn = new int[buffersize];
}
prevCharIsLF = prevCharIsCR = false;
tokenBegin = inBuf = maxNextCharInd = 0;
bufpos = -1;
}
/** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn)
{
ReInit(dstream, startline, startcolumn, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.Reader dstream)
{
ReInit(dstream, 1, 1, 4096);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
this(dstream, encoding, startline, startcolumn, 4096);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn)
{
this(dstream, startline, startcolumn, 4096);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
this(dstream, encoding, 1, 1, 4096);
}
/** Constructor. */
public SimpleCharStream(java.io.InputStream dstream)
{
this(dstream, 1, 1, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
ReInit(dstream, encoding, 1, 1, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream)
{
ReInit(dstream, 1, 1, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
ReInit(dstream, encoding, startline, startcolumn, 4096);
}
/** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn)
{
ReInit(dstream, startline, startcolumn, 4096);
}
/** Get token literal value. */
public String GetImage()
{
if (bufpos >= tokenBegin)
return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
else
return new String(buffer, tokenBegin, bufsize - tokenBegin) +
new String(buffer, 0, bufpos + 1);
}
/** Get the suffix. */
public char[] GetSuffix(int len)
{
char[] ret = new char[len];
if ((bufpos + 1) >= len)
System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
else
{
System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
len - bufpos - 1);
System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
}
return ret;
}
/** Reset buffer when finished. */
public void Done()
{
buffer = null;
bufline = null;
bufcolumn = null;
}
/**
* Method to adjust line and column numbers for the start of a token.
*/
public void adjustBeginLineColumn(int newLine, int newCol)
{
int start = tokenBegin;
int len;
if (bufpos >= tokenBegin)
{
len = bufpos - tokenBegin + inBuf + 1;
}
else
{
len = bufsize - tokenBegin + bufpos + 1 + inBuf;
}
int i = 0, j = 0, k = 0;
int nextColDiff = 0, columnDiff = 0;
while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
{
bufline[j] = newLine;
nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
bufcolumn[j] = newCol + columnDiff;
columnDiff = nextColDiff;
i++;
}
if (i < len)
{
bufline[j] = newLine++;
bufcolumn[j] = newCol + columnDiff;
while (i++ < len)
{
if (bufline[j = start % bufsize] != bufline[++start % bufsize])
bufline[j] = newLine++;
else
bufline[j] = newLine;
}
}
line = bufline[j];
column = bufcolumn[j];
}
}
/* JavaCC - OriginalChecksum=ab0c629eabd887d4c88cec51eb5e6477 (do not edit this line) */

View File

@@ -0,0 +1,131 @@
/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.luaj.vm2.parser;
/**
* Describes the input token stream.
*/
public class Token implements java.io.Serializable {
/**
* The version identifier for this Serializable class.
* Increment only if the <i>serialized</i> form of the
* class changes.
*/
private static final long serialVersionUID = 1L;
/**
* An integer that describes the kind of this token. This numbering
* system is determined by JavaCCParser, and a table of these numbers is
* stored in the file ...Constants.java.
*/
public int kind;
/** The line number of the first character of this Token. */
public int beginLine;
/** The column number of the first character of this Token. */
public int beginColumn;
/** The line number of the last character of this Token. */
public int endLine;
/** The column number of the last character of this Token. */
public int endColumn;
/**
* The string image of the token.
*/
public String image;
/**
* A reference to the next regular (non-special) token from the input
* stream. If this is the last token from the input stream, or if the
* token manager has not read tokens beyond this one, this field is
* set to null. This is true only if this token is also a regular
* token. Otherwise, see below for a description of the contents of
* this field.
*/
public Token next;
/**
* This field is used to access special tokens that occur prior to this
* token, but after the immediately preceding regular (non-special) token.
* If there are no such special tokens, this field is set to null.
* When there are more than one such special token, this field refers
* to the last of these special tokens, which in turn refers to the next
* previous special token through its specialToken field, and so on
* until the first special token (whose specialToken field is null).
* The next fields of special tokens refer to other special tokens that
* immediately follow it (without an intervening regular token). If there
* is no such token, this field is null.
*/
public Token specialToken;
/**
* An optional attribute value of the Token.
* Tokens which are not used as syntactic sugar will often contain
* meaningful values that will be used later on by the compiler or
* interpreter. This attribute value is often different from the image.
* Any subclass of Token that actually wants to return a non-null value can
* override this method as appropriate.
*/
public Object getValue() {
return null;
}
/**
* No-argument constructor
*/
public Token() {}
/**
* Constructs a new token for the specified Image.
*/
public Token(int kind)
{
this(kind, null);
}
/**
* Constructs a new token for the specified Image and Kind.
*/
public Token(int kind, String image)
{
this.kind = kind;
this.image = image;
}
/**
* Returns the image.
*/
public String toString()
{
return image;
}
/**
* Returns a new Token object, by default. However, if you want, you
* can create and return subclass objects based on the value of ofKind.
* Simply add the cases to the switch for all those special cases.
* For example, if you have a subclass of Token called IDToken that
* you want to create if ofKind is ID, simply add something like :
*
* case MyParserConstants.ID : return new IDToken(ofKind, image);
*
* to the following switch statement. Then you can cast matchedToken
* variable to the appropriate type and use sit in your lexical actions.
*/
public static Token newToken(int ofKind, String image)
{
switch(ofKind)
{
default : return new Token(ofKind, image);
}
}
public static Token newToken(int ofKind)
{
return newToken(ofKind, null);
}
}
/* JavaCC - OriginalChecksum=70d73add5771158f10d1ae81755e7cfc (do not edit this line) */

View File

@@ -0,0 +1,147 @@
/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
/* JavaCCOptions: */
package org.luaj.vm2.parser;
/** Token Manager Error. */
public class TokenMgrError extends Error
{
/**
* The version identifier for this Serializable class.
* Increment only if the <i>serialized</i> form of the
* class changes.
*/
private static final long serialVersionUID = 1L;
/*
* Ordinals for various reasons why an Error of this type can be thrown.
*/
/**
* Lexical error occurred.
*/
static final int LEXICAL_ERROR = 0;
/**
* An attempt was made to create a second instance of a static token manager.
*/
static final int STATIC_LEXER_ERROR = 1;
/**
* Tried to change to an invalid lexical state.
*/
static final int INVALID_LEXICAL_STATE = 2;
/**
* Detected (and bailed out of) an infinite loop in the token manager.
*/
static final int LOOP_DETECTED = 3;
/**
* Indicates the reason why the exception is thrown. It will have
* one of the above 4 values.
*/
int errorCode;
/**
* Replaces unprintable characters by their escaped (or unicode escaped)
* equivalents in the given string
*/
protected static final String addEscapes(String str) {
StringBuffer retval = new StringBuffer();
char ch;
for (int i = 0; i < str.length(); i++) {
switch (str.charAt(i))
{
case 0 :
continue;
case '\b':
retval.append("\\b");
continue;
case '\t':
retval.append("\\t");
continue;
case '\n':
retval.append("\\n");
continue;
case '\f':
retval.append("\\f");
continue;
case '\r':
retval.append("\\r");
continue;
case '\"':
retval.append("\\\"");
continue;
case '\'':
retval.append("\\\'");
continue;
case '\\':
retval.append("\\\\");
continue;
default:
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
String s = "0000" + Integer.toString(ch, 16);
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
} else {
retval.append(ch);
}
continue;
}
}
return retval.toString();
}
/**
* Returns a detailed message for the Error when it is thrown by the
* token manager to indicate a lexical error.
* Parameters :
* EOFSeen : indicates if EOF caused the lexical error
* curLexState : lexical state in which this error occurred
* errorLine : line number when the error occurred
* errorColumn : column number when the error occurred
* errorAfter : prefix that was seen before this error occurred
* curchar : the offending character
* Note: You can customize the lexical error message by modifying this method.
*/
protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
return("Lexical error at line " +
errorLine + ", column " +
errorColumn + ". Encountered: " +
(EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
"after : \"" + addEscapes(errorAfter) + "\"");
}
/**
* You can also modify the body of this method to customize your error messages.
* For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
* of end-users concern, so you can return something like :
*
* "Internal Error : Please file a bug report .... "
*
* from this method for such cases in the release version of your parser.
*/
public String getMessage() {
return super.getMessage();
}
/*
* Constructors of various flavors follow.
*/
/** No arg constructor. */
public TokenMgrError() {
}
/** Constructor with message and reason. */
public TokenMgrError(String message, int reason) {
super(message);
errorCode = reason;
}
/** Full Constructor. */
public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
}
}
/* JavaCC - OriginalChecksum=bd3720425dc7b44a5223b12676db358c (do not edit this line) */