| 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; |
| } |
| } |