/*******************************************************************************
* 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);
}
}
}