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 = 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)); }
private bool Evaluate(InterpreterScope scope, bool inAssignment, out ExpressionBase result) { var functionDefinition = scope.GetFunction(FunctionName.Name); if (functionDefinition == null) { if (scope.GetVariable(FunctionName.Name) != null) { result = new UnknownVariableParseErrorExpression(FunctionName.Name + " is not a function", FunctionName); } else { result = new UnknownVariableParseErrorExpression("Unknown function: " + FunctionName.Name, FunctionName); } return(false); } var functionParametersScope = GetParameters(functionDefinition, scope, out result); if (functionParametersScope == null || result is ParseErrorExpression) { return(false); } if (functionParametersScope.Depth >= 100) { result = new ParseErrorExpression("Maximum recursion depth exceeded", this); return(false); } functionParametersScope.Context = this; if (inAssignment) { // in assignment, just replace variables functionDefinition.ReplaceVariables(functionParametersScope, out result); if (result.Type == ExpressionType.FunctionCall) { // if the result is a function call, check for any variable references. it can't be marked // as fully expanded if any variable references are present. var functionCall = (FunctionCallExpression)result; if (!functionCall.Parameters.Any(p => p is VariableReferenceExpression)) { functionCall._fullyExpanded = true; } // if there was no change, also mark the source as fully expanded. if (result == this) { _fullyExpanded = true; } // when expanding the parameters, a new functionCall object will be created without a name // location. if that has happened, replace the temporary name object with the real one. if (functionCall.FunctionName.Location.Start.Line == 0 && functionCall.FunctionName.Name == FunctionName.Name) { functionCall.FunctionName = FunctionName; } } } else { // not in assignment, evaluate the function functionDefinition.Evaluate(functionParametersScope, out result); } var error = result as ParseErrorExpression; if (error != null) { if (error.Location.Start.Line == 0) { this.CopyLocation(error); } result = ParseErrorExpression.WrapError(error, FunctionName.Name + " call failed", FunctionName); return(false); } return(true); }