| package org.luaj.vm3.ast; |
| |
| import java.util.List; |
| |
| import org.luaj.vm3.LuaValue; |
| import org.luaj.vm3.ast.Exp.Constant; |
| import org.luaj.vm3.ast.Exp.NameExp; |
| import org.luaj.vm3.ast.Exp.VarExp; |
| import org.luaj.vm3.ast.Stat.Assign; |
| import org.luaj.vm3.ast.Stat.FuncDef; |
| import org.luaj.vm3.ast.Stat.GenericFor; |
| import org.luaj.vm3.ast.Stat.LocalAssign; |
| import org.luaj.vm3.ast.Stat.LocalFuncDef; |
| import org.luaj.vm3.ast.Stat.NumericFor; |
| |
| /** |
| * Visitor that resolves names to scopes. |
| * Each Name is resolved to a NamedVarible, possibly in a NameScope |
| * if it is a local, or in no named scope if it is a global. |
| */ |
| public class NameResolver extends Visitor { |
| |
| private NameScope scope = null; |
| |
| private void pushScope() { |
| scope = new NameScope(scope); |
| } |
| |
| private void popScope() { |
| scope = scope.outerScope; |
| } |
| |
| public void visit(NameScope scope) {} |
| |
| public void visit(Block block) { |
| pushScope(); |
| block.scope = scope; |
| super.visit(block); |
| popScope(); |
| } |
| |
| public void visit(FuncBody body) { |
| pushScope(); |
| scope.functionNestingCount++; |
| body.scope = scope; |
| super.visit(body); |
| popScope(); |
| } |
| |
| public void visit(LocalFuncDef stat) { |
| defineLocalVar(stat.name); |
| super.visit(stat); |
| } |
| |
| public void visit(NumericFor stat) { |
| pushScope(); |
| stat.scope = scope; |
| defineLocalVar(stat.name); |
| super.visit(stat); |
| popScope(); |
| } |
| |
| public void visit(GenericFor stat) { |
| pushScope(); |
| stat.scope = scope; |
| defineLocalVars(stat.names); |
| super.visit(stat); |
| popScope(); |
| } |
| |
| public void visit(NameExp exp) { |
| exp.name.variable = resolveNameReference(exp.name); |
| super.visit(exp); |
| } |
| |
| public void visit(FuncDef stat) { |
| stat.name.name.variable = resolveNameReference(stat.name.name); |
| stat.name.name.variable.hasassignments = true; |
| super.visit(stat); |
| } |
| |
| public void visit(Assign stat) { |
| super.visit(stat); |
| for (int i = 0, n = stat.vars.size(); i < n; i++) { |
| VarExp v = (VarExp) stat.vars.get(i); |
| v.markHasAssignment(); |
| } |
| } |
| |
| public void visit(LocalAssign stat) { |
| visitExps(stat.values); |
| defineLocalVars(stat.names); |
| int n = stat.names.size(); |
| int m = stat.values != null ? stat.values.size() : 0; |
| boolean isvarlist = m > 0 && m < n && ((Exp) stat.values.get(m - 1)).isvarargexp(); |
| for (int i = 0; i < n && i < (isvarlist ? m - 1 : m); i++) |
| if (stat.values.get(i) instanceof Constant) |
| ((Name) stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value; |
| if (!isvarlist) |
| for (int i = m; i < n; i++) |
| ((Name) stat.names.get(i)).variable.initialValue = LuaValue.NIL; |
| } |
| |
| public void visit(ParList pars) { |
| if (pars.names != null) |
| defineLocalVars(pars.names); |
| if (pars.isvararg) |
| scope.define("arg"); |
| super.visit(pars); |
| } |
| |
| protected void defineLocalVars(List<Name> names) { |
| for (int i = 0, n = names.size(); i < n; i++) |
| defineLocalVar((Name) names.get(i)); |
| } |
| |
| protected void defineLocalVar(Name name) { |
| name.variable = scope.define(name.name); |
| } |
| |
| protected Variable resolveNameReference(Name name) { |
| Variable v = scope.find(name.name); |
| if (v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount) |
| v.isupvalue = true; |
| return v; |
| } |
| } |