public LSLVariableDeclarationNode ResolveVariable(string name)
        {
            var local = (from scope in _scopeVariables
                         where scope.ContainsKey(name)
                         select scope[name]).FirstOrDefault();

            if (local != null)
            {
                return(local);
            }


            if (_parameterScopeVariables.ContainsKey(name))
            {
                var x = _parameterScopeVariables[name];
                return(x);
            }


            if (GlobalVariables.ContainsKey(name))
            {
                return(GlobalVariables[name]);
            }

            return(null);
        }
예제 #2
0
 public void AddVariable(string name, string content)
 {
     if (!GlobalVariables.ContainsKey(name.ToLower()) && !LocalVariables.ContainsKey(name.ToLower()))
     {
         var newVar = new Variable(name, content);
         LocalVars.Add(newVar.Name.ToLower(), newVar);
     }
 }
예제 #3
0
 public void SetVariableValue(string variableName, int targetValue)
 {
     if (GlobalVariables.ContainsKey(variableName))
     {
         GlobalVariables[variableName] = targetValue;
     }
     else
     {
         GlobalVariables.Add(variableName, targetValue);
     }
 }
 /// <summary>
 ///     Determines if given the current scoping state, can a variable be defined without causing a conflict
 /// </summary>
 /// <param name="name">name of the variable</param>
 /// <param name="scope">the scope level of the variable to be defined</param>
 /// <returns>whether or not the variable can be defined without conflict</returns>
 public bool CanVariableBeDefined(string name, LSLVariableScope scope)
 {
     if (scope == LSLVariableScope.Global)
     {
         return(!GlobalVariables.ContainsKey(name));
     }
     if (scope == LSLVariableScope.Local)
     {
         return(!_scopeVariables.Peek().ContainsKey(name));
     }
     return(true);
 }
예제 #5
0
        public string RenameVariable(string oldName, string newName)
        {
            string currentVarName = oldName;

            if (!GlobalVariables.ContainsKey(newName.ToLower()) && !LocalVariables.ContainsKey(newName.ToLower()))
            {
                LocalVars.Add(newName.ToLower(), LocalVariables[oldName.ToLower()]);
                LocalVars[newName.ToLower()].Name = newName;
                RemoveVariable(oldName.ToLower());
                currentVarName = newName;
            }

            return(currentVarName);
        }
예제 #6
0
 public void AddValueToGlobalContext(string name, Value val)
 {
     //On the other hand global variables are not constant
     if (Parent == null)
     {
         if (GlobalVariables.ContainsKey(name))
         {
             GlobalVariables.Remove(name);
         }
         GlobalVariables.Add(name, val);
     }
     else
     {
         Parent.AddValueToGlobalContext(name, val);
     }
 }
예제 #7
0
        public dynamic RunParagraph(string paragraphName, FiMObject paramObject = null)
        {
            if (!Paragraphs.ContainsKey(paragraphName))
            {
                throw new Exception("Invalid Paragraph name");
            }

            FiMParagraph paragraph = Paragraphs[paragraphName];

            // Empty function
            if (paragraph.Lines.Count() == 0)
            {
                return(null);
            }

            List <string> paragraphLines = new List <string>();

            paragraphLines.AddRange(paragraph.Lines);

            for (int i = 0; i < paragraphLines.Count(); i++)
            {
                if (!string.IsNullOrWhiteSpace(paragraphLines[i]) && !Regex.IsMatch(paragraphLines[i], @"( |\t)*(P\.)(P\.)*S\.($| )"))
                {
                    string nl = paragraphLines[i];
                    if (nl.StartsWith("    "))
                    {
                        nl = nl.Remove(0, "    ".Length);
                    }
                    else if (nl.StartsWith("\t"))
                    {
                        nl = nl.Remove(0, 1);
                    }
                    else
                    {
                        throw new Exception("Invalid indentation at line '" + paragraph.FirstLineIndex + i + "'");
                    }

                    paragraphLines[i] = nl;
                }
            }

            //
            Dictionary <string, FiMObject> LocalVariables = new Dictionary <string, FiMObject>();

            if (paragraph.ParameterName != null)
            {
                LocalVariables.Add(paragraph.ParameterName, paramObject);
            }

            int lineIndex = 1;
            int skipTo    = -1;

            string[] pLArray = paragraphLines.ToArray();
            foreach (string line in paragraphLines)
            {
                if (lineIndex <= skipTo)
                {
                    lineIndex++;
                    continue;
                }

                //Console.WriteLine(line);

                if (!string.IsNullOrWhiteSpace(line) && !Regex.IsMatch(line, @"( |\t)*(P\.)(P\.)*S\.($| )"))
                {
                    NetFIMMethods.FiMMethodOut method;
                    try {
                        method = NetFIMMethods.ScanMethod(this, line, pLArray, paragraph.FirstLineIndex + lineIndex + 1, lineIndex, paragraph, variables: NetFIMMethods.MergeLocalAndGlobalVariables(GlobalVariables, LocalVariables), paragraphs: Paragraphs);
                    }
                    catch (Exception e) { throw e; }

                    //

                    switch (method.methodType)
                    {
                    case "WRITE-RUN":
                    {
                        if (!Paragraphs.ContainsKey(method.outArgs["Method Name"]))
                        {
                            throw new Exception("[" + paragraph.FirstLineIndex + lineIndex + "] Paragraph '" + method.outArgs["Method Name"] + "' doesn't exist");
                        }

                        if (method.outArgs["doWrite"] == true)
                        {
                            NetFIMMethods.WriteToScreen(RunParagraph(method.outArgs["Method Name"], method.outArgs["Parameter"]));
                        }
                        else
                        {
                            RunParagraph(method.outArgs["Method Name"], method.outArgs["Parameter"]);
                        }
                    }
                    break;

                    case "MAKE-VARIABLE":
                    {
                        LocalVariables.Add(method.outArgs["Variable Name"], method.outArgs["Variable"]);
                    }
                    break;

                    case "MODIFY-ARRAY":
                    {
                        // In the case of Paragraph ScanMethod, we either put it on the Global or Local list.
                        if (GlobalVariables.ContainsKey(method.outArgs["Variable Name"]))
                        {
                            var ol = GlobalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            ol[method.outArgs["Slot"]] = method.outArgs["New Value"];
                            GlobalVariables[method.outArgs["Variable Name"]].Value = (object)ol;
                        }
                        else
                        {
                            var ol = LocalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            ol[method.outArgs["Slot"]] = method.outArgs["New Value"];
                            LocalVariables[method.outArgs["Variable Name"]].Value = (object)ol;
                        }
                    }
                    break;

                    case "MODIFY-VARIABLE":
                    {
                        if (GlobalVariables.ContainsKey(method.outArgs["Variable Name"]))
                        {
                            GlobalVariables[method.outArgs["Variable Name"]] = method.outArgs["New Value"];
                        }
                        else
                        {
                            LocalVariables[method.outArgs["Variable Name"]] = method.outArgs["New Value"];
                        }
                    }
                    break;

                    case "VARIABLE-INCREMENT":
                    {
                        if (GlobalVariables.ContainsKey(method.outArgs["Variable Name"]))
                        {
                            float oldValue = GlobalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            oldValue++;
                            GlobalVariables[method.outArgs["Variable Name"]].Value = (object)oldValue;
                        }
                        else
                        {
                            float oldValue = LocalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            oldValue++;
                            LocalVariables[method.outArgs["Variable Name"]].Value = (object)oldValue;
                        }
                    }
                    break;

                    case "VARIABLE-DECREMENT":
                    {
                        if (GlobalVariables.ContainsKey(method.outArgs["Variable Name"]))
                        {
                            float oldValue = GlobalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            oldValue--;
                            GlobalVariables[method.outArgs["Variable Name"]].Value = (object)oldValue;
                        }
                        else
                        {
                            float oldValue = LocalVariables[method.outArgs["Variable Name"]].GetActualValue();
                            oldValue--;
                            LocalVariables[method.outArgs["Variable Name"]].Value = (object)oldValue;
                        }
                    }
                    break;

                    case "WHILE":
                    {
                        skipTo = lineIndex + method.outArgs["Skip"] + 1;
                        //
                        Dictionary <string, FiMObject> changed = method.outArgs["Changed Variables"];

                        if (changed.Count() > 0)
                        {
                            changed.Keys.ToList().ForEach(x =>
                                {
                                    FiMObject obj = changed[x];

                                    if (GlobalVariables.ContainsKey(x))
                                    {
                                        GlobalVariables[x] = obj;
                                    }
                                    else
                                    {
                                        LocalVariables[x] = obj;
                                    }
                                });
                        }

                        if (method.outArgs.ContainsKey("Returned Variable"))
                        {
                            return(method.outArgs["Returned Variable"]);
                        }
                    }
                    break;

                    case "IF-ELSE":
                    {
                        skipTo = lineIndex + method.outArgs["Skip"] + 1;
                        //
                        if (method.outArgs.ContainsKey("Statement"))
                        {
                            NetFIMMethods.FiMStatement statement = method.outArgs["Statement"];
                            statement.changedVariables.Keys.ToList().ForEach(x =>
                                {
                                    FiMObject obj = statement.changedVariables[x];

                                    if (GlobalVariables.ContainsKey(x))
                                    {
                                        GlobalVariables[x] = obj;
                                    }
                                    else
                                    {
                                        LocalVariables[x] = obj;
                                    }
                                });

                            if (statement.hasReturned)
                            {
                                return(statement.returnedObject);
                            }
                        }
                    }
                    break;

                    case "RETURN":
                        return(method.outArgs["Variable"]);

                    case "WRITE-WRITE":
                    default:
                        break;
                    }
                }

                lineIndex++;
            }

            return(null);
        }
 public bool GlobalVariableDefined(string name)
 {
     return(GlobalVariables.ContainsKey(name));
 }
예제 #9
0
        //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);
        }
예제 #10
0
        //executes a single statement
        void ExecuteNextStatement()
        {
            Token keyword = lastToken;

            expressionMarker = (Marker)lexer.Position.Clone();
            ReadNextToken();
            Value         expr;
            IfElifFrame   prevElifFrame;
            FunctionFrame functionFrame;

            switch (keyword)
            {
            case Token.Global:
                MatchToken(Token.Identifier);
                GlobalVariables.Add(lexer.TokenIdentifier, Value.Null);
                ReadNextToken();
                break;

            case Token.Abstract:
                MatchToken(Token.Identifier);
                GlobalVariables.Add(lexer.TokenIdentifier, new Value(new Expression(lexer.TokenIdentifier)));
                ReadNextToken();
                break;

            case Token.Identifier:
                string id = lexer.TokenIdentifier;
                if (lastToken == Token.Set)
                {
                    if (ReadOnlyVariables.Contains(id))
                    {
                        throw new Exception("FastCode cannot write to a read only variable.");
                    }
                    ReadNextToken();
                    expr = EvaluateNextExpression();
                    if (expr == null)
                    {
                        return;
                    }
                    if (GlobalVariables.ContainsKey(id))
                    {
                        GlobalVariables[id] = expr;
                        break;
                    }
                    else
                    {
                        functionFrame = GetCurrentContext();
                        if (functionFrame.LocalVariables.ContainsKey(id))
                        {
                            functionFrame.LocalVariables[id] = expr;
                        }
                        else
                        {
                            functionFrame.LocalVariables.Add(id, expr);
                        }
                    }
                    break;
                }
                else if (lastToken == Token.OpenParenthesis)
                {
                    if (functions.ContainsKey(id) || builtInFunctions.ContainsKey(id))
                    {
                        lexer.ShiftCurrentPosition(keywordMarker);
                        ReadNextToken();
                        EvaluateNextExpression();
                        break;
                    }
                }
                else if (lastToken == Token.OpenBracket)
                {
                    ReadNextToken();
                    Value indexValue = EvaluateNextExpression();
                    if (indexValue == null)
                    {
                        return;
                    }
                    if (indexValue.Type != ValueType.Double)
                    {
                        throw new Exception("Indicie's must be of type double.");
                    }
                    MatchToken(Token.CloseBracket);
                    ReadNextToken();
                    MatchToken(Token.Set);
                    ReadNextToken();
                    Value setval = EvaluateNextExpression();
                    if (setval == null)
                    {
                        return;
                    }
                    if (GlobalVariables.ContainsKey(id))
                    {
                        if (GlobalVariables[id].Type == ValueType.Array)
                        {
                            GlobalVariables[id].Array[(int)indexValue.Double] = setval;
                            break;
                        }
                        else if (GlobalVariables[id].Type == ValueType.String)
                        {
                            if (setval.Type != ValueType.Character)
                            {
                                throw new Exception("Strings can only index characters.");
                            }
                            char[] str = GlobalVariables[id].String.ToCharArray();
                            str[(int)indexValue.Double] = setval.Character;
                            GlobalVariables[id]         = new Value(new string(str));
                            break;
                        }
                    }
                    else
                    {
                        functionFrame = GetCurrentContext();
                        if (functionFrame.LocalVariables[id].Type == ValueType.Array)
                        {
                            functionFrame.LocalVariables[id].Array[(int)indexValue.Double] = setval;
                            break;
                        }
                        else if (functionFrame.LocalVariables[id].Type == ValueType.String)
                        {
                            if (setval.Type != ValueType.Character)
                            {
                                throw new Exception("Strings can only index characters.");
                            }
                            char[] str = functionFrame.LocalVariables[id].String.ToCharArray();
                            str[(int)indexValue.Double]      = setval.Character;
                            functionFrame.LocalVariables[id] = new Value(new string(str));
                            break;
                        }
                    }
                }
                throw new Exception("Identifier \"" + id + "\" cannot stand alone without a keyword.");

            case Token.Break:
                int i = 0;
                while (!(CallStack.Peek().GetType() == typeof(WhileFrame) || CallStack.Peek().GetType() == typeof(ForFrame)))
                {
                    if (CallStack.Peek().GetType() == typeof(FunctionFrame))
                    {
                        throw new UnexpectedStatementException(Token.Break.ToString());
                    }
                    i++;
                    prevCallFrame = CallStack.Pop();
                }
                prevCallFrame = CallStack.Pop();
                SkipCallFrame(i);
                break;

            case Token.Return:
                functionFrame = null;
                int j = 0;
                while (CallStack.Count != 0)
                {
                    if (CallStack.Peek().GetType() == typeof(FunctionFrame))
                    {
                        functionFrame = (FunctionFrame)CallStack.Pop();
                        if (functionFrame.Identifier == "MAINSTRUCTURE")
                        {
                            throw new Exception("Only functions may return values.");
                        }
                        break;
                    }
                    CallStack.Pop();
                    j++;
                }
                if (PeekNextToken() != Token.Newline && PeekNextToken() != Token.Semicolon)
                {
                    CallStack.Push(functionFrame);
                    expr = EvaluateNextExpression();
                    if (expr == null)
                    {
                        return;
                    }
                    functionFrame = (FunctionFrame)CallStack.Pop();
                    functionFrame.ReturnResult = expr;
                }
                CallStack.Push(functionFrame);
                SkipCallFrame(j, true);
                ExecuteNextStatement();
                break;

            case Token.Stop:
                Exit = true;
                return;

            case Token.Import:
                MatchToken(Token.Value);
                if (lexer.TokenValue.Type != ValueType.String)
                {
                    throw new Exception("Expected string, got " + lexer.TokenValue.Type);
                }

                ReadNextToken();
                break;

            case Token.EndOfFile:
                Exit = true;
                return;

            case Token.If:
                IfElifFrame ifFrame = new IfElifFrame();
                expr = EvaluateNextExpression();
                if (expr == null)
                {
                    return;
                }
                ifFrame.Result = (expr.PerformBinaryOperation(Token.Equals, new Value(0)).Double == 1);     //not not the actual result, it just checks if the condition failed so it can skip that section. Kinda misleading if you didn't know - just refer to the assertion token's case.
                CallStack.Push(ifFrame);

                readTillCallFrameStart();     //read till open bracket

                if (ifFrame.Result == true)   //skip till close bracket.
                {
                    SkipCallFrame();
                    prevCallFrame = CallStack.Pop();
                }

                break;

            case Token.Else:     //not if results are inverted
                if (prevCallFrame.GetType() != typeof(IfElifFrame))
                {
                    throw new UnexpectedStatementException(keyword.ToString());
                }
                prevElifFrame = (IfElifFrame)prevCallFrame;
                if (prevElifFrame.Result == true)     //skip all the crap
                {
                    CallStack.Push(new ElseFrame());
                    readTillCallFrameStart();
                }
                else if (prevElifFrame.Result == false)
                {
                    CallStack.Push(new ElseFrame());
                    readTillCallFrameStart();
                    SkipCallFrame();
                    prevCallFrame = CallStack.Pop();
                }
                break;

            case Token.Elif:
                if (prevCallFrame.GetType() != typeof(IfElifFrame))
                {
                    throw new UnexpectedStatementException(keyword.ToString());
                }
                IfElifFrame elifFrame = new IfElifFrame();
                prevElifFrame = (IfElifFrame)prevCallFrame;
                if (prevElifFrame.Result == true)
                {
                    expr = EvaluateNextExpression();
                    if (expr == null)
                    {
                        return;
                    }
                    elifFrame.Result = (expr.PerformBinaryOperation(Token.Equals, new Value(0)).Double == 1);
                    CallStack.Push(elifFrame);
                    readTillCallFrameStart();
                    if (elifFrame.Result == true)
                    {
                        SkipCallFrame();
                        prevCallFrame = CallStack.Pop();
                    }
                }
                else
                {
                    CallStack.Push(elifFrame);
                    readTillCallFrameStart();
                    SkipCallFrame();
                    prevCallFrame = CallStack.Pop();
                }
                break;

            case Token.While:
                WhileFrame whileFrame = new WhileFrame();
                whileFrame.ExpressionMarker = (Marker)expressionMarker.Clone();
                expr = EvaluateNextExpression();
                if (expr == null)
                {
                    return;
                }
                CallStack.Push(whileFrame);
                readTillCallFrameStart();
                if (expr.PerformBinaryOperation(Token.Equals, new Value(0)).Double == 1)
                {
                    SkipCallFrame();
                    prevCallFrame = CallStack.Pop();
                }
                break;

            case Token.For:
                ForFrame forFrame = new ForFrame();
                MatchToken(Token.Identifier);
                forFrame.IndexerIdentifier = lexer.TokenIdentifier;
                ReadNextToken();
                MatchToken(Token.In);
                ReadNextToken();
                expr = EvaluateNextExpression();
                if (expr == null)
                {
                    return;
                }
                if (expr.Type == ValueType.Array)
                {
                    forFrame.Values = expr.Array;
                }
                else if (expr.Type == ValueType.String)
                {
                    forFrame.Values = new List <Value>();
                    for (int k = 0; k < expr.String.Length; k++)
                    {
                        forFrame.Values.Add(new Value(expr.String[k]));
                    }
                }
                else
                {
                    throw new Exception("Fastcode can only iterate through an array or string.");
                }
                forFrame.currentIndex = 0;
                functionFrame         = GetCurrentContext();
                if (forFrame.Values.Count > 0)
                {
                    if (functionFrame.LocalVariables.ContainsKey(forFrame.IndexerIdentifier))
                    {
                        functionFrame.LocalVariables[forFrame.IndexerIdentifier] = forFrame.Values[0];
                    }
                    else
                    {
                        functionFrame.LocalVariables.Add(forFrame.IndexerIdentifier, forFrame.Values[0]);
                    }
                }

                CallStack.Push(forFrame);
                readTillCallFrameStart();
                if (forFrame.currentIndex >= forFrame.Values.Count)
                {
                    SkipCallFrame();
                    prevCallFrame = CallStack.Pop();
                }
                break;

            case Token.Function:
                MatchToken(Token.Identifier);
                string fid = lexer.TokenIdentifier;
                if (functions.ContainsKey(fid) || GlobalVariables.ContainsKey(fid) || builtInFunctions.ContainsKey(fid))
                {
                    throw new Exception("Identifiers must be unique");
                }
                functionFrame = new FunctionFrame(fid);
                ReadNextToken();
                MatchToken(Token.OpenParenthesis);
                List <string> argument_identifiers = new List <string>();
                while (lastToken != Token.CloseParenthesis)
                {
                    ReadNextToken();
                    if (lastToken == Token.Comma || lastToken == Token.CloseParenthesis)
                    {
                        continue;
                    }
                    else if (lastToken == Token.Identifier)
                    {
                        if (argument_identifiers.Contains(lexer.TokenIdentifier) || GlobalVariables.ContainsKey(lexer.TokenIdentifier))
                        {
                            throw new Exception("Argument identifiers must be unique.");
                        }
                        argument_identifiers.Add(lexer.TokenIdentifier);
                    }
                    else if (lastToken == Token.CloseParenthesis)
                    {
                        break;
                    }
                    else
                    {
                        throw new UnexpectedStatementException("an identifier", lastToken.ToString());
                    }
                }
                functionFrame.SetArgumentParameters(argument_identifiers);
                CallStack.Push(functionFrame);
                readTillCallFrameStart();
                functionFrame  = (FunctionFrame)CallStack.Pop();
                functions[fid] = functionFrame;
                SkipCallFrame();
                break;

            case Token.CloseBrace:     //checks to return or repeat.
                if (CallStack.Peek().GetType() == typeof(WhileFrame))
                {
                    Marker currentpos = (Marker)lexer.Position.Clone();
                    lexer.ShiftCurrentPosition(((WhileFrame)CallStack.Peek()).ExpressionMarker);
                    ReadNextToken();
                    expr = EvaluateNextExpression();
                    if (expr == null)
                    {
                        return;
                    }
                    if (expr.PerformBinaryOperation(Token.Equals, new Value(0)).Double == 1)
                    {
                        prevCallFrame = CallStack.Pop();
                        lexer.ShiftCurrentPosition(currentpos);
                    }
                    else
                    {
                        lexer.ShiftCurrentPosition(CallStack.Peek().StartPosition);
                        ReadNextToken();
                    }
                }
                else if (CallStack.Peek().GetType() == typeof(ForFrame))
                {
                    ForFrame forStructure2 = (ForFrame)CallStack.Pop();
                    forStructure2.currentIndex++;
                    functionFrame = GetCurrentContext();
                    if (forStructure2.currentIndex < forStructure2.Values.Count)
                    {
                        functionFrame.LocalVariables[forStructure2.IndexerIdentifier] = forStructure2.Values[forStructure2.currentIndex];
                        CallStack.Push(forStructure2);
                        lexer.ShiftCurrentPosition(CallStack.Peek().StartPosition);
                        ReadNextToken();
                    }
                    else
                    {
                        functionFrame.LocalVariables.Remove(forStructure2.IndexerIdentifier);
                    }
                }
                else if (CallStack.Peek().GetType() == typeof(FunctionFrame))
                {
                    functionFrame = (FunctionFrame)CallStack.Pop();
                    lexer.ShiftCurrentPosition(functionFrame.ReturnPosition);
                    GetCurrentContext().functionResults.Enqueue(functionFrame.ReturnResult);
                }
                else
                {
                    prevCallFrame = CallStack.Pop();
                }

                break;

            default:
                throw new UnexpectedStatementException(keyword.ToString());
            }
            if (lastToken == Token.Semicolon)
            {
                keywordMarker = (Marker)lexer.Position.Clone();
                ReadNextToken();
                while (lastToken == Token.Newline)
                {
                    ReadNextToken();
                }
                ExecuteNextStatement();
            }
        }