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