/// <summary> /// Declares a variable or function in this scope. This will be initialized with the value /// of the given expression. /// </summary> /// <param name="keyword"> The keyword that was used to declare the variable (var, let or /// const). </param> /// <param name="name"> The name of the variable. </param> /// <param name="hoistedFunction"> The function value to hoist to the top of the scope. /// Should be <c>null</c> for everything except function declarations. </param> /// <returns> A reference to the variable that was declared. </returns> internal void DeclareVariable(KeywordToken keyword, string name, FunctionExpression hoistedFunction = null) { if (name == null) { throw new ArgumentNullException(nameof(name)); } // If variables cannot be declared in the scope, try the parent scope instead. var declarationScope = this; if (keyword == KeywordToken.Var) { while (declarationScope != null && (declarationScope.Type == ScopeType.Block || declarationScope.Type == ScopeType.With)) { declarationScope = declarationScope.ParentScope; } } if (declarationScope != null && !declarationScope.variables.ContainsKey(name)) { // This is a local variable that has not been declared before. var variable = new DeclaredVariable() { Scope = declarationScope, Index = declarationScope.variables.Count, Keyword = keyword, Name = name, }; declarationScope.variables.Add(name, variable); } if (hoistedFunction != null) { var hoistedScope = this; while (hoistedScope != null && hoistedScope.Type == ScopeType.Block) { hoistedScope = hoistedScope.ParentScope; } if (hoistedScope.hoistedFunctions == null) { hoistedScope.hoistedFunctions = new Dictionary <string, FunctionExpression>(); } hoistedScope.hoistedFunctions[name] = hoistedFunction; } }
/// <summary> /// Declares a variable or function in this scope. This will be initialized with the value /// of the given expression. /// </summary> /// <param name="name"> The name of the variable. </param> /// <param name="valueAtTopOfScope"> The value of the variable at the top of the scope. /// Can be <c>null</c> to indicate the variable does not need initializing. </param> /// <param name="writable"> <c>true</c> if the variable can be modified; <c>false</c> /// otherwise. Defaults to <c>true</c>. </param> /// <param name="deletable"> <c>true</c> if the variable can be deleted; <c>false</c> /// otherwise. Defaults to <c>true</c>. </param> /// <returns> A reference to the variable that was declared. </returns> internal virtual DeclaredVariable DeclareVariable(string name, Expression valueAtTopOfScope = null, bool writable = true, bool deletable = false) { if (name == null) { throw new ArgumentNullException(nameof(name)); } // If variables cannot be declared in the scope, try the parent scope instead. if (this.CanDeclareVariables == false) { if (this.ParentScope == null) { throw new InvalidOperationException("Invalid scope chain."); } return(this.ParentScope.DeclareVariable(name, valueAtTopOfScope, writable, deletable)); } DeclaredVariable variable; this.variables.TryGetValue(name, out variable); if (variable == null) { // This is a local variable that has not been declared before. variable = new DeclaredVariable() { Scope = this, Index = this.variables.Count, Name = name, Writable = writable, Deletable = deletable }; this.variables.Add(name, variable); } // Set the initial value, if one was provided. if (valueAtTopOfScope != null) { // Function expressions override literals. if ((valueAtTopOfScope is LiteralExpression && variable.ValueAtTopOfScope is FunctionExpression) == false) { variable.ValueAtTopOfScope = valueAtTopOfScope; } } return(variable); }
/// <summary> /// Declares a variable or function in this scope. This will be initialized with the value /// of the given expression. /// </summary> /// <param name="name"> The name of the variable. </param> /// <param name="valueAtTopOfScope"> The value of the variable at the top of the scope. /// Can be <c>null</c> to indicate the variable does not need initializing. </param> /// <param name="writable"> <c>true</c> if the variable can be modified; <c>false</c> /// otherwise. Defaults to <c>true</c>. </param> /// <param name="deletable"> <c>true</c> if the variable can be deleted; <c>false</c> /// otherwise. Defaults to <c>true</c>. </param> /// <returns> A reference to the variable that was declared. </returns> internal virtual DeclaredVariable DeclareVariable(string name, Expression valueAtTopOfScope = null, bool writable = true, bool deletable = false) { if (name == null) throw new ArgumentNullException("name"); // If variables cannot be declared in the scope, try the parent scope instead. if (this.CanDeclareVariables == false) { if (this.ParentScope == null) throw new InvalidOperationException("Invalid scope chain."); return this.ParentScope.DeclareVariable(name, valueAtTopOfScope, writable, deletable); } DeclaredVariable variable; this.variables.TryGetValue(name, out variable); if (variable == null) { // This is a local variable that has not been declared before. variable = new DeclaredVariable() { Scope = this, Index = this.variables.Count, Name = name, Writable = writable, Deletable = deletable }; this.variables.Add(name, variable); } // Set the initial value, if one was provided. if (valueAtTopOfScope != null) { // Function expressions override literals. if ((valueAtTopOfScope is LiteralExpression && variable.ValueAtTopOfScope is FunctionExpression) == false) variable.ValueAtTopOfScope = valueAtTopOfScope; } return variable; }