/// <summary> /// Updates the provided scope with the new variable value. /// </summary> /// <param name="scope">The scope object containing variable values and function parameters.</param> /// <returns> /// <c>null</c> if successful, or a <see cref="ParseErrorExpression" /> if not. /// </returns> public ParseErrorExpression Evaluate(InterpreterScope scope) { var assignmentScope = new InterpreterScope(scope) { Context = this }; ExpressionBase result; var functionDefinition = Value as FunctionDefinitionExpression; if (functionDefinition != null) { scope.AddFunction(functionDefinition); result = new FunctionReferenceExpression(functionDefinition.Name.Name); } else { if (!Value.ReplaceVariables(assignmentScope, out result)) { return((ParseErrorExpression)result); } } return(scope.AssignVariable(Variable, result)); }
/// <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 = new InterpreterScope(scope); 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.AssignVariable(new VariableExpression("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 assignmentScope = new InterpreterScope(scope) { Context = assignedParameter }; ExpressionBase value; if (!assignedParameter.Value.ReplaceVariables(assignmentScope, out value)) { error = new ParseErrorExpression(value, assignedParameter.Value); return(null); } assignedParameter.Value.CopyLocation(value); 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 : "..."; var assignmentScope = new InterpreterScope(scope) { Context = new AssignmentExpression(new VariableExpression(variableName), parameter) }; ExpressionBase value; if (!parameter.ReplaceVariables(assignmentScope, out value)) { error = new ParseErrorExpression(value, parameter); return(null); } parameter.CopyLocation(value); 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); }