/// <summary> /// clones this set of variables /// this is required in order to support local scope and recursion /// a copy of the set of variables (arguments in a function) will be pushed on the scope stack /// </summary> /// <returns></returns> public Variables Clone() { Variables vars = new Variables(); foreach (string key in Keys) { vars.Add(key, this[key]); } return(vars); }
protected override object EvaluateExpression(ParseTree tree, params object[] paramlist) { // if only left hand side available, this is not an assignment, simple evaluate expression if (nodes.Count == 1) { return(this.GetValue(tree, TokenType.AssignmentExpression, 0)); // return the result } if (nodes.Count != 3) { tree.Errors.Add(new ParseError("Illegal EvaluateExpression format", 1092, this)); return(null); } // ok, this is an assignment so declare the function or variable // assignment only allowed to function or to a variable ParseNode v = GetFunctionOrVariable(nodes[0]); if (v == null) { tree.Errors.Add(new ParseError("Can only assign to function or variable", 1020, this)); return(null); } ParseTreeEvaluator root = tree as ParseTreeEvaluator; if (root == null) { tree.Errors.Add(new ParseError("Invalid parser used", 1040, this)); return(null); } if (root.Context == null) { tree.Errors.Add(new ParseError("No context defined", 1041, this)); return(null); } if (v.Token.Type == TokenType.VARIABLE) { // simply overwrite any previous defnition string key = v.Token.Text.ToLowerInvariant(); root.Context.Globals[key] = this.GetValue(tree, TokenType.AssignmentExpression, 1); return(null); } else if (v.Token.Type == TokenType.Function) { string key = v.Nodes[0].Token.Text; // function lookup is case insensitive if (root.Context.Functions.ContainsKey(key.ToLower())) { if (!(root.Context.Functions[key.ToLower()] is DynamicFunction)) { tree.Errors.Add(new ParseError("Built in functions cannot be overwritten", 1050, this)); return(null); } } // lets determine the input variables. // functions must be of te form f(x;y;z) = x+y*z; // check the function parameters to be of type Variable, error otherwise Variables vars = new Variables(); ParseNode paramsNode = v.Nodes[2]; if (paramsNode.Token.Type == TokenType.Params) { // function has parameters, so check if they are all variable declarations for (int i = 0; i < paramsNode.Nodes.Count; i += 2) { ParseNode varNode = GetFunctionOrVariable(paramsNode.Nodes[i]); if (varNode == null || varNode.Token.Type != TokenType.VARIABLE) { tree.Errors.Add(new ParseError("Function declaration may only contain variables", 1051, this)); return(null); } // simply declare the variable, no need to evaluate the value of it at this point. // evaluation will be done when the function is executed // note, variables are Case Sensitive (!) vars.Add(varNode.Token.Text, null); } } // we have all the info we need to know to declare the dynamicly defined function // pass on nodes[2] which is the Right Hand Side (RHS) of the assignment // nodes[2] will be evaluated at runtime when the function is executed. DynamicFunction dynf = new DynamicFunction(key, nodes[2], vars, vars.Count, vars.Count); root.Context.Functions[key.ToLower()] = dynf; return(null); } // in an assignment, dont return any result (basically void) return(null); }
protected override object EvaluateExpression(ParseTree tree, params object[] paramlist) { // if only left hand side available, this is not an assignment, simple evaluate expression if (nodes.Count == 1) return this.GetValue(tree, TokenType.AssignmentExpression, 0); // return the result if (nodes.Count != 3) { tree.Errors.Add(new ParseError("Illegal EvaluateExpression format", 1092, this)); return null; } // ok, this is an assignment so declare the function or variable // assignment only allowed to function or to a variable ParseNode v = GetFunctionOrVariable(nodes[0]); if (v == null) { tree.Errors.Add(new ParseError("Can only assign to function or variable", 1020, this)); return null; } ParseTreeEvaluator root = tree as ParseTreeEvaluator; if (root == null) { tree.Errors.Add(new ParseError("Invalid parser used", 1040, this)); return null; } if (root.Context == null) { tree.Errors.Add(new ParseError("No context defined", 1041, this)); return null; } if (v.Token.Type == TokenType.VARIABLE) { // simply overwrite any previous defnition string key = v.Token.Text.ToLowerInvariant(); root.Context.Globals[key] = this.GetValue(tree, TokenType.AssignmentExpression, 1); return null; } else if (v.Token.Type == TokenType.Function) { string key = v.Nodes[0].Token.Text; // function lookup is case insensitive if (root.Context.Functions.ContainsKey(key.ToLower())) if (!(root.Context.Functions[key.ToLower()] is DynamicFunction)) { tree.Errors.Add(new ParseError("Built in functions cannot be overwritten", 1050, this)); return null; } // lets determine the input variables. // functions must be of te form f(x;y;z) = x+y*z; // check the function parameters to be of type Variable, error otherwise Variables vars = new Variables(); ParseNode paramsNode = v.Nodes[2]; if (paramsNode.Token.Type == TokenType.Params) { // function has parameters, so check if they are all variable declarations for (int i = 0; i < paramsNode.Nodes.Count; i += 2) { ParseNode varNode = GetFunctionOrVariable(paramsNode.Nodes[i]); if (varNode == null || varNode.Token.Type != TokenType.VARIABLE) { tree.Errors.Add(new ParseError("Function declaration may only contain variables", 1051, this)); return null; } // simply declare the variable, no need to evaluate the value of it at this point. // evaluation will be done when the function is executed // note, variables are Case Sensitive (!) vars.Add(varNode.Token.Text, null); } } // we have all the info we need to know to declare the dynamicly defined function // pass on nodes[2] which is the Right Hand Side (RHS) of the assignment // nodes[2] will be evaluated at runtime when the function is executed. DynamicFunction dynf = new DynamicFunction(key, nodes[2], vars, vars.Count, vars.Count); root.Context.Functions[key.ToLower()] = dynf; return null; } // in an assignment, dont return any result (basically void) return null; }