Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }