/// <summary> /// Creates a new ExpressionStatement instance. By default, this expression does not /// contribute to the result of an eval(). /// </summary> /// <param name="expression"> The underlying expression. </param> public ExpressionStatement(Expression expression) : base(null) { if (expression == null) throw new ArgumentNullException("expression"); this.Expression = expression; }
/// <summary> /// Creates a new ExpressionStatement instance. By default, this expression does /// contribute to the result of an eval(). /// </summary> /// <param name="labels"> The labels that are associated with this statement. </param> /// <param name="expression"> The underlying expression. </param> public ExpressionStatement(IList<string> labels, Expression expression) : base(labels) { if (expression == null) throw new ArgumentNullException("expression"); this.Expression = expression; this.ContributesToEvalResult = true; }
/// <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. </param> /// <param name="writable"> <c>true</c> if the variable can be modified; <c>false</c> /// otherwise. </param> /// <param name="deletable"> <c>true</c> if the variable can be deleted; <c>false</c> /// otherwise. </param> /// <returns> A reference to the variable that was declared. </returns> internal override DeclaredVariable DeclareVariable(string name, Expression valueAtTopOfScope = null, bool writable = true, bool deletable = false) { // Variables can be added to a declarative scope using eval(). When this happens the // values array needs to be resized. That check happens here. if (this.values != null && this.DeclaredVariableCount >= this.Values.Length) Array.Resize(ref this.values, this.DeclaredVariableCount + 10); // Delegate to the Scope class. return base.DeclareVariable(name, valueAtTopOfScope, writable, deletable); }
/// <summary> /// Checks the given AST is valid. /// </summary> /// <param name="root"> The root of the AST. </param> private void CheckASTValidity(Expression root) { // Push the root expression onto a stack. Stack<Expression> stack = new Stack<Expression>(); stack.Push(root); while (stack.Count > 0) { // Pop the next expression from the stack. var expression = stack.Pop() as OperatorExpression; // Only operator expressions are checked for validity. if (expression == null) continue; // Check the operator expression has the right number of operands. if (expression.Operator.IsValidNumberOfOperands(expression.OperandCount) == false) throw new JavaScriptException(this.engine, "SyntaxError", "Wrong number of operands", this.LineNumber, this.SourcePath); // Check the operator expression is closed. if (expression.Operator.SecondaryToken != null && expression.SecondTokenEncountered == false) throw new JavaScriptException(this.engine, "SyntaxError", string.Format("Missing closing token '{0}'", expression.Operator.SecondaryToken.Text), this.LineNumber, this.SourcePath); // Check the child nodes. for (int i = 0; i < expression.OperandCount; i++) stack.Push(expression.GetRawOperand(i)); } }
/// <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; }
/// <summary> /// Creates a simple variable assignment expression. /// </summary> /// <param name="scope"> The scope the variable is defined within. </param> /// <param name="name"> The name of the variable to set. </param> /// <param name="value"> The value to set the variable to. </param> public AssignmentExpression(Scope scope, string name, Expression value) : base(Operator.Assignment) { this.Push(new NameExpression(scope, name)); this.Push(value); }
/// <summary> /// Creates a new instance of BinaryJSExpression. /// </summary> /// <param name="operator"> The binary operator to base this expression on. </param> /// <param name="left"> The operand on the left side of the operator. </param> /// <param name="right"> The operand on the right side of the operator. </param> public BinaryExpression(Operator @operator, Expression left, Expression right) : base(@operator) { this.Push(left); this.Push(right); }
/// <summary> /// Creates a new object scope for use inside a with statement. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="scopeObject"> An expression that evaluates to the object to use. </param> /// <returns> A new ObjectScope instance. </returns> internal static ObjectScope CreateWithScope(Scope parentScope, Expression scopeObject) { if (parentScope == null) throw new ArgumentException("With scopes must have a parent scope."); return new ObjectScope(parentScope) { ScopeObjectExpression = scopeObject, ProvidesImplicitThisValue = true, CanDeclareVariables = false }; }
/// <summary> /// Adds an operand. /// </summary> /// <param name="operand"> The expression representing the operand to add. </param> public void Push(Expression operand) { if (this.OperandCount >= this.operands.Length) throw new InvalidOperationException("Too many operands."); this.operands[this.OperandCount] = operand; this.OperandCount ++; }