| /******************************************************************************* |
| * 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.vm3.ast; |
| |
| import org.luaj.vm3.Lua; |
| import org.luaj.vm3.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); |
| } |
| } |
| |
| } |