public Value InvokeUserFunction(List <Value> arguments) { if (!(arguments.Count >= 1)) { throw new ArgumentException("The amount of arguments passed into the function do not match the amount of expected arguments."); } if (arguments[0].Type != ValueType.String) { throw new Exception("An invalid argument type has been passed into a built in function."); } if (CallStack.Count > 1000) { throw new StackOverflowException("The call stack's size has exceeded the 1000 item limit."); } FunctionFrame f = functions[arguments[0].String].CloneTemplate(); if (arguments.Count == 1) { f.SetArguments(new List <Value>()); } else { f.SetArguments(arguments.GetRange(1, arguments.Count - 1)); } f.ReturnPosition = (Marker)keywordMarker.Clone(); f.ReturnResult = Value.Null; CallStack.Push(f); lexer.ShiftCurrentPosition(functions[arguments[0].String].StartPosition); return(null); }
public FunctionFrame CloneTemplate() { FunctionFrame functionStructure = new FunctionFrame(Identifier); functionStructure.SetArgumentParameters(argument_identifiers); functionStructure.SetArguments(LocalVariables.Values.ToList()); return(functionStructure); }
//gets the next value Value NextValue(FunctionFrame current) { Value val = Value.Null; if (lastToken == Token.Value) //raw value { val = lexer.TokenValue; ReadNextToken(); } else if (lastToken == Token.Identifier) { if (GlobalVariables.ContainsKey(lexer.TokenIdentifier)) //see if it's a variable { string vid = lexer.TokenIdentifier; if (PeekNextToken() == Token.OpenBracket) { ReadNextToken(); ReadNextToken(); Value v = EvaluateNextExpression(0, current); if (v == null) { return(null); } if (v.Type != ValueType.Double) { throw new Exception("Indicie's must be of type double."); } if (GlobalVariables[vid].Type == ValueType.String) { val = new Value(GlobalVariables[vid].String[(int)v.Double]); } else if (GlobalVariables[vid].Type == ValueType.Array) { val = GlobalVariables[vid].Array[(int)v.Double]; } else { throw new Exception("Only arrays and strings can be indexed."); } MatchToken(Token.CloseBracket); } else { val = GlobalVariables[vid]; } } else if (functions.ContainsKey(lexer.TokenIdentifier) || builtInFunctions.ContainsKey(lexer.TokenIdentifier)) //see if it's a function { ReadNextToken(); MatchToken(Token.OpenParenthesis); string fid = lexer.TokenIdentifier; int aid = lexer.Position.Index; List <Value> arguments = new List <Value>(); int argno = 0; //current argument index while (lastToken != Token.CloseParenthesis) //collect all the arguments { ReadNextToken(); if (lastToken == Token.Comma || lastToken == Token.CloseParenthesis) { continue; //just skip the comma's } else { if (argno >= arguments.Count) { Value v = EvaluateNextExpression(0, current); if (v == null) { return(null); //this is how to escape the recursive function when a function needs to be evaluated through the main loop first } arguments.Add(v); } else { int paramCount = 0; //skip open params, close params till it balances out do { ReadNextToken(); if (lastToken == Token.OpenParenthesis) { paramCount++; } else if (lastToken == Token.CloseParenthesis) { paramCount--; } }while (paramCount >= 0 && lastToken != Token.Comma); } } argno++; } //bracket_counter++; if (current.functionResults.Count > 0) { Value value = current.functionResults.Dequeue(); current.processedFunctionResults.Enqueue(value); ReadNextToken(); return(value); } if (functions.ContainsKey(fid)) { if (CallStack.Count > 1000) { throw new StackOverflowException("The call stack's size has exceeded the 1000 item limit."); } FunctionFrame f = functions[fid].CloneTemplate(); f.SetArguments(arguments); f.ReturnPosition = (Marker)keywordMarker.Clone(); f.ReturnResult = Value.Null; CallStack.Push(f); lexer.ShiftCurrentPosition(functions[fid].StartPosition); ReadNextToken(); return(null); } else { val = builtInFunctions[fid].Invoke(arguments); ReadNextToken(); if (val == null) { return(null); } current.processedFunctionResults.Enqueue(val); return(val); } } else { val = null; FunctionFrame function = GetCurrentContext(); if (function.LocalVariables.ContainsKey(lexer.TokenIdentifier)) { string fid = lexer.TokenIdentifier; if (PeekNextToken() == Token.OpenBracket) { ReadNextToken(); ReadNextToken(); Value v = EvaluateNextExpression(0, current); if (v == null) { return(null); } if (v.Type != ValueType.Double) { throw new Exception("Indicie's must be of type double."); } if (function.LocalVariables[fid].Type == ValueType.String) { val = new Value(function.LocalVariables[fid].String[(int)v.Double]); } else if (function.LocalVariables[fid].Type == ValueType.Array) { val = function.LocalVariables[fid].Array[(int)v.Double]; } else { throw new Exception("Only arrays and strings can be indexed."); } MatchToken(Token.CloseBracket); } else { val = function.LocalVariables[fid]; } } if (val == null) { throw new UnidentifiedTokenExcepion(); } } ReadNextToken(); } else if (lastToken == Token.OpenParenthesis) //it's an expression { ReadNextToken(); val = EvaluateNextExpression(0, current); //call the evaluate function if (val == null) { return(null); } MatchToken(Token.CloseParenthesis); ReadNextToken(); } else if (lastToken == Token.OpenBracket) { List <Value> values = new List <Value>(); while (lastToken != Token.CloseBracket) //collect all the arguments { ReadNextToken(); if (lastToken == Token.Comma || lastToken == Token.CloseBracket) { continue; //just skip the comma's } else { Value v = EvaluateNextExpression(0, current); if (v == null) { return(null); //this is how to escape the recursive function when a function needs to be evaluated through the main loop first } values.Add(v); } } ReadNextToken(); val = new Value(values); } //this part handles uniary operations else { Token tok = lastToken; ReadNextToken(); if (tok == Token.Refrence) { val = new Value(lexer.TokenIdentifier); } else { Value val1 = NextValue(current); if (val1 == null) { return(null); } val = val1.PerformUniaryOperation(tok); } } return(val); }