public VariableId RegisterVariableForcedReDeclaration(AType type, string name, Token throwToken) { if (this.idsByVar.ContainsKey(name)) { throw new ParserException(throwToken, "This variable has already been used in this scope."); } VariableId varId = new VariableId(type, name); this.idsByVar[name] = varId; this.rootScope.usedVariableNames.Add(name); this.variableToUseIfNotFoundInDirectParent[name] = varId; this.rootScope.rootScopeOrder.Add(varId); return(varId); }
public VariableId RegisterVariable(AType type, string name, bool allowSameScopeCollisions) { // Before anything else, check to see if this is coming from the closure. VariableScope closureWalker = this.closureScope; while (closureWalker != null) { VariableId closureVarId; if (closureWalker.idsByVar.TryGetValue(name, out closureVarId)) { MarkVarAsClosureVarThroughParentChain(this, closureWalker, closureVarId); return(closureVarId); } closureWalker = closureWalker.closureScope; } VariableId varId; // Check if variable is already declared in this or a parent scope already. if (rootScope.usedVariableNames.Contains(name)) { // The above if statement is a quick check to see if variable used before, anywhere, // even if in a parallel branch. This will prevent many unnecessary walks up the parent chain. // Variable is already known by this scope. Nothing to do. if (this.idsByVar.TryGetValue(name, out varId)) { return(varId); } if (this.variableToUseIfNotFoundInDirectParent.TryGetValue(name, out varId)) { return(varId); } // Check to see if this variable was used by this or any parent scope. VariableScope walker = this.parentScope; while (walker != null) { if (walker.idsByVar.TryGetValue(name, out varId)) { // cache this value in the current scope to make the lookup faster in the future this.idsByVar[name] = varId; return(varId); } walker = walker.parentScope; } // Do it again but using the fuzzy fallback walker = this; while (walker != null) { if (walker.variableToUseIfNotFoundInDirectParent.ContainsKey(name)) { varId = walker.variableToUseIfNotFoundInDirectParent[name]; this.idsByVar[name] = varId; return(varId); } } // This should not happen. #if DEBUG throw new System.InvalidOperationException("Couldn't find variable declaration: " + name); #endif } // Variable has never been used anywhere. Create a new one and put it in the root bookkeeping. varId = new VariableId(type, name); this.variableToUseIfNotFoundInDirectParent.Add(name, varId); this.idsByVar[name] = varId; this.rootScope.usedVariableNames.Add(name); this.rootScope.rootScopeOrder.Add(varId); return(varId); }
private void MarkVarAsClosureVarThroughParentChain(VariableScope fromScope, VariableScope toScope, VariableId varId) { if (!varId.UsedByClosure) { varId.ClosureID = fromScope.closureRootScope.closureIdAlloc++; varId.UsedByClosure = true; } do { fromScope.idsByVar[varId.Name] = varId; fromScope = fromScope.closureScope; } while (fromScope != toScope); }