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