/******************************************************************************* * 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.ast; import org.luaj.vm2.Lua; import org.luaj.vm2.LuaValue; abstract public class Exp extends SyntaxElement { abstract public void accept(Visitor visitor); public static Exp constant(LuaValue value) { return new Constant(value); } public static Exp numberconstant(String token) { return new Constant( LuaValue.valueOf(token).tonumber() ); } public static Exp varargs() { return new VarargsExp(); } public static Exp tableconstructor(TableConstructor tc) { return tc; } 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); } 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); } 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: case Lua.OP_MOD: 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) { return new AnonFuncDef(funcbody); } /** foo */ public static NameExp nameprefix(String name) { return new NameExp(name); } /** ( foo.bar ) */ public static ParensExp parensprefix(Exp exp) { return new ParensExp(exp); } /** foo[exp] */ public static IndexExp indexop(PrimaryExp lhs, Exp exp) { return new IndexExp(lhs, exp); } /** foo.bar */ public static FieldExp fieldop(PrimaryExp lhs, String name) { return new FieldExp(lhs, name); } /** foo(2,3) */ public static FuncCall functionop(PrimaryExp lhs, FuncArgs args) { return new FuncCall(lhs, args); } /** foo:bar(4,5) */ public static MethodCall methodop(PrimaryExp lhs, String name, FuncArgs args) { return new MethodCall(lhs, name, args); } public boolean isvarexp() { return false; } public boolean isfunccall() { return false; } public boolean isvarargexp() { return false; } abstract public static class PrimaryExp extends Exp { public boolean isvarexp() { return false; } public boolean isfunccall() { return false; } } abstract public static class VarExp extends PrimaryExp { public boolean isvarexp() { return true; } public void markHasAssignment() { } } public static class NameExp extends VarExp { public final Name name; public NameExp(String name) { this.name = new Name(name); } public void markHasAssignment() { name.variable.hasassignments = true; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class ParensExp extends PrimaryExp { public final Exp exp; public ParensExp(Exp exp) { this.exp = exp; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class FieldExp extends VarExp { public final PrimaryExp lhs; public final Name name; public FieldExp(PrimaryExp lhs, String name) { this.lhs = lhs; this.name = new Name(name); } public void accept(Visitor visitor) { visitor.visit(this); } } public static class IndexExp extends VarExp { public final PrimaryExp lhs; public final Exp exp; public IndexExp(PrimaryExp lhs, Exp exp) { this.lhs = lhs; this.exp = exp; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class FuncCall extends PrimaryExp { public final PrimaryExp lhs; public final FuncArgs args; public FuncCall(PrimaryExp lhs, FuncArgs args) { this.lhs = lhs; this.args = args; } public boolean isfunccall() { return true; } public void accept(Visitor visitor) { visitor.visit(this); } public boolean isvarargexp() { return true; } } public static class MethodCall extends FuncCall { public final String name; public MethodCall(PrimaryExp lhs, String name, FuncArgs args) { super(lhs, args); this.name = new String(name); } public boolean isfunccall() { return true; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class Constant extends Exp { public final LuaValue value; public Constant(LuaValue value) { this.value = value; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class VarargsExp extends Exp { public void accept(Visitor visitor) { visitor.visit(this); } public boolean isvarargexp() { return true; } } public static class UnopExp extends Exp { public final int op; public final Exp rhs; public UnopExp(int op, Exp rhs) { this.op = op; this.rhs = rhs; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class BinopExp extends Exp { public final Exp lhs,rhs; public final int op; public BinopExp(Exp lhs, int op, Exp rhs) { this.lhs = lhs; this.op = op; this.rhs = rhs; } public void accept(Visitor visitor) { visitor.visit(this); } } public static class AnonFuncDef extends Exp { public final FuncBody body; public AnonFuncDef(FuncBody funcbody) { this.body = funcbody; } public void accept(Visitor visitor) { visitor.visit(this); } } }