/// <summary> /// Gets the return value from calling a function. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the function result.</param> /// <returns> /// <c>true</c> if invocation was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public bool Evaluate(InterpreterScope scope, out ExpressionBase result) { var functionDefinition = scope.GetFunction(FunctionName.Name); if (functionDefinition == null) { result = new ParseErrorExpression("Unknown function: " + FunctionName.Name, FunctionName); return(false); } var functionScope = GetParameters(functionDefinition, scope, out result); if (functionScope == null) { return(false); } if (functionScope.Depth >= 100) { result = new ParseErrorExpression("Maximum recursion depth exceeded", this); return(false); } functionScope.Context = this; if (!functionDefinition.Evaluate(functionScope, out result)) { return(false); } scope.ReturnValue = result; return(true); }
private static bool MergeAddition(ExpressionBase left, ExpressionBase right, out ExpressionBase result) { // if either side is a string, combine to a larger string if (left.Type == ExpressionType.StringConstant || right.Type == ExpressionType.StringConstant) { var builder = new StringBuilder(); left.AppendStringLiteral(builder); right.AppendStringLiteral(builder); result = new StringConstantExpression(builder.ToString()); return(true); } // if either side is a float, convert both to float if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant) { if (!ConvertToFloat(ref left, ref right, out result)) { return(false); } result = new FloatConstantExpression(((FloatConstantExpression)left).Value + ((FloatConstantExpression)right).Value); return(true); } if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant) { result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value + ((IntegerConstantExpression)right).Value); return(true); } result = new ParseErrorExpression("Cannot add expressions"); return(false); }
/// <summary> /// Determines whether the expression evaluates to true for the provided <paramref name="scope" /> /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="error">[out] The error that prevented evaluation (or null if successful).</param> /// <returns> /// The result of evaluating the expression /// </returns> public override bool IsTrue(InterpreterScope scope, out ParseErrorExpression error) { bool result = Left.IsTrue(scope, out error); if (error != null) { return(false); } switch (Operation) { case ConditionalOperation.And: if (result) { result = Right.IsTrue(scope, out error); } break; case ConditionalOperation.Or: if (!result) { result = Right.IsTrue(scope, out error); } break; case ConditionalOperation.Not: result = !result; break; } return(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) { var functionDefinition = scope.GetFunction(FunctionName.Name); if (functionDefinition == null) { result = new ParseErrorExpression("Unknown function: " + FunctionName.Name, FunctionName); return(false); } var functionScope = GetParameters(functionDefinition, scope, out result); if (functionScope == null) { return(false); } if (functionScope.Depth >= 100) { result = new ParseErrorExpression("Maximum recursion depth exceeded", this); return(false); } functionScope.Context = this; if (!functionDefinition.ReplaceVariables(functionScope, out result)) { return(false); } CopyLocation(result); return(true); }
protected FunctionDefinitionExpression GetFunctionParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = scope.GetVariable(name); if (parameter == null) { parseError = new ParseErrorExpression("No value provided for " + name + " parameter"); return(null); } var functionDefinition = parameter as FunctionDefinitionExpression; if (functionDefinition == null) { var functionReference = parameter as FunctionReferenceExpression; if (functionReference == null) { parseError = new ParseErrorExpression(name + " must be a function reference"); return(null); } functionDefinition = scope.GetFunction(functionReference.Name); if (functionDefinition == null) { parseError = new ParseErrorExpression("Undefined function: " + functionReference.Name); return(null); } } parseError = null; return(functionDefinition); }
/// <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) { // user-defined functions should be evaluated (expanded) immediately. if (!Evaluate(scope, out result)) { return(false); } if (result == null) { var functionCall = scope.GetContext <FunctionCallExpression>(); if (functionCall != null) { result = new ParseErrorExpression(Name.Name + " did not return a value", functionCall.FunctionName); } else { result = new ParseErrorExpression(Name.Name + " did not return a value"); } return(false); } return(true); }
/// <summary> /// Gets the dictionary parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns> protected DictionaryExpression GetDictionaryParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = GetParameter(scope, name, out parseError); if (parameter == null) { return(null); } var typedParameter = parameter as DictionaryExpression; if (typedParameter == null) { var originalParameter = LocateParameter(scope, name); if (originalParameter != null) { parameter = originalParameter; } parseError = new ParseErrorExpression(name + " is not a dictionary", parameter); return(null); } parseError = null; return(typedParameter); }
/// <summary> /// Gets the variable reference from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The variable reference, or <c>null</c> if an error occurred.</b></returns> protected VariableReferenceExpression GetReferenceParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = scope.GetVariable(name); if (parameter == null) { parseError = new ParseErrorExpression("No value provided for " + name + " parameter"); return(null); } var typedParameter = parameter as VariableReferenceExpression; if (typedParameter == null) { var originalParameter = LocateParameter(scope, name); if (originalParameter != null) { parameter = originalParameter; } parseError = new ParseErrorExpression(name + " is not a reference", parameter); return(null); } parseError = null; return(typedParameter); }
/// <summary> /// Gets the boolean parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns> protected BooleanConstantExpression GetBooleanParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = GetParameter(scope, name, out parseError); if (parameter == null) { return(null); } var typedParameter = parameter as BooleanConstantExpression; if (typedParameter == null) { var originalParameter = LocateParameter(scope, name); if (originalParameter != null) { parameter = originalParameter; } parseError = new ParseErrorExpression(name + " is not a boolean", parameter); return(null); } parseError = null; return(typedParameter); }
private bool GetSingleParameter(FunctionDefinitionExpression function, InterpreterScope parameterScope, out ExpressionBase error) { var funcParameter = function.Parameters.First(); ExpressionBase value = Parameters.First(); if (value.IsConstant) { // already a basic type, just proceed to storing it error = null; } else { var assignedParameter = value as AssignmentExpression; if (assignedParameter == null) { assignedParameter = new AssignmentExpression(new VariableExpression(funcParameter.Name), value); } else if (funcParameter.Name != assignedParameter.Variable.Name) { error = new ParseErrorExpression(String.Format("'{0}' does not have a '{1}' parameter", function.Name.Name, assignedParameter.Variable.Name), value); return(true); } value = GetParameter(parameterScope, parameterScope, assignedParameter); error = value as ParseErrorExpression; if (error != null) { return(true); } } parameterScope.DefineVariable(new VariableDefinitionExpression(funcParameter.Name), value); return(true); }
public override bool?IsTrue(InterpreterScope scope, out ParseErrorExpression error) { ExpressionBase result; if (!Evaluate(scope, true, out result)) { error = result as ParseErrorExpression; return(null); } var functionCall = result as FunctionCallExpression; if (functionCall != null) // prevent recursion { error = null; var funcDef = scope.GetFunction(functionCall.FunctionName.Name); if (funcDef is Functions.AlwaysTrueFunction) { return(true); } if (funcDef is Functions.AlwaysFalseFunction) { return(false); } return(null); } return(result.IsTrue(scope, out error)); }
private static bool MergeModulus(ExpressionBase left, ExpressionBase right, out ExpressionBase result) { // if either side is a float, convert both to float if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant) { if (!ConvertToFloat(ref left, ref right, out result)) { return(false); } if (((FloatConstantExpression)right).Value == 0.0) { result = new ParseErrorExpression("Division by zero"); return(false); } result = new FloatConstantExpression(((FloatConstantExpression)left).Value % ((FloatConstantExpression)right).Value); return(true); } if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant) { if (((IntegerConstantExpression)right).Value == 0) { result = new ParseErrorExpression("Division by zero"); return(false); } result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value % ((IntegerConstantExpression)right).Value); return(true); } result = new ParseErrorExpression("Cannot modulus expressions"); return(false); }
/// <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) { // FunctionDefinition.ReplaceVariables is called when evaluating a function for an assignment. // For user functions (see UserFunctionDefinition.ReplaceVariables) - it will just evaluate the // function call and return the result. Several internal functions have very special Evaluate // handling that should not be executed when defining variables. Those functions rely on this // behavior to just evaluate the parameters without calling Evaluate. There are some built-in // functions that should call Evaluate when ReplaceVariables is called. They will override // ReplaceVariables to do that. var parameters = new ExpressionBase[Parameters.Count]; int i = 0; foreach (var parameterName in Parameters) { // do a direct lookup here. calling GetParameter will discard the VariableReference // and we want to preserve those for now. var parameter = scope.GetVariable(parameterName.Name); if (parameter == null) { result = new ParseErrorExpression("No value provided for " + parameterName.Name + " parameter", parameterName); return(false); } parameters[i++] = parameter; } result = new FunctionCallExpression(Name.Name, parameters); CopyLocation(result); return(true); }
public void AddEvaluationError(ParseErrorExpression error) { lock (_evaluationErrors) { _evaluationErrors.Add(error); } }
public bool GetExpressionsForLine(List <ExpressionBase> expressions, int line) { bool result = false; foreach (var group in GetGroupsForLine(line)) { result |= group.GetExpressionsForLine(expressions, line); } lock (_evaluationErrors) { foreach (var error in _evaluationErrors) { var unknownVariableError = error.InnermostError as UnknownVariableParseErrorExpression; if (unknownVariableError != null && unknownVariableError.Location.Start.Line <= line && unknownVariableError.Location.End.Line >= line) { if (!expressions.Contains(unknownVariableError)) { expressions.Add(unknownVariableError); } result = true; } ParseErrorExpression mostSignificantError = null; var scan = error; do { if (scan.Location.Start.Line <= line && scan.Location.End.Line >= line) { // scan is more significant than current error, use it mostSignificantError = scan; } else if (mostSignificantError != null && scan.Location.Start.Line >= mostSignificantError.Location.Start.Line && scan.Location.End.Line < mostSignificantError.Location.End.Line) { // scan is more significant than current error, but not part of line, ignore it mostSignificantError = null; break; } scan = scan.InnerError; } while (scan != null); if (mostSignificantError != null) { if (!expressions.Contains(mostSignificantError)) { expressions.Add(mostSignificantError); } result = true; } } } return(result); }
public void AddParseError(ParseErrorExpression error) { if (_parseErrors == null) { _parseErrors = new List <ParseErrorExpression>(); } _parseErrors.Add(error); }
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); } } }
private static bool MergeBitwiseAnd(ExpressionBase left, ExpressionBase right, out ExpressionBase result) { if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant) { result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value & ((IntegerConstantExpression)right).Value); return(true); } result = new ParseErrorExpression("Cannot bitwise and expressions"); return(false); }
public static ParseErrorExpression WrapError(ParseErrorExpression error, string message, ExpressionBase expression) { if (error.Location.End == expression.Location.End && error.Location.Start == expression.Location.Start) { return(error); } return(new ParseErrorExpression(message, expression) { InnerError = error }); }
internal static ParseErrorExpression ParseError(PositionalTokenizer tokenizer, string message, int line, int column) { var error = new ParseErrorExpression(message, line, column, tokenizer.Line, tokenizer.Column); var expressionTokenizer = tokenizer as ExpressionTokenizer; if (expressionTokenizer != null) { expressionTokenizer.AddError(error); } return(error); }
/// <summary> /// Gets the parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns> protected ExpressionBase GetParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = scope.GetVariable(name); if (parameter == null) { parseError = new ParseErrorExpression("No value provided for " + name + " parameter"); return(null); } parseError = null; return(parameter); }
/// <summary> /// Gets the return value from calling a function. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the function result.</param> /// <returns> /// <c>true</c> if invocation was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public bool Invoke(InterpreterScope scope, out ExpressionBase result) { if (Evaluate(scope, out result)) { return(true); } if (result.Location.Start.Line == 0) { result = new ParseErrorExpression(result, FunctionName); } return(false); }
/// <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 container, index; GetContainerIndex(scope, out container, out index); switch (container.Type) { case ExpressionType.Dictionary: result = ((DictionaryExpression)container).GetEntry(index); if (result == null) { var builder = new StringBuilder(); builder.Append("No entry in dictionary for key: "); index.AppendString(builder); result = new ParseErrorExpression(builder.ToString(), Index); return(false); } break; case ExpressionType.Array: result = ((ArrayExpression)container).Entries[((IntegerConstantExpression)index).Value]; break; case ExpressionType.ParseError: result = container; return(false); default: { var builder = new StringBuilder(); builder.Append("Cannot index: "); Variable.AppendString(builder); builder.Append(" ("); builder.Append(container.Type); builder.Append(')'); result = new ParseErrorExpression(builder.ToString(), Variable); } return(false); } if (result == null) { return(false); } return(result.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) { if (!Evaluate(scope, out result)) { return(false); } if (result == null) { result = new ParseErrorExpression(FunctionName.Name + " did not return a value", FunctionName); return(false); } CopyLocation(result); return(true); }
/// <summary> /// Gets the string parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns> protected StringConstantExpression GetStringParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = GetParameter(scope, name, out parseError); if (parameter == null) { return(null); } var typedParameter = parameter as StringConstantExpression; if (typedParameter == null) { parseError = new ParseErrorExpression(name + " is not a string", parameter); return(null); } parseError = null; return(typedParameter); }
/// <summary> /// Gets a parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections. /// </summary> /// <param name="scope">The scope.</param> /// <param name="name">The name of the parameter.</param> /// <param name="parseError">[out] The error that occurred.</param> /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns> protected ExpressionBase GetParameter(InterpreterScope scope, string name, out ExpressionBase parseError) { var parameter = scope.GetVariable(name); if (parameter == null) { parseError = new ParseErrorExpression("No value provided for " + name + " parameter"); return(null); } parseError = null; // if it's a variable reference, return the referenced object. if (parameter.Type == ExpressionType.VariableReference) { return(((VariableReferenceExpression)parameter).Expression); } // WARNING: variable references may still exist within a varargs object return(parameter); }
/// <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)); }
public void AddError(ParseErrorExpression error) { _expressionGroup.AddParseError(error); }
/// <summary> /// Determines whether the expression evaluates to true for the provided <paramref name="scope" /> /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="error">[out] The error that prevented evaluation (or null if successful).</param> /// <returns> /// The result of evaluating the expression /// </returns> public override bool IsTrue(InterpreterScope scope, out ParseErrorExpression error) { ExpressionBase left, right; if (!Left.ReplaceVariables(scope, out left)) { error = left as ParseErrorExpression; return(false); } if (!Right.ReplaceVariables(scope, out right)) { error = right as ParseErrorExpression; return(false); } error = null; var integerLeft = left as IntegerConstantExpression; if (integerLeft != null) { var integerRight = right as IntegerConstantExpression; if (integerRight == null) { return(false); } switch (Operation) { case ComparisonOperation.Equal: return(integerLeft.Value == integerRight.Value); case ComparisonOperation.NotEqual: return(integerLeft.Value != integerRight.Value); case ComparisonOperation.GreaterThan: return(integerLeft.Value > integerRight.Value); case ComparisonOperation.GreaterThanOrEqual: return(integerLeft.Value >= integerRight.Value); case ComparisonOperation.LessThan: return(integerLeft.Value < integerRight.Value); case ComparisonOperation.LessThanOrEqual: return(integerLeft.Value <= integerRight.Value); default: return(false); } } var stringLeft = left as StringConstantExpression; if (stringLeft != null) { var stringRight = right as StringConstantExpression; if (stringRight == null) { return(false); } switch (Operation) { case ComparisonOperation.Equal: return(stringLeft.Value == stringRight.Value); case ComparisonOperation.NotEqual: return(stringLeft.Value != stringRight.Value); case ComparisonOperation.GreaterThan: return(String.Compare(stringLeft.Value, stringRight.Value) > 0); case ComparisonOperation.GreaterThanOrEqual: return(String.Compare(stringLeft.Value, stringRight.Value) >= 0); case ComparisonOperation.LessThan: return(String.Compare(stringLeft.Value, stringRight.Value) < 0); case ComparisonOperation.LessThanOrEqual: return(String.Compare(stringLeft.Value, stringRight.Value) <= 0); default: return(false); } } return(false); }
/// <summary> /// Creates a new scope for calling a function and populates values for parameters passed to the function. /// </summary> /// <param name="function">The function defining the parameters to populate.</param> /// <param name="scope">The outer scope containing the function call.</param> /// <param name="error">[out] A <see cref="ParseErrorExpression"/> indicating why constructing the new scope failed.</param> /// <returns>The new scope, <c>null</c> if an error occurred - see <paramref name="error"/> for error details.</returns> public InterpreterScope GetParameters(FunctionDefinitionExpression function, InterpreterScope scope, out ExpressionBase error) { var parameterScope = function.CreateCaptureScope(scope); // optimization for no parameter function if (function.Parameters.Count == 0 && Parameters.Count == 0) { error = null; return(parameterScope); } // optimization for single parameter function if (function.Parameters.Count == 1 && Parameters.Count == 1) { if (GetSingleParameter(function, parameterScope, out error)) { return(parameterScope); } if (error != null) { return(null); } } var providedParameters = new List <string>(function.Parameters.Count); foreach (var parameter in function.Parameters) { providedParameters.Add(parameter.Name); } ArrayExpression varargs = null; if (providedParameters.Remove("...")) { varargs = new ArrayExpression(); parameterScope.DefineVariable(new VariableDefinitionExpression("varargs"), varargs); } var parameterCount = providedParameters.Count; int index = 0; bool namedParameters = false; foreach (var parameter in Parameters) { var assignedParameter = parameter as AssignmentExpression; if (assignedParameter != null) { if (!providedParameters.Remove(assignedParameter.Variable.Name)) { if (!function.Parameters.Any(p => p.Name == assignedParameter.Variable.Name)) { error = new ParseErrorExpression(String.Format("'{0}' does not have a '{1}' parameter", function.Name.Name, assignedParameter.Variable.Name), parameter); return(null); } error = new ParseErrorExpression(String.Format("'{0}' already has a value", assignedParameter.Variable.Name), assignedParameter.Variable); return(null); } var value = GetParameter(parameterScope, scope, assignedParameter); error = value as ParseErrorExpression; if (error != null) { return(null); } parameterScope.DefineVariable(new VariableDefinitionExpression(assignedParameter.Variable), value); namedParameters = true; } else { if (namedParameters) { error = new ParseErrorExpression("Non-named parameter following named parameter", parameter); return(null); } if (index >= parameterCount && varargs == null) { error = new ParseErrorExpression("Too many parameters passed to function", parameter); return(null); } var variableName = (index < parameterCount) ? function.Parameters.ElementAt(index).Name : "..."; assignedParameter = new AssignmentExpression(new VariableExpression(variableName), parameter); var value = GetParameter(parameterScope, scope, assignedParameter); error = value as ParseErrorExpression; if (error != null) { return(null); } if (index < parameterCount) { providedParameters.Remove(variableName); parameterScope.DefineVariable(new VariableDefinitionExpression(variableName), value); } else { varargs.Entries.Add(value); } } ++index; } foreach (var parameter in providedParameters) { ExpressionBase value; if (!function.DefaultParameters.TryGetValue(parameter, out value)) { error = new ParseErrorExpression(String.Format("Required parameter '{0}' not provided", parameter), FunctionName); return(null); } var assignmentScope = new InterpreterScope(scope) { Context = new AssignmentExpression(new VariableExpression(parameter), value) }; if (!value.ReplaceVariables(assignmentScope, out value)) { error = new ParseErrorExpression(value, this); return(null); } parameterScope.DefineVariable(new VariableDefinitionExpression(parameter), value); } error = null; return(parameterScope); }