package org.luaj.vm2.ast; import java.util.List; import org.luaj.vm2.LuaValue; import org.luaj.vm2.ast.Exp.Constant; import org.luaj.vm2.ast.Exp.NameExp; import org.luaj.vm2.ast.Exp.VarExp; import org.luaj.vm2.ast.Stat.Assign; import org.luaj.vm2.ast.Stat.FuncDef; import org.luaj.vm2.ast.Stat.GenericFor; import org.luaj.vm2.ast.Stat.LocalAssign; import org.luaj.vm2.ast.Stat.LocalFuncDef; import org.luaj.vm2.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; } }