/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { var expressionScope = new InterpreterScope(scope) { Context = this }; ExpressionBase value; if (!Value.ReplaceVariables(expressionScope, out value)) { result = value; return(false); } result = new AssignmentExpression(Variable, value); CopyLocation(result); return(true); }
private void GetContainerIndex(InterpreterScope scope, out ExpressionBase container, out ExpressionBase index) { if (Index.Type == ExpressionType.FunctionCall) { var expression = (FunctionCallExpression)Index; if (!expression.ReplaceVariables(scope, out index)) { container = index; return; } } else if (!Index.ReplaceVariables(scope, out index)) { container = index; return; } var indexed = Variable as IndexedVariableExpression; if (indexed != null) { indexed.ReplaceVariables(scope, out container); return; } container = scope.GetVariable(Variable.Name); if (container == null) { container = new UnknownVariableParseErrorExpression("Unknown variable: " + Variable.Name, Variable); return; } var variableReference = container as VariableReferenceExpression; if (variableReference != null) { container = variableReference.Expression; } var array = container as ArrayExpression; if (array != null) { var intIndex = index as IntegerConstantExpression; if (intIndex == null) { container = new ParseErrorExpression("Index does not evaluate to an integer constant", index); } else if (intIndex.Value < 0 || intIndex.Value >= array.Entries.Count) { container = new ParseErrorExpression(String.Format("Index {0} not in range 0-{1}", intIndex.Value, array.Entries.Count - 1), index); } } }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { ExpressionBase value; if (!Value.ReplaceVariables(scope, out value)) { result = value; return(false); } result = new ReturnExpression(value); CopyLocation(result); return(true); }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { ExpressionBase value = scope.GetVariable(Name); if (value == null) { var func = scope.GetFunction(Name); if (func != null) { // special wrapper for returning a function as a variable result = new FunctionReferenceExpression(Name); result.CopyLocation(this); return(true); } result = new UnknownVariableParseErrorExpression("Unknown variable: " + Name, this); return(false); } return(value.ReplaceVariables(scope, out result)); }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { ExpressionBase value = scope.GetVariable(Name); if (value == null) { var func = scope.GetFunction(Name); if (func != null) { result = new ParseErrorExpression("Function used like a variable: " + Name, this); } else { result = new ParseErrorExpression("Unknown variable: " + Name, this); } return(false); } return(value.ReplaceVariables(scope, out result)); }
private static ExpressionBase GetParameter(InterpreterScope parameterScope, InterpreterScope scope, AssignmentExpression assignment) { ExpressionBase value = assignment.Value; var variable = value as VariableExpression; if (variable != null) { value = scope.GetVariable(variable.Name); if (value == null) { // could not find variable, fallback to VariableExpression.ReplaceVariables generating an error value = assignment.Value; } else { // when a parameter is assigned to a variable that is an array or dictionary, // assume it has already been evaluated and pass it by reference. this is magnitudes // more performant, and allows the function to modify the data in the container. if (value.Type == ExpressionType.Dictionary || value.Type == ExpressionType.Array) { value = scope.GetVariableReference(variable.Name); assignment.Value.CopyLocation(value); return(value); } } } if (value.IsConstant) { // already a basic type, do nothing } else if (value.Type == ExpressionType.FunctionDefinition) { var anonymousFunction = value as AnonymousUserFunctionDefinitionExpression; if (anonymousFunction != null) { anonymousFunction.CaptureVariables(parameterScope); } } else { bool isLogicalUnit = value.IsLogicalUnit; // not a basic type, evaluate it var assignmentScope = new InterpreterScope(scope) { Context = assignment }; if (!value.ReplaceVariables(assignmentScope, out value)) { var error = (ParseErrorExpression)value; return(new ParseErrorExpression("Invalid value for parameter: " + assignment.Variable.Name, assignment.Value) { InnerError = error }); } value.IsLogicalUnit = isLogicalUnit; assignment.Value.CopyLocation(value); } return(value); }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { if (_fullyExpanded) { result = this; return(true); } bool hasTrue = false; bool hasFalse = false; bool isChanged = false; var updatedConditions = new List <ExpressionBase>(_conditions.Count); for (int i = 0; i < _conditions.Count; ++i) { if (!_conditions[i].ReplaceVariables(scope, out result)) { return(false); } // can eliminate true/false now, but not things that evaluate to true/false. // (like always_true or always_false) as those may be used to generate explicit alt groups. var booleanExpression = result as BooleanConstantExpression; if (booleanExpression != null) { if (booleanExpression.Value) { hasTrue = true; if (Operation == ConditionalOperation.And) { isChanged = true; continue; } } else { hasFalse = true; if (Operation == ConditionalOperation.Or) { isChanged = true; continue; } } } isChanged |= !ReferenceEquals(result, _conditions[i]); updatedConditions.Add(result); } bool?logicalResult = null; switch (Operation) { case ConditionalOperation.Not: if (hasTrue) { logicalResult = false; } else if (hasFalse) { logicalResult = true; } else { result = InvertExpression(updatedConditions[0]); if (result.Type == ExpressionType.ParseError) { return(false); } CopyLocation(result); // InvertExpression may distribute Nots to subnodes, recurse return(result.ReplaceVariables(scope, out result)); } break; case ConditionalOperation.Or: if (hasTrue) { // anything or true is true logicalResult = true; } else if (hasFalse && updatedConditions.Count == 0) { // all conditions were false, entire condition is false logicalResult = false; } break; case ConditionalOperation.And: if (hasFalse) { // anything and false is false logicalResult = false; } if (hasTrue && updatedConditions.Count == 0) { // all conditions were true, entire condition is true logicalResult = true; } break; } if (logicalResult == true) { result = new BooleanConstantExpression(true); } else if (logicalResult == false) { result = new BooleanConstantExpression(false); } else { // merge with nested logic when possible for (int i = updatedConditions.Count - 1; i >= 0; i--) { var conditionalExpression = updatedConditions[i] as ConditionalExpression; if (conditionalExpression != null && conditionalExpression.Operation == Operation) { updatedConditions.RemoveAt(i); updatedConditions.InsertRange(i, conditionalExpression._conditions); isChanged = true; } } if (!isChanged) { _fullyExpanded = true; result = this; return(true); } else { var newConditionalExpression = new ConditionalExpression(Operation, updatedConditions); newConditionalExpression._fullyExpanded = true; result = newConditionalExpression; } } CopyLocation(result); return(true); }