/// <summary>
 ///		Returns true if the given data type is valid for the given operator. 
 /// </summary>
 /// <param name="type">Data type to check operator against.</param>
 /// <param name="opToken">Operator to check validitity for.</param>
 /// <returns>True if the given data type is valid for the given operator.</returns>
 private bool OperatorDataTypeValid(DataTypeValue type, TokenID opToken)
 {
     if (type.DataType == DataType.Invalid) return false;
     if (type.IsArray == true && opToken != TokenID.OpAssign && opToken != TokenID.OpEqual && opToken != TokenID.OpNotEqual) return false;
     switch (opToken)
     {
         case TokenID.OpAdd:
             return (type.DataType == DataType.Object ? false : true);
         case TokenID.OpAssign:
             return true;
         case TokenID.OpAssignAdd:
             return (type.DataType == DataType.Object ? false : true);
         case TokenID.OpAssignBitwiseAnd:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignBitwiseOr:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignBitwiseNot:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignBitwiseSHL:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignBitwiseSHR:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignBitwiseXOr:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignDivide:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpAssignModulus:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpAssignMultiply:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpAssignSub:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpBitwiseAnd:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpBitwiseOr:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpBitwiseSHL:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpBitwiseSHR:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpBitwiseXOr:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpBitwiseNot:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpDecrement:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpDivide:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpEqual:
             return true;
         case TokenID.OpGreater:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpGreaterEqual:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpIncrement:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpLess:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpLessEqual:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpLogicalAnd:
             return (type.DataType != DataType.Bool ? false : true);
         case TokenID.OpLogicalOr:
             return (type.DataType != DataType.Bool ? false : true);
         case TokenID.OpLogicalNot:
             return (type.DataType != DataType.Bool ? false : true);
         case TokenID.OpModulus:
             return (type.DataType != DataType.Int ? false : true);
         case TokenID.OpMultiply:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         case TokenID.OpNotEqual:
             return true;
         case TokenID.OpSub:
             return (type.DataType == DataType.Object || type.DataType == DataType.String || type.DataType == DataType.Null ? false : true);
         default:
             return false;
     }
 }
 /// <summary>
 ///		Checks if a given parameter data type can be applied to this parameter.
 /// </summary>
 /// <param name="index">Index of parameter to check.</param>
 /// <returns>Boolean describing if the data type is valid.</returns>
 public bool CheckParameterTypeValid(int index, DataTypeValue value)
 {
     if (index >= _symbolList.Count) return false;
     VariableSymbol symbol = _symbolList[index] as VariableSymbol;
     return (symbol.DataType == value || value.DataType == DataType.Null);//|| ScriptCompiler.CanImplicitlyCast(symbol.DataType, value));
 }
 /// <summary>
 ///		Nullifys all values in this instance.
 /// </summary>
 public void Clear()
 {
     _booleanLiteral = false;
     _byteLiteral = 0;
     _doubleLiteral = 0;
     _floatLiteral = 0;
     _integerLiteral = 0;
     _longLiteral = 0;
     _memoryIndex = -1;
     _shortLiteral = 0;
     _stringLiteral = "";
     _objectIndex = -1;
     _referenceCount = 0;
     _valueType = RuntimeValueType.Invalid;
     _dataType = null;
 }
        /// <summary>
        ///		Parses a single statement. A statement encompesses the highest level of parsing, things like
        ///		the while loop, the if statement and the return statement ... ecetera.
        /// </summary>
        private void ParseStatement()
        {
            // Check is is an empty statement.
            if (LookAheadToken() != null && LookAheadToken().ID == TokenID.CharSemiColon)
            {
                ExpectToken(TokenID.CharSemiColon);
                return;
            }

            // Check if there is an open block next, and if so parse it.
            if (LookAheadToken().ID == TokenID.CharOpenBrace)
            {
                ParseBlock(TokenID.CharOpenBrace, TokenID.CharCloseBrace);
                return;
            }

            // Check if we have a chunk of meta data next.
            bool foundThisParse = true;
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                _lastMetaDataSymbol = null;
                foundThisParse = true;
                ParseMetaData();
            }

            // Emit a enter statement opcode if in debug.
            bool isBreakpoint = (LookAheadToken().ID == TokenID.KeywordBreakpoint);
            if ((_compileFlags & CompileFlags.Debug) != 0 && _currentPass == 1 && isBreakpoint == false)
                CreateInstruction(OpCode.ENTER_STATEMENT, _currentScope, (Token)_tokenList[_tokenIndex]);

            // Parse based on starting token.
            switch (NextToken().ID)
            {
                // General statements.
                case TokenID.KeywordDo:			ParseDo();			break;
                case TokenID.KeywordEnum:		ParseEnum();		break;
                case TokenID.KeywordIf:			ParseIf();			break;
                case TokenID.KeywordLock:		ParseLock();		break;
                case TokenID.KeywordAtom:		ParseAtom();		break;
                case TokenID.KeywordReturn:		ParseReturn();		break;
                case TokenID.KeywordSwitch:		ParseSwitch();		break;
                case TokenID.KeywordState:		ParseState();		break;
                case TokenID.KeywordWhile:		ParseWhile();		break;
                case TokenID.KeywordFor:		ParseFor();			break;
                case TokenID.KeywordGoto:		ParseGoto();		break;
                case TokenID.KeywordBreak:		ParseBreak();		break;
                case TokenID.KeywordContinue:	ParseContinue();	break;
                case TokenID.KeywordGotoState:	ParseGotoState();	break;
                case TokenID.KeywordBreakpoint: ParseBreakPoint();  break;
                case TokenID.KeywordNamespace:  ParseNamespace();   break;

                case TokenID.KeywordEditor:
                case TokenID.KeywordEngine:
                    ParseState();
                    break;
                /*
                case TokenID.KeywordStruct:		ParseStruct();		break;
                case TokenID.KeywordClass:		ParseClass();		break;
                */

                // Variable / function declarations.
                case TokenID.KeywordBool:
                case TokenID.KeywordByte:
                case TokenID.KeywordDouble:
                case TokenID.KeywordObject:
                case TokenID.KeywordFloat:
                case TokenID.KeywordInt:
                case TokenID.KeywordLong:
                case TokenID.KeywordShort:
                case TokenID.KeywordString:
                case TokenID.KeywordVoid:
                case TokenID.KeywordConst:
                case TokenID.KeywordStatic:
                case TokenID.KeywordProperty:
                case TokenID.KeywordImport:
                case TokenID.KeywordExport:
                case TokenID.KeywordThread:
                case TokenID.KeywordPublic:
                case TokenID.KeywordProtected:
                case TokenID.KeywordPrivate:
                case TokenID.KeywordEvent:
                case TokenID.KeywordConsole:

                    int offset = 0;
                    if (_currentToken.ID == TokenID.KeywordPublic || _currentToken.ID == TokenID.KeywordProtected || _currentToken.ID == TokenID.KeywordPrivate)
                        offset = 1;

                    if (_currentToken.ID == TokenID.KeywordConsole || _currentToken.ID == TokenID.KeywordEvent || _currentToken.ID == TokenID.KeywordExport || _currentToken.ID == TokenID.KeywordImport || _currentToken.ID == TokenID.KeywordThread || LookAheadToken(2 + offset).ID == TokenID.CharOpenParenthesis)
                        ParseFunction();

                    // If its not parenthesis its a variable declaration.
                    else
                        ParseVariable();

                    break;

                // Assignments and function calls.
                case TokenID.TypeIdentifier:

                    // Check if its a label.
                    if (LookAheadToken().ID == TokenID.CharColon)
                        ParseLabel();

                    // See if its a function or assignment.
                    else
                    {
                        int tokenIndex = _tokenIndex;
                        Token currentToken = _currentToken;
                        ResolveMemberScope();

                        // Ignore any array accessors.
                        if (LookAheadToken().ID == TokenID.CharOpenBracket)
                        {
                            NextToken();
                            int depth = 1;
                            while (depth != 0)
                            {
                                NextToken();
                                if (_currentToken.ID == TokenID.CharOpenBracket)
                                    depth++;
                                else if (_currentToken.ID == TokenID.CharCloseBracket)
                                    depth--;
                            }
                            //ExpectToken(TokenID.CharCloseBracket);
                        }

                        // Function
                        if (LookAheadToken().ID == TokenID.CharOpenParenthesis)
                        {
                            string functionName = _currentToken.Ident;
                            _tokenIndex = tokenIndex;
                            _currentToken = currentToken;

                            // Check we are in a valid scope.
                            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                                Error(ErrorCode.InvalidScope, "Function calls are only valid inside a function's or event's scope.", false, 0);

                            DataTypeValue functionDataType = ParseFunctionCall();

                            // Do we have a member call after?
                            if (LookAheadToken().ID == TokenID.OpMemberResolver)
                            {
                                NextToken();

                                // If its not an object how can we access it?
                                if (functionDataType != new DataTypeValue(DataType.Object, false, false))
                                    Error(ErrorCode.IllegalResolve, "Member accessing can only be preformed on objects.", false, 1);

                                // Parse the cast.
                                ExpectToken(TokenID.CharOpenParenthesis);
                                if (NextToken().IsDataType == false)
                                    Error(ErrorCode.InvalidCast, "Attempt to cast member to unknown type.", false, 0);

                                DataTypeValue castDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);

                                // Is it an array?
                                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                                {
                                    NextToken();
                                    ExpectToken(TokenID.CharCloseBracket);
                                    castDataType.IsArray = true;
                                }
                                ExpectToken(TokenID.CharCloseParenthesis);

                                ExpectToken(TokenID.TypeIdentifier);

                                if (LookAheadToken().ID == TokenID.CharOpenParenthesis)
                                    ParseMemberFunctionCall(_currentToken.Ident, castDataType);
                                else
                                    ParseMemberAssignment(_currentToken.Ident, castDataType);
                            }

                            ExpectToken(TokenID.CharSemiColon);
                        }

                        // Member function / assignment?
                        else if (LookAheadToken().ID == TokenID.OpMemberResolver)
                        {
                            ParseMemberAccessor();
                            ExpectToken(TokenID.CharSemiColon);
                        }

                        // Assignment.
                        else
                        {
                            _tokenIndex = tokenIndex;
                            _currentToken = currentToken;

                            ParseAssignment();
                            ExpectToken(TokenID.CharSemiColon);
                        }
                    }

                    break;

                // Its none of the above its invalid.
                default:
                    Error(ErrorCode.UnexpectedToken, "Encountered unexpected token \"" + _currentToken.ToString() + "\"", false, 0);

                    break;
            }

            // Emit a exit statement opcode if in debug.
            if ((_compileFlags & CompileFlags.Debug) != 0 && _currentPass == 1 && isBreakpoint == false)
                CreateInstruction(OpCode.EXIT_STATEMENT, _currentScope, _currentToken);

            // If we read in any meta data associated with this statement then destroy it now.
            if (_metaDataList.Count > 0 && foundThisParse == true)
            {
                Symbol symbolToAttachTo = null;
                if (_lastMetaDataSymbol != null)
                    symbolToAttachTo = _lastMetaDataSymbol;
                else
                    symbolToAttachTo = _currentScope;

                if (_currentPass == 0)
                {
                    foreach (MetaDataSymbol metaDataSymbol in _metaDataList)
                    {
                        metaDataSymbol.Scope = symbolToAttachTo;
                        symbolToAttachTo.AddSymbol(metaDataSymbol);
                    }
                }
                _metaDataList.Clear();
            }
        }
        /// <summary>
        ///		Parses a lower level expression. The lower level is responsible for parsing 
        ///		any factors and the -> operator.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseSubTermExpression()
        {
            // Parse the left hand factor expression.
            DataTypeValue factorDataType1 = ParseFactorExpression();

            // Parse any subsequent factor expressions.
            while (true)
            {
                // Check that the next token is an member resolver operator.
                Token operatorToken = LookAheadToken();
                if (operatorToken.ID != TokenID.OpMemberResolver)
                    break;
                NextToken();

                // If its not an object how can we access it?
                if (factorDataType1.DataType != DataType.Object)
                    Error(ErrorCode.IllegalResolve, "Member accessing can only be preformed on objects.", false, 1);

                // ARRAY ACCESSING!

                // Parse the cast.
                ExpectToken(TokenID.CharOpenParenthesis);
                if (NextToken().IsDataType == false)
                    Error(ErrorCode.InvalidCast, "Attempt to cast member to unknown type.", false, 0);

                DataTypeValue castDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);

                // Is it an array?
                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                {
                    NextToken();
                    ExpectToken(TokenID.CharCloseBracket);
                    castDataType.IsArray = true;
                }
                ExpectToken(TokenID.CharCloseParenthesis);

                // Set the factor data type as the casts value.
                factorDataType1 = castDataType;

                // Read in the indentifier of the member.
                string identifier = ExpectToken(TokenID.TypeIdentifier).Ident;

                // Parse The member that is being called.
                if (LookAheadToken().ID != TokenID.CharOpenParenthesis)
                {
                    // Are we going to index it?
                    bool parsingArray = false;
                    DataTypeValue arrayIndexValue = new DataTypeValue(DataType.Invalid, false, false);
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        parsingArray = true;
                        arrayIndexValue = ParseExpression();
                        ExpectToken(TokenID.CharCloseBracket);
                    }

                    // Create the symbol.
                    VariableSymbol variableSymbol = null;
                    if (_currentPass == 0)
                    {
                        variableSymbol = _memberScope.FindVariableSymbol(identifier, castDataType) as VariableSymbol;
                        if (variableSymbol == null)
                        {
                            variableSymbol = new VariableSymbol(_memberScope);
                            variableSymbol.Identifier = identifier;
                            variableSymbol.DataType = castDataType;
                            variableSymbol.VariableType = VariableType.Member;
                        }
                    }
                    else if (_currentPass == 1)
                        variableSymbol = _memberScope.FindVariableSymbol(identifier, castDataType) as VariableSymbol;

                    if (_currentPass == 1)
                    {
                        Instruction instruction = null;

                        // Pop the index into arith 1.
                        if (parsingArray == true)
                        {
                            instruction = CreateInstruction(OpCodeByType(arrayIndexValue, OpCodeType.POP), _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic1);
                        }

                        // Pop the object into the member register.
                        instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);

                        // Call the GET_MEMBER opCode.
                        if (parsingArray)
                        {
                            instruction = CreateInstruction(OpCode.GET_MEMBER, _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic2);
                            new Operand(instruction, variableSymbol);
                        }
                        else
                        {
                            instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic2);
                            new Operand(instruction, variableSymbol);
                            new Operand(instruction, Register.Arithmetic1);
                        }

                        // Push the returned value.
                        instruction = CreateInstruction(OpCodeByType(castDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, Register.Return);
                    }
                }
                else
                {
                    #region Function calling

                    // Parse the function call and remember the return type.
                    ParseMemberFunctionCall(identifier, castDataType);

                    // Push the return value of the function onto the stack.
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(castDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, Register.Return);
                    }

                    #endregion
                }
            }

            return factorDataType1;
        }
        /// <summary>
        ///		Parses the lowest level of an expression. The lowest level is respolsible
        ///		for parsing things such as literal values and function calls, it also
        ///		deals with unary, prefix and postfix operators.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseFactorExpression()
        {
            // Declare a variable to store the data type in.
            DataTypeValue factorDataType = new DataTypeValue(DataType.Invalid, false, false);
            StringSymbol stringSymbol = null;

            #region Unary op
            // Check if there is a unary operator pending.
            bool unaryOpPending = false;
            Token unaryOpToken = LookAheadToken();
            if (unaryOpToken.ID == TokenID.OpAdd || unaryOpToken.ID == TokenID.OpSub ||
                unaryOpToken.ID == TokenID.OpLogicalNot || unaryOpToken.ID == TokenID.OpBitwiseNot ||
                unaryOpToken.ID == TokenID.OpIncrement || unaryOpToken.ID == TokenID.OpDecrement)
            {
                unaryOpPending = true;
                NextToken();
            }
            #endregion

            #region Cast Pending
            // Check if there is a explicit cast pending.
            bool castPending = false;
            DataTypeValue castType = new DataTypeValue(DataType.Invalid, false, false);
            if (LookAheadToken().ID == TokenID.CharOpenParenthesis)
            {
                castType.DataType = DataTypeFromKeywordToken(LookAheadToken(2).ID);
                if (castType.DataType != DataType.Invalid)
                {
                    NextToken(); // Read in open parenthesis.
                    NextToken(); // Read in cast keyword.
                    // Check for array.
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        NextToken();
                        castType.IsArray = true;
                        ExpectToken(TokenID.CharCloseBracket);
                    }
                    ExpectToken(TokenID.CharCloseParenthesis); // Read in closing parenthesis.
                    castPending = true;
                }
            }
            #endregion

            // Determine what factor type we are looking at
            // and act accordingly.
            NextToken();
            switch (_currentToken.ID)
            {
                #region Indexer
                case TokenID.KeywordIndexer:

                    // Check we are inside an indexer loop.
                    if (_insideIndexerLoop == false)
                        Error(ErrorCode.InvalidIndexer, "The Indexer keyword can only be used inside a valid indexable loop.");

                    // Set the factor data type as an integer (an indexer is always an integer).
                    factorDataType = new DataTypeValue(DataType.Int, false, false);

                    // Generate byte code to push indexer onto the stack.
                    if (_currentPass == 1)
                    {
                        VariableSymbol indexerVariable = _currentScope.FindSymbol("$" + _indexerLoopIndex, SymbolType.Variable) as VariableSymbol;
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        Operand.DirectStackOperand(instruction, indexerVariable.StackIndex);
                    }
                    break;

                #endregion
                #region New
                case TokenID.KeywordNew:

                    // Read in identifier specifying what we wish to create a new
                    // instance of.
                    NextToken();

                    // Check if we are detailing with a data type.
                    DataTypeValue dataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), true, false);
                    factorDataType = dataType;
                    if (dataType.DataType != DataType.Invalid)
                    {

                        // Check this is an array.
                        if (LookAheadToken().ID == TokenID.CharOpenBracket)
                        {
                            // Read in opening bracket.
                            NextToken();

                            // Parse the size expression.
                            DataTypeValue indexDataType = ParseExpression();

                            // Make sure we can convert it to an integer index.
                            if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), indexDataType))
                            {
                                // If we are in pass 2 create the byte code to allocate a
                                // new array on the heap and associate it with this variable.
                                if (_currentPass == 1)
                                {
                                    // Pop the index value into arith register 2.
                                    Instruction instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Arithmetic2);

                                    // Cast?

                                    // Allocate enough space on the heap for the array.
                                    instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.ALLOCATE_HEAP), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Arithmetic2);
                                    new Operand(instruction, Register.Reserved4);

                                    // Push the memory index onto the stack.
                                    instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Reserved4);
                                }
                            }
                            else
                                Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + indexDataType.ToString() + "\"", false, 0);

                            // Read in closing bracket.
                            ExpectToken(TokenID.CharCloseBracket);

                            if (LookAheadToken().ID == TokenID.CharOpenBrace)
                            {
                                ExpectToken(TokenID.CharOpenBrace);

                                int index = 0;
                                while (true)
                                {
                                    // Parse the expression
                                    DataTypeValue valueType = ParseExpression();
                                    if (CanImplicitlyCast(new DataTypeValue(dataType.DataType, false, false), valueType) == true)
                                    {
                                        // Its valid so insert.
                                        if (_currentPass == 1)
                                        {
                                            Instruction instruction = null;

                                            // Pop the value into arith 2.
                                            instruction = CreateInstruction(OpCodeByType(valueType, OpCodeType.POP), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Arithmetic2);

                                            // Pop the memory index off the stack.
                                            instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.POP), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved4);

                                            // Do we need to cast first?
                                            if (dataType.DataType != valueType.DataType)
                                            {
                                                // Cast value.
                                                instruction = CreateInstruction(OpCodeByType(new DataTypeValue(dataType.DataType, false, false), OpCodeType.CAST), _currentScope, _currentToken);
                                                new Operand(instruction, Register.Arithmetic2);
                                            }

                                            // Move index into arith 3.
                                            instruction = CreateInstruction(OpCode.MOV_INT, _currentScope, _currentToken);
                                            new Operand(instruction, Register.Arithmetic3);
                                            new Operand(instruction, index);

                                            // Insert!
                                            instruction = CreateInstruction(OpCodeByType(new DataTypeValue(dataType.DataType, false, false), OpCodeType.MOV), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved4, Register.Arithmetic3);
                                            new Operand(instruction, Register.Arithmetic2);

                                            // Push the memory index back onto the stack.
                                            instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved4);
                                        }
                                    }
                                    else
                                        Error(ErrorCode.InvalidDataType, "Unable to implicitly cast from type \"" + DataTypeFromTypeToken(_currentToken.ID).ToString() + "\" to type \"" + dataType.DataType.ToString() + "\".", false, 1);

                                    // Read in comma or break out of loop if there isn't one.
                                    if (LookAheadToken().ID == TokenID.CharComma)
                                    {
                                        NextToken();
                                        index++;
                                    }
                                    else
                                        break;
                                }

                                ExpectToken(TokenID.CharCloseBrace);
                            }
                        }
                        else
                            Error(ErrorCode.InvalidFactor, "Primitive data types must currently be created as arrays.", false,0);
                    }
                    else
                        Error(ErrorCode.InvalidFactor, "New keyword can currently only be used to create new primitive data arrays.", false,0);

                    break;
                #endregion
                #region Boolean
                case TokenID.TypeBoolean:
                    factorDataType = new DataTypeValue(DataType.Bool, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, bool.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Byte
                case TokenID.TypeByte:
                    factorDataType = new DataTypeValue(DataType.Byte, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, byte.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Double
                case TokenID.TypeDouble:
                    factorDataType = new DataTypeValue(DataType.Double, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, double.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Float
                case TokenID.TypeFloat:
                    factorDataType = new DataTypeValue(DataType.Float, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, float.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Integer
                case TokenID.TypeInteger:
                    factorDataType = new DataTypeValue(DataType.Int, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        if (_currentToken.Ident.Length > 2 && _currentToken.Ident.Substring(0, 2) == "0x")
                            new Operand(instruction, Convert.ToInt32(_currentToken.Ident, 16));
                        else
                            new Operand(instruction, int.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Long
                case TokenID.TypeLong:
                    factorDataType = new DataTypeValue(DataType.Long, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, Convert.ToInt64(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Short
                case TokenID.TypeShort:
                    factorDataType = new DataTypeValue(DataType.Short, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, short.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Null
                case TokenID.TypeNull:
                    factorDataType = new DataTypeValue(DataType.Null, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                    }
                    break;
                #endregion
                #region String
                case TokenID.TypeString:
                    // Always add strings to the global scope, this stops them
                    // being duplicated in multiple scopes.
                    factorDataType = new DataTypeValue(DataType.String, false, false);

                    // Check for a pre-existing string with the same value.
                    foreach (Symbol subSymbol in _globalScope.Symbols)
                    {
                        if (subSymbol.Identifier == null || subSymbol.Type != SymbolType.String) continue;
                        if (subSymbol.Identifier == _currentToken.Ident)
                        {
                            stringSymbol = subSymbol as StringSymbol;
                            break;
                        }
                    }

                    if (stringSymbol == null) stringSymbol = new StringSymbol(_globalScope, _currentToken.Ident);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, stringSymbol);
                    }
                    break;
                #endregion
                #region Identifier
                case TokenID.TypeIdentifier:
                    VariableSymbol symbol = null;
                    string symbolIdent = _currentToken.Ident;
                    int tokenIndex = _tokenIndex;
                    Token currentToken = _currentToken;
                    Symbol resolvedScope = ResolveMemberScope();
                    symbol = resolvedScope == null ? null : resolvedScope.FindSymbol(_currentToken.Ident, SymbolType.Variable) as VariableSymbol;
                    if (symbol != null)
                    {
                        // Tag the variable as used so we don't end up throwing up a warning.
                        symbol.IsUsed = true;

                        // Set the factor data type.
                        factorDataType = new DataTypeValue(symbol.DataType.DataType, symbol.DataType.IsArray, symbol.DataType.IsReference);

                        if (symbol.IsConstant == true && symbol.ConstToken != null)
                        {
                            switch (symbol.DataType.DataType)
                            {
                                case DataType.Bool:
                                    factorDataType = new DataTypeValue(DataType.Bool, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, bool.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Byte:
                                    factorDataType = new DataTypeValue(DataType.Byte, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, byte.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Double:
                                    factorDataType = new DataTypeValue(DataType.Double, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, double.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Float:
                                    factorDataType = new DataTypeValue(DataType.Float, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, float.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Int:
                                    factorDataType = new DataTypeValue(DataType.Int, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        if (symbol.ConstToken.Ident.Length > 2 && symbol.ConstToken.Ident.Substring(0, 2) == "0x")
                                            new Operand(instruction, Convert.ToInt32(symbol.ConstToken.Ident, 16));
                                        else
                                            new Operand(instruction, int.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Long:
                                    factorDataType = new DataTypeValue(DataType.Long, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, Convert.ToInt64(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Short:
                                    factorDataType = new DataTypeValue(DataType.Short, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, short.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.String:
                                    factorDataType = new DataTypeValue(DataType.String, false, false);
                                    stringSymbol = _globalScope.FindSymbol(symbol.ConstToken.Ident, SymbolType.String) as StringSymbol;
                                    if (stringSymbol == null) stringSymbol = new StringSymbol(_globalScope, symbol.ConstToken.Ident);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, stringSymbol);
                                    }
                                    break;
                            }
                        }
                        else
                        {
                            // Check if we are parsing an array.
                            if (LookAheadToken().ID == TokenID.CharOpenBracket)
                            {
                                // As the array is indexed we can remove array from the factor data type.
                                factorDataType.IsArray = false;

                                // Read in open bracket.
                                NextToken();

                                // Make sure it really is an array.
                                if (symbol.IsArray == false) Error(ErrorCode.InvalidArrayIndex, "Non-array variables can not be indexed.", false, 0);

                                // Check that the next token is not a closing brace otherwise
                                // its an invalid index.
                                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                                    Error(ErrorCode.InvalidArrayIndex, "Array's must be indexed.", false, 0);

                                // Parse the index expression.
                                DataTypeValue indexDataType = ParseExpression();
                                ExpectToken(TokenID.CharCloseBracket);

                                // Check the index data type can be cast to an integer index.
                                if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), indexDataType) == true)
                                {
                                    // Emit the value retrieval's byte code.
                                    if (_currentPass == 1)
                                    {
                                        // Pop the index value into register 1.
                                        Instruction instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                                        new Operand(instruction, Register.Reserved1);

                                        // Cast index value to integer
                                        if (indexDataType.DataType != DataType.Int)
                                        {
                                            instruction = CreateInstruction(OpCode.CAST_INT, _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved1);
                                        }

                                        // Move the array's memory slot into reserved2 register.
                                        instruction = CreateInstruction(OpCode.MOV_MEMORY_INDEX, _currentScope, _currentToken);
                                        new Operand(instruction, Register.Reserved2);
                                        if (symbol.VariableType == VariableType.Constant || symbol.VariableType == VariableType.Global)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);

                                        // Push the array's data onto the stack indexed
                                        // by the register we just poped the index into.
                                        instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);

                                    }

                                    #region ++ / -- Parsing
                                    // Check if there is a increment (++) or decrement (--) operator following this value..
                                    if (LookAheadToken().ID == TokenID.OpIncrement)
                                    {
                                        // Read in increment token.
                                        NextToken();

                                        // Check the data types are valid with this operator.
                                        if (OperatorDataTypeValid(symbol.DataType, _currentToken.ID) == false)
                                            Error(ErrorCode.InvalidDataType, "Operator \"" + _currentToken.Ident + "\" can't be applied to data type \"" + symbol.DataType.ToString() + "\"", false, 0);

                                        // Make sure the symbol is not constant.
                                        if (symbol.IsConstant == true)
                                            Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                        // Increment the variable.
                                        if (_currentPass == 1)
                                        {
                                            // Take the assumtion that the values are still in the register from the previous code.
                                            Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.INC), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);
                                        }
                                    }
                                    else if (LookAheadToken().ID == TokenID.OpDecrement)
                                    {
                                        // Read in increment token.
                                        NextToken();

                                        // Check the data types are valid with this operator.
                                        if (OperatorDataTypeValid(symbol.DataType, _currentToken.ID) == false)
                                            Error(ErrorCode.InvalidDataType, "Operator \"" + _currentToken.Ident + "\" can't be applied to data type \"" + symbol.DataType.ToString() + "\"", false, 0);

                                        // Make sure the symbol is not constant.
                                        if (symbol.IsConstant == true)
                                            Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                        // Decrement the variable.
                                        if (_currentPass == 1)
                                        {
                                            // Take the assumtion that the values are still in the register from the previous code.
                                            Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.DEC), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);
                                        }
                                    }
                                    #endregion

                                }
                                else
                                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + indexDataType.ToString() + "\"", false, 0);

                            }

                            // Its not an array so parse it as a reqular variable.
                            else
                            {
                                // Push the variable's value onto stack.
                                if (_currentPass == 1)
                                {
                                    Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                    if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                        Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                    else
                                        Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                }

                                #region ++ / -- Parsing
                                // Check if there is a increment (++) or decrement (--) operator following this value..
                                if (LookAheadToken().ID == TokenID.OpIncrement)
                                {
                                    // Read in increment token.
                                    NextToken();

                                    // Check the data types are valid with this operator.
                                    if (OperatorDataTypeValid(symbol.DataType, _currentToken.ID) == false)
                                        Error(ErrorCode.InvalidDataType, "Operator \"" + _currentToken.Ident + "\" can't be applied to data type \"" + symbol.DataType.ToString() + "\"", false, 0);

                                    // Make sure the symbol is not constant.
                                    if (symbol.IsConstant == true)
                                        Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                    // Increment the variable.
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.INC), _currentScope, _currentToken);
                                        if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                    }
                                }
                                else if (LookAheadToken().ID == TokenID.OpDecrement)
                                {
                                    // Read in increment token.
                                    NextToken();

                                    // Check the data types are valid with this operator.
                                    if (OperatorDataTypeValid(symbol.DataType, _currentToken.ID) == false)
                                        Error(ErrorCode.InvalidDataType, "Operator \"" + _currentToken.Ident + "\" can't be applied to data type \"" + symbol.DataType.ToString() + "\"", false, 0);

                                    // Make sure the symbol is not constant.
                                    if (symbol.IsConstant == true)
                                        Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                    // Decrement the variable.
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.DEC), _currentScope, _currentToken);
                                        if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                    }
                                }
                                #endregion

                            }
                        }
                    }

                    // It look for opening parenthesis which would make it a function call.
                    else if (EndOfTokenStream() == false && LookAheadToken().ID == TokenID.CharOpenParenthesis)
                    {
                        #region Function calling

                        _tokenIndex = tokenIndex;
                        _currentToken = currentToken;

                        // Parse the function call and remember the return type.
                        DataTypeValue functionReturnType = ParseFunctionCall();

                        // Push the return value of the function onto the stack.
                        if (_currentPass == 1)
                        {
                            Instruction instruction = CreateInstruction(OpCodeByType(functionReturnType, OpCodeType.PUSH), _currentScope, _currentToken);
                            new Operand(instruction, Register.Return);
                        }

                        // Set the factors data type.
                        factorDataType = functionReturnType;

                        #endregion
                    }

                    // WTF! Is this?
                    else
                    {
                        Error(ErrorCode.UndeclaredVariable, "Encountered attempt to access an undeclared symbol \"" + symbolIdent + "\".", false, 1);
                    }
                    break;
                #endregion
                #region Sub expression
                case TokenID.CharOpenParenthesis:
                    factorDataType = ParseExpression();
                    ExpectToken(TokenID.CharCloseParenthesis);
                    break;
                #endregion
                default:
                    Error(ErrorCode.InvalidFactor, "Invalid factor.", false, 0);
                    break;
            }

            // Create instructions for unary operator if in second pass.
            if (unaryOpPending == true && _currentPass == 1)
            {
                // Check the data types are valid with this operator.
                if (OperatorDataTypeValid(factorDataType, unaryOpToken.ID) == false)
                    Error(ErrorCode.InvalidDataType, "Operator \"" + unaryOpToken.Ident + "\" can't be apply to data type \"" + factorDataType.ToString() + "\"");

                // Pop the value of this value out of the stack
                // and preform action on it.
                Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.POP), _currentScope, _currentToken);
                new Operand(instruction, Register.Arithmetic1);

                // Create instruction based on operation code.
                switch (unaryOpToken.ID)
                {
                    case TokenID.OpAdd: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.ABS), _currentScope, _currentToken); break;
                    case TokenID.OpSub: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.NEG), _currentScope, _currentToken); break;
                    case TokenID.OpLogicalNot: instruction = CreateInstruction(OpCode.LOGICAL_NOT, _currentScope, _currentToken); break;
                    case TokenID.OpBitwiseNot: instruction = CreateInstruction(OpCode.BIT_NOT_INT, _currentScope, _currentToken); break;
                    case TokenID.OpIncrement: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.INC), _currentScope, _currentToken); break;
                    case TokenID.OpDecrement: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.DEC), _currentScope, _currentToken); break;
                }
                new Operand(instruction, Register.Arithmetic1);

                // Push the value back onto the stack (as long as its not the logical not, which does that itself).
                if (unaryOpToken.ID != TokenID.OpLogicalNot)
                {
                    instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                }
            }

            // If a cast is pending then convert the result to the given type.
            if (castPending == true && factorDataType != castType)
            {
                if (_currentPass == 1)
                {
                    // Pop the result out of the stack.
                    Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);

                    // Cast it to the given type.
                    instruction = CreateInstruction(OpCodeByType(castType, OpCodeType.CAST), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);

                    // Push the value back onto the stack.
                    instruction = CreateInstruction(OpCodeByType(castType, OpCodeType.PUSH), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                }
                factorDataType = castType;
            }

            return factorDataType;
        }
        /// <summary>
        ///     Parses a member assignment.
        /// </summary>
        private void ParseMemberAssignment(string identifier, DataTypeValue returnDataType)
        {
            // Check we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                Error(ErrorCode.InvalidScope, "Assignments are only valid inside a function's or event's scope.", false, 0);

            #region Variable retrieving

            // If we are in pass 2 try and retrieve the variable.
            VariableSymbol variableSymbol = null;
            DataTypeValue dataType = returnDataType;
            if (_currentPass == 0)
            {
                variableSymbol = _memberScope.FindVariableSymbol(identifier, returnDataType) as VariableSymbol;
                if (variableSymbol == null)
                {
                    variableSymbol = new VariableSymbol(_memberScope);
                    variableSymbol.Identifier = identifier;
                    variableSymbol.DataType = returnDataType;
                    variableSymbol.VariableType = VariableType.Member;
                    if (variableSymbol.VariableType == VariableType.Constant)
                        Error(ErrorCode.IllegalAssignment, "Encountered attempt to assign to a constant variable \"" + identifier + "\".");
                }
            }
            else if (_currentPass == 1)
                variableSymbol = _memberScope.FindVariableSymbol(identifier, returnDataType) as VariableSymbol;

            #endregion
            #region Array index parsing

            // Check if we are assigning to an array.
            bool isArray = false;
            DataTypeValue indexDataType = null;
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                // Make sure variable is an array if we are in pass 2.
                if (_currentPass == 1 && variableSymbol.DataType.IsArray == false)
                    Error(ErrorCode.InvalidArrayIndex, "Non-array variables can not be indexed.");

                // As its an array and its index we can remove the array declaration from
                // the data type.
                dataType.IsArray = false;

                // Read in opening bracket and check expression is valid
                NextToken();
                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                    Error(ErrorCode.InvalidArrayIndex, "Array's must be indexed.", false, 0);

                // Read in expression and closing bracket.
                indexDataType = ParseExpression();
                ExpectToken(TokenID.CharCloseBracket);

                isArray = true;
            }
            #endregion
            #region Operator parsing

            // Check if the operator is a valid assignment operator.
            NextToken();
            if (_currentToken.ID != TokenID.OpAssign && _currentToken.ID != TokenID.OpAssignAdd &&
                _currentToken.ID != TokenID.OpAssignBitwiseAnd && _currentToken.ID != TokenID.OpAssignBitwiseNot &&
                _currentToken.ID != TokenID.OpAssignBitwiseOr && _currentToken.ID != TokenID.OpAssignBitwiseSHL &&
                _currentToken.ID != TokenID.OpAssignBitwiseSHR && _currentToken.ID != TokenID.OpAssignBitwiseXOr &&
                _currentToken.ID != TokenID.OpAssignDivide && _currentToken.ID != TokenID.OpAssignModulus &&
                _currentToken.ID != TokenID.OpAssignMultiply && _currentToken.ID != TokenID.OpAssignSub &&
                _currentToken.ID != TokenID.OpIncrement && _currentToken.ID != TokenID.OpDecrement)
                Error(ErrorCode.IllegalAssignmentOperator, "Encountered attempt to use an illegal assignment operator.");

            Token operatorToken = _currentToken;
            Instruction instruction = null;
            DataTypeValue expressionType = new DataTypeValue(DataType.Invalid, false, false);
            #endregion

            // Check the data types are valid with this operator.
            if (_currentPass == 1 && OperatorDataTypeValid(variableSymbol.DataType, operatorToken.ID) == false)
                Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + variableSymbol.DataType.ToString() + "\"");

            #region Value byte code emission and parsing

            // Read in expression if it is not a increment (++) or decrement (--) operator.
            if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
            {
                // Parse the expression.
                expressionType = ParseExpression();

                // Pop the expression into reserved register 3.
                if (_currentPass == 1)
                {
                    // Pop the value of into reserved register 3.
                    instruction = CreateInstruction(OpCodeByType(expressionType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Reserved3);

                    // Cast the value to a valid type.
                    if (dataType != expressionType)
                    {
                        instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.CAST), _currentScope, _currentToken);
                        new Operand(instruction, Register.Reserved3);
                    }
                }

                // If we are an array check that we have been indexed, unless we
                // are assigning null to it.
                if (_currentPass == 1 && variableSymbol.DataType.IsArray == true && isArray == false && expressionType.DataType != DataType.Null && expressionType.IsArray != true)
                    Error(ErrorCode.InvalidArrayIndex, "Arrays must be indexed.");
            }
            else
            {
                expressionType = new DataTypeValue(DataType.Int, false, false);
            }
            #endregion

            // Check we can cast to the expression result to the variables data type.
            if (_currentPass == 1 && CanImplicitlyCast(dataType, expressionType) == false)
                Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + dataType.ToString() + "\" and \"" + expressionType.ToString() + "\"");

            #region Array index byte code emission

            // If this is an array pop the index into reserved register 2.
            if (isArray == true && _currentPass == 1)
            {
                // Pop the index into reserved register 2.
                instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                new Operand(instruction, Register.Reserved2);
            }

            #endregion

            #region Assignment byte code emission

            // Create assignment byte code if we are in pass 2.
            if (_currentPass == 1)
            {
                // Pop the object into the member register.
                instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                new Operand(instruction, Register.Arithmetic1);

                // Call the GET_MEMBER opCode.
                if (returnDataType.IsArray)
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, variableSymbol);
                }
                else
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Arithmetic2);
                }

                switch (operatorToken.ID)
                {
                    case TokenID.OpAssign: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MOV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignAdd: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.ADD), _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseAnd: instruction = CreateInstruction(OpCode.BIT_AND_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseNot: instruction = CreateInstruction(OpCode.BIT_NOT_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseOr: instruction = CreateInstruction(OpCode.BIT_OR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHL: instruction = CreateInstruction(OpCode.BIT_SHL_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHR: instruction = CreateInstruction(OpCode.BIT_SHR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseXOr: instruction = CreateInstruction(OpCode.BIT_XOR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignDivide: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DIV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignModulus: instruction = CreateInstruction(OpCode.MOD_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignMultiply: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MUL), _currentScope, _currentToken); break;
                    case TokenID.OpAssignSub: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.SUB), _currentScope, _currentToken); break;
                    case TokenID.OpIncrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.INC), _currentScope, _currentToken); break;
                    case TokenID.OpDecrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DEC), _currentScope, _currentToken); break;
                }

                // Generate destination operands based on if variable is array.
                new Operand(instruction, Register.Return);

                // Generate the source operand if we are not dealing with the ++ and -- operators.
                if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
                    new Operand(instruction, Register.Reserved3);

                // Call the SET_MEMBER opCode.
                if (returnDataType.IsArray)
                {
                    instruction = CreateInstruction(OpCode.SET_MEMBER, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Return);
                }
                else
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Return);
                    new Operand(instruction, Register.Arithmetic2);
                }
            }

            #endregion
        }
        /// <summary>
        ///		Creates a new instance of this class with the given data.
        /// </summary>
        /// <param name="name">Identifier used inside a script to call this function</param>
        /// <param name="returnType">Data type that this function returns to the script</param>
        /// <param name="parameterTypes">Parameters that this function accepts</param>
        public NativeFunctionInfo(string name, string returnType, string parameterTypes)
        {
            _name = name;
            _returnType = DataTypeValue.FromMnemonic(returnType);

            if (parameterTypes != "")
            {
                string[] parameterTypesSplit = parameterTypes.Split(new Char[] { ',' });
                _parameterTypes = new DataTypeValue[parameterTypesSplit.Length];

                for (int i = 0; i < parameterTypesSplit.Length; i++)
                {
                    if (parameterTypesSplit[i].EndsWith("[]"))
                    {
                        _parameterTypes[i] = DataTypeValue.FromMnemonic(parameterTypesSplit[i].Substring(0, parameterTypesSplit[i].Length - 2));
                        _parameterTypes[i].IsArray = true;
                    }
                    else
                        _parameterTypes[i] = DataTypeValue.FromMnemonic(parameterTypesSplit[i]);
                }
            }
            else
                _parameterTypes = new DataTypeValue[0];
        }
        /// <summary>
        ///     Invokes a export function from a given script.
        /// </summary>
        /// <param name="symbol">Symbol of function to call.</param>
        /// <param name="toThread">Thread to call function.</param>
        /// <param name="fromThread">Thread to call function from.</param>
        /// <returns>Memory index of new array.</returns>
        public void InvokeExportFunction(FunctionSymbol symbol, ScriptThread toThread, ScriptThread fromThread)
        {
            // Can't invoke functions if debugging :S.
            if (_debugger != null && _debugger.AllowInvokedFunctions == false && toThread == this)
                return;

            // Find the functions parameter types.
            DataTypeValue[] parameterTypes = new DataTypeValue[symbol.ParameterCount];
            for (int i = 0; i < symbol.ParameterCount; i++)
                parameterTypes[i] = ((VariableSymbol)symbol.Symbols[i]).DataType;

            // Push any parameters we have been given.
            for (int i = 0; i < parameterTypes.Length; i++)
            {
                RuntimeValue parameter = fromThread._runtimeStack[(fromThread._runtimeStack.TopIndex - parameterTypes.Length) + i];
                parameter.DataType = parameterTypes[i];

                if (parameterTypes[i].IsArray == true)
                    toThread.PassParameterArray(CopyValueArrayFromThread(parameter, toThread, fromThread));
                else
                    toThread.PassParameter(CopyValueFromThread(parameter, toThread, fromThread));
            }

            // Call the function.
            toThread.InvokeFunction(symbol.Identifier, true, true);

            // Copy the return register.
            fromThread._registers[(int)Register.Return].DataType = symbol.ReturnType;
            if (symbol.ReturnType.IsArray == true)
                SetMemoryIndexValue(fromThread._registers[(int)Register.Return], CopyValueArrayFromThread(toThread._registers[(int)Register.Return], fromThread, toThread));
            else
                fromThread._registers[(int)Register.Return] = CopyValueFromThread(toThread._registers[(int)Register.Return], fromThread, toThread);
        }
        /// <summary>
        ///		Allocates a chunk of data on the heap.
        /// </summary>
        /// <param name="size">Size of data to allocate.</param>
        /// <param name="type">Data type the allocated memory should store.</param>
        /// <param name="value">Data type this heap is stored as (differs from the type paramter 'type' as it keeps track of arrays and references to)</param>
        /// <returns>Starting index of data on the heap.</returns>
        public int AllocateHeap(int size, RuntimeValueType type, DataTypeValue value)
        {
            // Check if there is any space on the stack.
            // Ignore the constant and global memory index as they are persistant.
            int allocatableIndex = 0, allocatableSize = 0;

            // First element is reserved to capture null-to-zero-cast-to-memory-index (XD) errors.
            for (int i = 1; i < _memoryHeap.Length; i++)
            {
                if (_memoryHeap[i] != null)
                {
                    allocatableSize = 0;
                    allocatableIndex = i + 1;
                    if (_memoryHeap[i].ValueType == RuntimeValueType.MemoryBoundry)
                    {
                        i += _memoryHeap[i].IntegerLiteral;
                        allocatableIndex = i + 1;
                        continue;
                    }
                    i++;
                    continue;
                }
                else
                    allocatableSize++;

                if (allocatableSize >= (size + 1))
                    break;
            }
            if (allocatableSize < (size + 1))// || (allocatableIndex + allocatableSize) >= _memoryHeap.Length)
            {
                CollectGarbage(); // Desperatly try and free some space :S.
                if (allocatableSize + _lastCollectionMemoryCount < (size + 1))
                {
                    // If all else fails, resize. Its better than crashing.
                    Array.Resize(ref _memoryHeap, _memoryHeap.Length * 2 < _memoryHeap.Length + size ? _memoryHeap.Length + size : _memoryHeap.Length * 2); // Double the size.
                    DebugLogger.WriteLog("Memory heap of script '"+_url.ToString()+"' was resized due to overflow.");
                    return AllocateHeap(size, type, value);
                }
                else
                    return AllocateHeap(size, type, value);
            }

            // Actually allocate the data.
            for (int i = allocatableIndex; i <= (allocatableIndex + allocatableSize); i++)
                _memoryHeap[i] = new RuntimeValue(type);

            // Set the first data block as a memory boundry so the GC can look after it.
            _memoryHeap[allocatableIndex].ValueType = RuntimeValueType.MemoryBoundry;
            _memoryHeap[allocatableIndex].IntegerLiteral = size;
            _memoryHeap[allocatableIndex].ReferenceCount = 0;
            _memoryHeap[allocatableIndex].DataType = value;

            return allocatableIndex + 1;
        }
 /// <summary>
 ///		Checks if a given parameter data type can be applied to this parameter.
 /// </summary>
 /// <param name="index">Index of parameter to check.</param>
 /// <returns>Boolean describing if the data type is valid.</returns>
 public bool CheckParameterTypeValid(int index, DataTypeValue value)
 {
     return (_parameterTypes[index] == value || value.DataType == DataType.Null);
 }
        /// <summary>
        ///     Copys the given processes data to this process.
        /// </summary>
        /// <param name="vm">Virtual machine this oricess us associated with.</param>
        /// <param name="process">Process to recieve data from.</param>
        public ScriptProcess(VirtualMachine vm, ScriptProcess process)
        {
            HighPreformanceTimer timer = new HighPreformanceTimer();

            // Store virtual machine for layer use.
            _virtualMachine = vm;

            // Load the given script into this process.
            process.CopyTo(this);

            // Create a default thread that should run this process.
            ScriptThread newThread = new ScriptThread(this);

            // Attach console commands / exported command to this thread.
            // TODO: What if they already exist?
            foreach (Symbol symbol in _symbolList)
                if (symbol != null && symbol.Type == SymbolType.Function)
                {
                    if (((FunctionSymbol)symbol).IsConsole == true)
                        new ScriptConsoleCommand((FunctionSymbol)symbol, newThread);
                    else if (((FunctionSymbol)symbol).IsExport == true)
                        new ScriptExportFunction((FunctionSymbol)symbol, newThread);
                    else if (((FunctionSymbol)symbol).IsImport == true)
                    {
                        // Find the functions parameter types.
                        DataTypeValue[] parameterTypes = new DataTypeValue[((FunctionSymbol)symbol).ParameterCount];
                        for (int i = 0; i < ((FunctionSymbol)symbol).ParameterCount; i++)
                            parameterTypes[(((FunctionSymbol)symbol).ParameterCount - 1) - i] = ((VariableSymbol)symbol.Symbols[i]).DataType;

                        ((FunctionSymbol)symbol).NativeFunction = _virtualMachine.FindNativeFunction(symbol.Identifier, parameterTypes);
                    }
                }
        }
 /// <summary>
 ///		Initializes a new instance of this class.
 /// </summary>
 /// <param name="identifier">Identifier used to call this function from a script.</param>
 /// <param name="nativeFunctionDelegate">Delegate of function you wish to be called when function is called from the script.</param>
 /// <param name="returnType">Data type that this function returns.</param>
 /// <param name="parameterTypes">Array of parameter data types this function uses.</param>
 public NativeFunction(string identifier, FunctionDelegate nativeFunctionDelegate, DataTypeValue returnType, DataTypeValue[] parameterTypes)
 {
     _identifier = identifier;
     _delegate = nativeFunctionDelegate;
     _returnType = returnType;
     _parameterTypes = parameterTypes;
 }
 /// <summary>
 ///		Nullifys all values in this instance.
 /// </summary>
 public void Clear()
 {
     _values.BooleanLiteral = false;
     _values.ByteLiteral = 0;
     _values.DoubleLiteral = 0;
     _values.FloatLiteral = 0;
     _values.IntegerLiteral = 0;
     _values.LongLiteral = 0;
     _memoryIndex = -1;
     _values.ShortLiteral = 0;
     _stringLiteralValue = "";
     _objectIndex = -1;
     _referenceCount = 0;
     _valueType = RuntimeValueType.Invalid;
     _dataType = null;
 }
        /// <summary>
        ///		Parses an variable assignment. A variable assignment basically just
        ///		places a given value into a previously declared variables memory space.
        ///		Syntax:
        ///			Identifier AssignmentOperator Expression
        /// </summary>
        private void ParseAssignment()
        {
            // Check we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                Error(ErrorCode.InvalidScope, "Assignments are only valid inside a function's or event's scope.", false, 0);

            // Retrieve the variables identifier and save it for later on.
            Symbol resolvedScope = ResolveMemberScope();
            string variableIdentifier = _currentToken.Ident;

            #region Variable retrieving
            // If we are in pass 2 try and retrieve the variable.
            VariableSymbol variableSymbol = null;
            DataTypeValue dataType = new DataTypeValue(DataType.Invalid, false, false);
            if (_currentPass == 1)
            {
                variableSymbol = resolvedScope.FindSymbol(variableIdentifier, SymbolType.Variable) as VariableSymbol;
                if (variableSymbol == null)
                    Error(ErrorCode.UndeclaredVariable, "Encountered attempt to assign a value to an undeclared variable \"" + variableIdentifier + "\".");
                if (variableSymbol.VariableType == VariableType.Constant)
                    Error(ErrorCode.IllegalAssignment, "Encountered attempt to assign to a constant variable \"" + variableIdentifier + "\".");
                variableSymbol.IsUsed = true;
                dataType.DataType = variableSymbol.DataType.DataType;
                dataType.IsArray = variableSymbol.DataType.IsArray;
                dataType.IsReference = variableSymbol.DataType.IsReference;
            }
            #endregion
            #region Array index parsing
            // Check if we are assigning to an array.
            bool isArray = false;
            DataTypeValue indexDataType = null;
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                // Make sure variable is an array if we are in pass 2.
                if (_currentPass == 1 && variableSymbol.IsArray == false)
                    Error(ErrorCode.InvalidArrayIndex, "Non-array variables can not be indexed.");

                // As its an array and its index we can remove the array declaration from
                // the data type.
                dataType.IsArray = false;

                // Read in opening bracket and check expression is valid
                NextToken();
                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                    Error(ErrorCode.InvalidArrayIndex, "Array's must be indexed.", false, 0);

                // Read in expression and closing bracket.
                indexDataType = ParseExpression();
                ExpectToken(TokenID.CharCloseBracket);

                // Check the expression is of a valid data type.
                if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), indexDataType) == false)
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + indexDataType.ToString() + "\"");

                isArray = true;
            }
            #endregion
            #region Operator parsing
            // Check if the operator is a valid assignment operator.
            NextToken();
            if (_currentToken.ID != TokenID.OpAssign && _currentToken.ID != TokenID.OpAssignAdd &&
                _currentToken.ID != TokenID.OpAssignBitwiseAnd && _currentToken.ID != TokenID.OpAssignBitwiseNot &&
                _currentToken.ID != TokenID.OpAssignBitwiseOr && _currentToken.ID != TokenID.OpAssignBitwiseSHL &&
                _currentToken.ID != TokenID.OpAssignBitwiseSHR && _currentToken.ID != TokenID.OpAssignBitwiseXOr &&
                _currentToken.ID != TokenID.OpAssignDivide && _currentToken.ID != TokenID.OpAssignModulus &&
                _currentToken.ID != TokenID.OpAssignMultiply && _currentToken.ID != TokenID.OpAssignSub &&
                _currentToken.ID != TokenID.OpIncrement && _currentToken.ID != TokenID.OpDecrement)
                Error(ErrorCode.IllegalAssignmentOperator, "Encountered attempt to use an illegal assignment operator.");

            Token operatorToken = _currentToken;
            Instruction instruction = null;
            DataTypeValue expressionType = new DataTypeValue(DataType.Invalid, false, false);
            #endregion

            // Check the data types are valid with this operator.
            if (_currentPass == 1 && OperatorDataTypeValid(variableSymbol.DataType, operatorToken.ID) == false)
                Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + variableSymbol.DataType.ToString() + "\"");

            #region Value byte code emission and parsing
            // Read in expression if it is not a increment (++) or decrement (--) operator.
            if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
            {
                // Parse the expression.
                expressionType = ParseExpression();

                // Pop the expression into reserved register 3.
                if (_currentPass == 1)
                {
                    // If we are an array deallocate our previous memory.
                    /*
                    if (variableSymbol.DataType.IsArray == true)
                    {
                        // Move the memory index into arith 2.
                        instruction = CreateInstruction(OpCode.MOV_MEMORY_INDEX, _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);
                        if (variableSymbol.VariableType == VariableType.Constant || variableSymbol.VariableType == VariableType.Global)
                            Operand.DirectMemoryOperand(instruction, variableSymbol.MemoryIndex);
                        else
                            Operand.DirectStackOperand(instruction, variableSymbol.StackIndex);

                        // Allocate enough space on the heap for the array.
                        instruction = CreateInstruction(OpCode.DEALLOCATE_HEAP, _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);
                    }
                    */

                    // Pop the value of into reserved register 3.
                    instruction = CreateInstruction(OpCodeByType(expressionType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Reserved3);

                    // Cast the value to a valid type.
                    if (dataType != expressionType)
                    {
                        instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.CAST), _currentScope, _currentToken);
                        new Operand(instruction, Register.Reserved3);
                    }
                }

                // If we are an array check that we have been indexed, unless we
                // are assigning null to it.
                if (_currentPass == 1 && variableSymbol.IsArray == true && isArray == false && expressionType.DataType != DataType.Null && expressionType.IsArray != true)
                    Error(ErrorCode.InvalidArrayIndex, "Arrays must be indexed.");
            }
            else
            {
                expressionType = new DataTypeValue(DataType.Int, false, false);
            }
            #endregion

            // Check we can cast to the expression result to the variables data type.
            if (_currentPass == 1 && CanImplicitlyCast(dataType, expressionType) == false)
                Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + variableSymbol.DataType.ToString() + "\" and \"" + expressionType.ToString() + "\"");

            #region Array index byte code emission
            // If this is an array pop the index into reserved register 2.
            if (isArray == true && _currentPass == 1)
            {
                // Pop the index into reserved regu=ister 2.
                instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                new Operand(instruction, Register.Reserved2);

                // Cast it to an integer index if its of another type.
                if (indexDataType != new DataTypeValue(DataType.Int, false, false))
                {
                    instruction = CreateInstruction(OpCode.CAST_INT, _currentScope, _currentToken);
                    new Operand(instruction, Register.Reserved2);
                }

                // Move the array memory slot into reserved register 1.
                instruction = CreateInstruction(OpCode.MOV_MEMORY_INDEX, _currentScope, _currentToken);
                new Operand(instruction, Register.Reserved1);
                if (variableSymbol.VariableType == VariableType.Constant || variableSymbol.VariableType == VariableType.Global)
                    Operand.DirectMemoryOperand(instruction, variableSymbol.MemoryIndex);
                else
                    Operand.DirectStackOperand(instruction, variableSymbol.StackIndex);
            }
            #endregion

            #region Assignment byte code emission
            // Create assignment byte code if we are in pass 2.
            if (_currentPass == 1)
            {
                switch (operatorToken.ID)
                {
                    case TokenID.OpAssign: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MOV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignAdd: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.ADD), _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseAnd: instruction = CreateInstruction(OpCode.BIT_AND_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseNot: instruction = CreateInstruction(OpCode.BIT_NOT_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseOr: instruction = CreateInstruction(OpCode.BIT_OR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHL: instruction = CreateInstruction(OpCode.BIT_SHL_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHR: instruction = CreateInstruction(OpCode.BIT_SHR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseXOr: instruction = CreateInstruction(OpCode.BIT_XOR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignDivide: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DIV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignModulus: instruction = CreateInstruction(OpCode.MOD_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignMultiply: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MUL), _currentScope, _currentToken); break;
                    case TokenID.OpAssignSub: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.SUB), _currentScope, _currentToken); break;
                    case TokenID.OpIncrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.INC), _currentScope, _currentToken); break;
                    case TokenID.OpDecrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DEC), _currentScope, _currentToken); break;
                }

                // Generate destination operands based on if variable is array.
                if (isArray == true)
                    Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved1, Register.Reserved2);
                else
                {
                    if (variableSymbol.VariableType == VariableType.Global || variableSymbol.VariableType == VariableType.Constant)
                        Operand.DirectMemoryOperand(instruction, variableSymbol.MemoryIndex);
                    else
                        Operand.DirectStackOperand(instruction, variableSymbol.StackIndex);
                }

                // Generate the source operand if we are not dealing with the ++ and -- operators.
                if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
                    new Operand(instruction, Register.Reserved3);

            }
            #endregion
        }
        /// <summary>
        ///		Runs this threads byte code.
        /// </summary>
        /// <param name="timeslice">Amount of time this thread is allowed to run for.</param>
        /// <returns>1 if the script has been forced to stop by a latency instruction, 2 if it has been forced to stop by a stack base marker or 3 if by an exit instruction.</returns>
        public int Run(int timeslice)
        {
            // Check that this thread is actually running.
            if (_isRunning == false) return 5;

            // Check the pause timer of this current thread.
            if (_isPaused == true)
            {
                if (_pauseTimer.DurationMillisecond <= _pauseLength) return 0;
                _isPaused = false;
            }

            // Check we are not at the end of this script, if we are then
            if (_instructionPointer >= _process.Instructions.Length) return 0;

            // If the debugger is running then we can't continue :S.
            if (_debugger != null && _debugger.RunScript == false)
                return 6;

            // Keep running until our timeslice runs out.
            int ticks = Environment.TickCount; // Don't use a high speed timer - To slow.
            //int secondsTimer = Environment.TickCount;
            //int instrCount = 0;
            //HighPreformanceTimer instructionTimer = new HighPreformanceTimer();
            //float[] opCodeTimes = new float[Enum.GetNames(typeof(OpCode)).Length];
            while (true)
            {
            #if !DEBUG
                try
                {
            #endif

                    //instructionTimer.Restart();
                    // Checks if this script is still in its timeslice.
                    if (timeslice != -1 && (Environment.TickCount - ticks) > timeslice &&
                        _priority != Priority.RealTime && _inAtom == false)
                        return 0;

                    // General exit stuff.
                    else if (_process == null || _callStack.Count == 0 || _instructionPointer >= _process.Instructions.Length || _isPaused == true || _isRunning == false || _isWaiting == true)
                        return 5;

                    // Debugger
                    else if (_debugger != null && _debugger.RunScript == false)
                        return 6;

                    // Retrieve's and execute's the next instruction in the list.
                    int originalPointer = _instructionPointer;

                    // Execute instruction and return result if neccessary.
                    RuntimeValue op1, op2, stack1;
                    RuntimeInstruction instruction = _process.Instructions[_instructionPointer];

                    //if (Environment.TickCount - secondsTimer > 10)
                    //{
                    //    secondsTimer = Environment.TickCount;
                    //if (_process.Url == "media\\scripts\\LTTP 2.0.fs")
                    //    System.Console.WriteLine(_process.Url+":"+(instrCount * 100) + " instrs/ps");
                    //    instrCount = 0;
                    //}
                    //else
                    //    instrCount++;

                    // This was originally a seperate function but to speed it up a bit it has been inlined.
                    #region Instruction Execution
                    switch (instruction.OpCode)
                    {
                        case OpCode.NOP:
                            break;

                        #region POP
                        case OpCode.POP_OBJECT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.Object;
                            stack1 = _runtimeStack.Pop();
                            SetObjectValue(op1, stack1.ObjectIndex);
                            if (stack1.ObjectIndex != -1) SetObjectValue(stack1, -1);
                            break;
                        case OpCode.POP_BOOL:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.BooleanLiteral;
                            op1.BooleanLiteral = _runtimeStack.Pop().BooleanLiteral;
                            break;
                        case OpCode.POP_BYTE:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.ByteLiteral;
                            op1.ByteLiteral = _runtimeStack.Pop().ByteLiteral;
                            break;
                        case OpCode.POP_INT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.IntegerLiteral;
                            op1.IntegerLiteral = _runtimeStack.Pop().IntegerLiteral;
                            break;
                        case OpCode.POP_SHORT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.ShortLiteral;
                            op1.ShortLiteral = _runtimeStack.Pop().ShortLiteral;
                            break;
                        case OpCode.POP_FLOAT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.FloatLiteral;
                            op1.FloatLiteral = _runtimeStack.Pop().FloatLiteral;
                            break;
                        case OpCode.POP_STRING:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.StringLiteral;
                            op1.StringLiteral = _runtimeStack.Pop().StringLiteral;
                            break;
                        case OpCode.POP_LONG:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.LongLiteral;
                            op1.LongLiteral = _runtimeStack.Pop().LongLiteral;
                            break;
                        case OpCode.POP_DOUBLE:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.DoubleLiteral;
                            op1.DoubleLiteral = _runtimeStack.Pop().DoubleLiteral;
                            break;
                        case OpCode.POP_MEMORY_INDEX:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.Invalid;
                            op2 = _runtimeStack.Pop();
                            // op1.MemoryIndex = op2.MemoryIndex;
                            op1.StackIndex = op2.StackIndex;
                            SetMemoryIndexValue(op1, op2.MemoryIndex);
                            if (op2.MemoryIndex != -1) SetMemoryIndexValue(op2, -1);
                            break;
                        case OpCode.POP_NULL:
                            _runtimeStack.Pop(); // Pop value of stack, we are not actually
                            // going to be using it so ignore it.
                            if (ResolveOperand(instruction, 0).ObjectIndex != -1) SetObjectValue(ResolveOperand(instruction, 0), -1);
                            else if (ResolveOperand(instruction, 0).MemoryIndex != -1) SetMemoryIndexValue(ResolveOperand(instruction, 0), -1);
                            ResolveOperand(instruction, 0).Clear(); // Nullify value.
                            break;
                        case OpCode.POP_DESTROY:
                            stack1 = _runtimeStack.Pop();
                            if (stack1.ObjectIndex != -1) SetObjectValue(stack1, -1);
                            else if (stack1.MemoryIndex != -1) SetMemoryIndexValue(stack1, -1);
                            _runtimeStack.Pop();
                            break;
                        #endregion
                        #region PUSH
                        case OpCode.PUSH_OBJECT:
                            SetObjectValue(_runtimeStack.PushEmpty(RuntimeValueType.Object), ResolveOperand(instruction, 0).ObjectIndex);
                            break;
                        case OpCode.PUSH_BOOL:
                            _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral).BooleanLiteral = ResolveOperand(instruction, 0).BooleanLiteral;
                            break;
                        case OpCode.PUSH_BYTE:
                            _runtimeStack.PushEmpty(RuntimeValueType.ByteLiteral).ByteLiteral = ResolveOperand(instruction, 0).ByteLiteral;
                            break;
                        case OpCode.PUSH_INT:
                            _runtimeStack.PushEmpty(RuntimeValueType.IntegerLiteral).IntegerLiteral = ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.PUSH_SHORT:
                            _runtimeStack.PushEmpty(RuntimeValueType.ShortLiteral).ShortLiteral = ResolveOperand(instruction, 0).ShortLiteral;
                            break;
                        case OpCode.PUSH_FLOAT:
                            _runtimeStack.PushEmpty(RuntimeValueType.FloatLiteral).FloatLiteral = ResolveOperand(instruction, 0).FloatLiteral;
                            break;
                        case OpCode.PUSH_STRING:
                            _runtimeStack.PushEmpty(RuntimeValueType.StringLiteral).StringLiteral = ResolveOperand(instruction, 0).StringLiteral;
                            break;
                        case OpCode.PUSH_LONG:
                            _runtimeStack.PushEmpty(RuntimeValueType.LongLiteral).LongLiteral = ResolveOperand(instruction, 0).LongLiteral;
                            break;
                        case OpCode.PUSH_DOUBLE:
                            _runtimeStack.PushEmpty(RuntimeValueType.DoubleLiteral).DoubleLiteral = ResolveOperand(instruction, 0).DoubleLiteral;
                            break;
                        case OpCode.PUSH_MEMORY_INDEX:
                            op1 = ResolveOperand(instruction, 0);
                            op2 = _runtimeStack.PushEmpty(RuntimeValueType.Invalid);
                            //op2.MemoryIndex = op1.MemoryIndex;
                            op2.StackIndex = op1.StackIndex;
                            SetMemoryIndexValue(op2, op1.MemoryIndex);
                            break;
                        case OpCode.PUSH_NULL:
                            _runtimeStack.PushEmpty(RuntimeValueType.Invalid).Clear();
                            break;
                        #endregion
                        #region CAST
                        // Value casting op codes.
                        case OpCode.CAST_NULL:
                            if (ResolveOperand(instruction, 0).ObjectIndex != -1) SetObjectValue(ResolveOperand(instruction, 0), -1);
                            else if (ResolveOperand(instruction, 0).MemoryIndex != -1) SetMemoryIndexValue(ResolveOperand(instruction, 0), -1);
                            ResolveOperand(instruction, 0).Clear();
                            break;
                        case OpCode.CAST_BOOL:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.BooleanLiteral = op1.ObjectIndex == 0 ? false : true; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.ByteLiteral: op1.BooleanLiteral = op1.ByteLiteral == 0 ? false : true; break;
                                case RuntimeValueType.DoubleLiteral: op1.BooleanLiteral = op1.DoubleLiteral == 0 ? false : true; break;
                                case RuntimeValueType.FloatLiteral: op1.BooleanLiteral = op1.FloatLiteral == 0 ? false : true; break;
                                case RuntimeValueType.IntegerLiteral: op1.BooleanLiteral = op1.IntegerLiteral == 0 ? false : true; break;
                                case RuntimeValueType.LongLiteral: op1.BooleanLiteral = op1.LongLiteral == 0 ? false : true; break;
                                case RuntimeValueType.ShortLiteral: op1.BooleanLiteral = op1.ShortLiteral == 0 ? false : true; break;
                                case RuntimeValueType.StringLiteral: op1.BooleanLiteral = (op1.StringLiteral == "1" || op1.StringLiteral.ToLower() == "true" ? true : false); break;
                            }
                            op1.ValueType = RuntimeValueType.BooleanLiteral;
                            break;
                        case OpCode.CAST_BYTE:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.ByteLiteral = (byte)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.ByteLiteral = byte.Parse(op1.BooleanLiteral.ToString()); break;
                                case RuntimeValueType.DoubleLiteral: op1.ByteLiteral = (byte)op1.DoubleLiteral; break;
                                case RuntimeValueType.FloatLiteral: op1.ByteLiteral = (byte)op1.FloatLiteral; break;
                                case RuntimeValueType.IntegerLiteral: op1.ByteLiteral = (byte)op1.IntegerLiteral; break;
                                case RuntimeValueType.LongLiteral: op1.ByteLiteral = (byte)op1.LongLiteral; break;
                                case RuntimeValueType.ShortLiteral: op1.ByteLiteral = (byte)op1.ShortLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.ByteLiteral = op1.StringLiteral == "" ? (byte)0 : (op1.StringLiteral.IndexOf('.') >= 0 ? (byte)float.Parse(op1.StringLiteral) : byte.Parse(op1.StringLiteral)); break;
                            }
                            op1.ValueType = RuntimeValueType.ByteLiteral;
                            break;
                        case OpCode.CAST_INT:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.IntegerLiteral = (int)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.IntegerLiteral = (op1.BooleanLiteral == true ? 1 : 0); break;
                                case RuntimeValueType.ByteLiteral: op1.IntegerLiteral = (int)op1.ByteLiteral; break;
                                case RuntimeValueType.DoubleLiteral: op1.IntegerLiteral = (int)op1.DoubleLiteral; break;
                                case RuntimeValueType.FloatLiteral: op1.IntegerLiteral = (int)op1.FloatLiteral; break;
                                case RuntimeValueType.LongLiteral: op1.IntegerLiteral = (int)op1.LongLiteral; break;
                                case RuntimeValueType.ShortLiteral: op1.IntegerLiteral = (int)op1.ShortLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.IntegerLiteral = op1.StringLiteral == "" ? 0 : (op1.StringLiteral.IndexOf('.') >= 0 ? (int)float.Parse(op1.StringLiteral) : int.Parse(op1.StringLiteral)); break;
                            }
                            op1.ValueType = RuntimeValueType.IntegerLiteral;
                            break;
                        case OpCode.CAST_SHORT:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.ShortLiteral = (short)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.ShortLiteral = (short)(op1.BooleanLiteral == true ? 1 : 0); break;
                                case RuntimeValueType.ByteLiteral: op1.ShortLiteral = (short)op1.ByteLiteral; break;
                                case RuntimeValueType.DoubleLiteral: op1.ShortLiteral = (short)op1.DoubleLiteral; break;
                                case RuntimeValueType.FloatLiteral: op1.ShortLiteral = (short)op1.FloatLiteral; break;
                                case RuntimeValueType.IntegerLiteral: op1.ShortLiteral = (short)op1.IntegerLiteral; break;
                                case RuntimeValueType.LongLiteral: op1.ShortLiteral = (short)op1.LongLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.ShortLiteral = op1.StringLiteral == "" ? (short)0 : (op1.StringLiteral.IndexOf('.') >= 0 ? (short)float.Parse(op1.StringLiteral) : short.Parse(op1.StringLiteral)); break;
                            }
                            op1.ValueType = RuntimeValueType.ShortLiteral;
                            break;
                        case OpCode.CAST_FLOAT:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.FloatLiteral: op1.FloatLiteral = (float)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.FloatLiteral = (op1.BooleanLiteral == true ? 1 : 0); break;
                                case RuntimeValueType.ByteLiteral: op1.FloatLiteral = (float)op1.ByteLiteral; break;
                                case RuntimeValueType.DoubleLiteral: op1.FloatLiteral = (float)op1.DoubleLiteral; break;
                                case RuntimeValueType.IntegerLiteral: op1.FloatLiteral = (float)op1.IntegerLiteral; break;
                                case RuntimeValueType.LongLiteral: op1.FloatLiteral = (float)op1.LongLiteral; break;
                                case RuntimeValueType.ShortLiteral: op1.FloatLiteral = (float)op1.ShortLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.FloatLiteral = op1.StringLiteral == "" ? 0 : float.Parse(op1.StringLiteral); break;
                            }
                            op1.ValueType = RuntimeValueType.FloatLiteral;
                            break;
                        case OpCode.CAST_DOUBLE:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.DoubleLiteral = (double)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.DoubleLiteral = (op1.BooleanLiteral == true ? 1 : 0); break;
                                case RuntimeValueType.ByteLiteral: op1.DoubleLiteral = (double)op1.ByteLiteral; break;
                                case RuntimeValueType.FloatLiteral: op1.DoubleLiteral = (double)op1.FloatLiteral; break;
                                case RuntimeValueType.IntegerLiteral: op1.DoubleLiteral = (double)op1.IntegerLiteral; break;
                                case RuntimeValueType.LongLiteral: op1.DoubleLiteral = (double)op1.LongLiteral; break;
                                case RuntimeValueType.ShortLiteral: op1.DoubleLiteral = (double)op1.ShortLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.DoubleLiteral = op1.StringLiteral == "" ? 0 : double.Parse(op1.StringLiteral); break;
                            }
                            op1.ValueType = RuntimeValueType.DoubleLiteral;
                            break;
                        case OpCode.CAST_LONG:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.LongLiteral = (long)op1.ObjectIndex; SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.LongLiteral = (op1.BooleanLiteral == true ? 1 : 0); break;
                                case RuntimeValueType.ByteLiteral: op1.LongLiteral = (long)op1.ByteLiteral; break;
                                case RuntimeValueType.DoubleLiteral: op1.LongLiteral = (long)op1.DoubleLiteral; break;
                                case RuntimeValueType.FloatLiteral: op1.LongLiteral = (long)op1.FloatLiteral; break;
                                case RuntimeValueType.IntegerLiteral: op1.LongLiteral = (long)op1.IntegerLiteral; break;
                                case RuntimeValueType.ShortLiteral: op1.LongLiteral = (long)op1.ShortLiteral; break;
                                case RuntimeValueType.StringLiteral: op1.LongLiteral = op1.StringLiteral == "" ? 0 : (op1.StringLiteral.IndexOf('.') >= 0 ? (long)float.Parse(op1.StringLiteral) : long.Parse(op1.StringLiteral)); break;
                            }
                            op1.ValueType = RuntimeValueType.LongLiteral;
                            break;
                        case OpCode.CAST_Object:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.BooleanLiteral: SetObjectValue(op1, (op1.BooleanLiteral == true ? 1 : 0)); break;
                                case RuntimeValueType.ByteLiteral: SetObjectValue(op1, op1.ByteLiteral); break;
                                case RuntimeValueType.DoubleLiteral: SetObjectValue(op1, (int)op1.DoubleLiteral); break;
                                case RuntimeValueType.FloatLiteral: SetObjectValue(op1, (int)op1.FloatLiteral); break;
                                case RuntimeValueType.IntegerLiteral: SetObjectValue(op1, op1.IntegerLiteral); break;
                                case RuntimeValueType.LongLiteral: SetObjectValue(op1, (int)op1.LongLiteral); break;
                                case RuntimeValueType.ShortLiteral: SetObjectValue(op1, op1.ShortLiteral); break;
                                case RuntimeValueType.StringLiteral: SetObjectValue(op1, (op1.StringLiteral != "" ? (op1.StringLiteral.IndexOf('.') >= 0 ? (int)float.Parse(op1.StringLiteral) : int.Parse(op1.StringLiteral)) : 0)); break;
                            }
                            op1.ValueType = RuntimeValueType.Object;
                            break;
                        case OpCode.CAST_STRING:
                            op1 = ResolveOperand(instruction, 0);
                            switch (op1.ValueType)
                            {
                                case RuntimeValueType.Object: op1.StringLiteral = op1.ObjectIndex.ToString(); SetObjectValue(op1, -1); break;
                                case RuntimeValueType.BooleanLiteral: op1.StringLiteral = (op1.BooleanLiteral == true ? "1" : "0"); break;
                                case RuntimeValueType.ByteLiteral: op1.StringLiteral = op1.ByteLiteral.ToString(); break;
                                case RuntimeValueType.DoubleLiteral: op1.StringLiteral = op1.DoubleLiteral.ToString(); break;
                                case RuntimeValueType.FloatLiteral: op1.StringLiteral = op1.FloatLiteral.ToString(); break;
                                case RuntimeValueType.IntegerLiteral: op1.StringLiteral = op1.IntegerLiteral.ToString(); break;
                                case RuntimeValueType.LongLiteral: op1.StringLiteral = op1.LongLiteral.ToString(); break;
                                case RuntimeValueType.ShortLiteral: op1.StringLiteral = op1.ShortLiteral.ToString(); break;
                            }
                            op1.ValueType = RuntimeValueType.StringLiteral;
                            break;
                        #endregion
                        #region MOV
                        // Arithmetic op codes.
                        case OpCode.MOV_BOOL:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.BooleanLiteral;
                            op1.BooleanLiteral = ResolveOperand(instruction, 1).BooleanLiteral;
                            break;
                        case OpCode.MOV_BYTE:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.ByteLiteral;
                            op1.ByteLiteral = ResolveOperand(instruction, 1).ByteLiteral;
                            break;
                        case OpCode.MOV_INT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.IntegerLiteral;
                            op1.IntegerLiteral = ResolveOperand(instruction, 1).IntegerLiteral;
                            break;
                        case OpCode.MOV_SHORT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.ShortLiteral;
                            op1.ShortLiteral = ResolveOperand(instruction, 1).ShortLiteral;
                            break;
                        case OpCode.MOV_FLOAT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.FloatLiteral;
                            op1.FloatLiteral = ResolveOperand(instruction, 1).FloatLiteral;
                            break;
                        case OpCode.MOV_DOUBLE:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.DoubleLiteral;
                            op1.DoubleLiteral = ResolveOperand(instruction, 1).DoubleLiteral;
                            break;
                        case OpCode.MOV_LONG:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.LongLiteral;
                            op1.LongLiteral = ResolveOperand(instruction, 1).LongLiteral;
                            break;
                        case OpCode.MOV_OBJECT:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.Object;
                            SetObjectValue(op1, ResolveOperand(instruction, 1).ObjectIndex);
                            break;
                        case OpCode.MOV_NULL:
                            if (ResolveOperand(instruction, 0).ObjectIndex != -1) SetObjectValue(ResolveOperand(instruction, 0), -1);
                            else if (ResolveOperand(instruction, 0).MemoryIndex != -1) SetMemoryIndexValue(ResolveOperand(instruction, 0), -1);
                            ResolveOperand(instruction, 0).Clear();
                            break;
                        case OpCode.MOV_STRING:
                            op1 = ResolveOperand(instruction, 0);
                            op1.ValueType = RuntimeValueType.StringLiteral;
                            op1.StringLiteral = ResolveOperand(instruction, 1).StringLiteral;
                            break;
                        case OpCode.MOV_MEMORY_INDEX:
                            op1 = ResolveOperand(instruction, 0);
                            op2 = ResolveOperand(instruction, 1);
                            //op1.MemoryIndex = op2.MemoryIndex;
                            op1.StackIndex = op2.StackIndex;
                            SetMemoryIndexValue(op1, op2.MemoryIndex);
                            break;
                        #endregion
                        #region MUL
                        case OpCode.MUL_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral *= ResolveOperand(instruction, 1).ByteLiteral;
                            break;
                        case OpCode.MUL_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral *= ResolveOperand(instruction, 1).IntegerLiteral;
                            break;
                        case OpCode.MUL_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral *= ResolveOperand(instruction, 1).ShortLiteral;
                            break;
                        case OpCode.MUL_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral *= ResolveOperand(instruction, 1).FloatLiteral;
                            break;
                        case OpCode.MUL_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral *= ResolveOperand(instruction, 1).DoubleLiteral;
                            break;
                        case OpCode.MUL_LONG:
                            ResolveOperand(instruction, 0).LongLiteral *= ResolveOperand(instruction, 1).LongLiteral;
                            break;
                        #endregion
                        #region DIV
                        case OpCode.DIV_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral /= ResolveOperand(instruction, 1).ByteLiteral;
                            break;
                        case OpCode.DIV_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral /= ResolveOperand(instruction, 1).IntegerLiteral;
                            break;
                        case OpCode.DIV_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral /= ResolveOperand(instruction, 1).ShortLiteral;
                            break;
                        case OpCode.DIV_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral /= ResolveOperand(instruction, 1).FloatLiteral;
                            break;
                        case OpCode.DIV_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral /= ResolveOperand(instruction, 1).DoubleLiteral;
                            break;
                        case OpCode.DIV_LONG:
                            ResolveOperand(instruction, 0).LongLiteral /= ResolveOperand(instruction, 1).LongLiteral;
                            break;
                        #endregion
                        #region ADD
                        case OpCode.ADD_STRING:
                            ResolveOperand(instruction, 0).StringLiteral += ResolveOperand(instruction, 1).StringLiteral;
                            break;
                        case OpCode.ADD_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral += ResolveOperand(instruction, 1).ByteLiteral;
                            break;
                        case OpCode.ADD_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral += ResolveOperand(instruction, 1).IntegerLiteral;
                            break;
                        case OpCode.ADD_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral += ResolveOperand(instruction, 1).ShortLiteral;
                            break;
                        case OpCode.ADD_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral += ResolveOperand(instruction, 1).FloatLiteral;
                            break;
                        case OpCode.ADD_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral += ResolveOperand(instruction, 1).DoubleLiteral;
                            break;
                        case OpCode.ADD_LONG:
                            ResolveOperand(instruction, 0).LongLiteral += ResolveOperand(instruction, 1).LongLiteral;
                            break;
                        #endregion
                        #region SUB
                        case OpCode.SUB_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral -= ResolveOperand(instruction, 1).ByteLiteral;
                            break;
                        case OpCode.SUB_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral -= ResolveOperand(instruction, 1).IntegerLiteral;
                            break;
                        case OpCode.SUB_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral -= ResolveOperand(instruction, 1).ShortLiteral;
                            break;
                        case OpCode.SUB_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral -= ResolveOperand(instruction, 1).FloatLiteral;
                            break;
                        case OpCode.SUB_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral -= ResolveOperand(instruction, 1).DoubleLiteral;
                            break;
                        case OpCode.SUB_LONG:
                            ResolveOperand(instruction, 0).LongLiteral -= ResolveOperand(instruction, 1).LongLiteral;
                            break;
                        #endregion
                        #region INC
                        case OpCode.INC_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral++;
                            break;
                        case OpCode.INC_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral++;
                            break;
                        case OpCode.INC_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral++;
                            break;
                        case OpCode.INC_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral++;
                            break;
                        case OpCode.INC_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral++;
                            break;
                        case OpCode.INC_LONG:
                            ResolveOperand(instruction, 0).LongLiteral++;
                            break;
                        #endregion
                        #region DEC
                        case OpCode.DEC_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral--;
                            break;
                        case OpCode.DEC_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral--;
                            break;
                        case OpCode.DEC_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral--;
                            break;
                        case OpCode.DEC_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral--;
                            break;
                        case OpCode.DEC_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral--;
                            break;
                        case OpCode.DEC_LONG:
                            ResolveOperand(instruction, 0).LongLiteral--;
                            break;
                        #endregion
                        #region NEG
                        case OpCode.NEG_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral = (byte)(-(int)ResolveOperand(instruction, 0).ByteLiteral);
                            break;
                        case OpCode.NEG_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral = -ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.NEG_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral = (short)(-(int)ResolveOperand(instruction, 0).ShortLiteral);
                            break;
                        case OpCode.NEG_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral = -ResolveOperand(instruction, 0).FloatLiteral;
                            break;
                        case OpCode.NEG_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral = -ResolveOperand(instruction, 0).DoubleLiteral;
                            break;
                        case OpCode.NEG_LONG:
                            ResolveOperand(instruction, 0).LongLiteral = -ResolveOperand(instruction, 0).LongLiteral;
                            break;
                        #endregion
                        #region ABS
                        case OpCode.ABS_BYTE:
                            ResolveOperand(instruction, 0).ByteLiteral = (byte)(+(int)ResolveOperand(instruction, 0).ByteLiteral);
                            break;
                        case OpCode.ABS_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral = +ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.ABS_SHORT:
                            ResolveOperand(instruction, 0).ShortLiteral = (short)(-(int)ResolveOperand(instruction, 0).ShortLiteral);
                            break;
                        case OpCode.ABS_FLOAT:
                            ResolveOperand(instruction, 0).FloatLiteral = +ResolveOperand(instruction, 0).FloatLiteral;
                            break;
                        case OpCode.ABS_DOUBLE:
                            ResolveOperand(instruction, 0).DoubleLiteral = +ResolveOperand(instruction, 0).DoubleLiteral;
                            break;
                        case OpCode.ABS_LONG:
                            ResolveOperand(instruction, 0).LongLiteral = +ResolveOperand(instruction, 0).LongLiteral;
                            break;
                        #endregion
                        #region Bitwise Operations
                        case OpCode.BIT_OR_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral |= ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.BIT_AND_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral &= ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.BIT_XOR_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral ^= ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.BIT_NOT_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral = ~ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.BIT_SHL_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral <<= ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        case OpCode.BIT_SHR_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral >>= ResolveOperand(instruction, 0).IntegerLiteral;
                            break;
                        #endregion
                        #region Misc Operations
                        case OpCode.EXP_INT:
                            ResolveOperand(instruction, 0).IntegerLiteral = (int)Math.Pow(ResolveOperand(instruction, 0).IntegerLiteral, ResolveOperand(instruction, 1).IntegerLiteral);
                            break;
                        case OpCode.MOD_INT:
                            if (ResolveOperand(instruction, 0).IntegerLiteral != 0 && ResolveOperand(instruction, 1).IntegerLiteral != 0)
                                ResolveOperand(instruction, 0).IntegerLiteral %= ResolveOperand(instruction, 1).IntegerLiteral;
                            else
                                ResolveOperand(instruction, 0).IntegerLiteral = 0;
                            break;
                        #endregion
                        #region CMP
                        // Flow of control op codes.
                        case OpCode.CMP_NULL:
                            op1 = ResolveOperand(instruction, 0);
                            _registers[(int)Register.Compare].IntegerLiteral = (op1.IsNull() == true || ((op1.DataType.DataType == DataType.Object) && _process.ObjectHeap[op1.ObjectIndex] == null)) ? 1 : 0;
                            break;
                        case OpCode.CMP_Object:
                            RuntimeObject obj1 = ResolveOperand(instruction, 0).ObjectIndex == -1 ? null : _process.ObjectHeap[ResolveOperand(instruction, 0).ObjectIndex];
                            RuntimeObject obj2 = ResolveOperand(instruction, 1).ObjectIndex == -1 ? null : _process.ObjectHeap[ResolveOperand(instruction, 1).ObjectIndex];
                            if (obj1 as NativeObject != null && obj2 as NativeObject != null)
                                _registers[(int)Register.Compare].IntegerLiteral = (((NativeObject)obj1).Object == ((NativeObject)obj2).Object) ? 0 : 1;
                            else if (obj1 as NativeObject == null && obj2 as NativeObject == null)
                                _registers[(int)Register.Compare].IntegerLiteral = 0;
                            else
                                _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).ObjectIndex - ResolveOperand(instruction, 1).ObjectIndex);
                            break;
                        case OpCode.CMP_BOOL:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign((ResolveOperand(instruction, 0).BooleanLiteral == true ? 1 : 0) - (ResolveOperand(instruction, 1).BooleanLiteral == true ? 1 : 0));
                            break;
                        case OpCode.CMP_BYTE:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).ByteLiteral - ResolveOperand(instruction, 1).ByteLiteral);
                            break;
                        case OpCode.CMP_INT:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).IntegerLiteral - ResolveOperand(instruction, 1).IntegerLiteral);
                            break;
                        case OpCode.CMP_SHORT:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).ShortLiteral - ResolveOperand(instruction, 1).ShortLiteral);
                            break;
                        case OpCode.CMP_FLOAT:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).FloatLiteral - ResolveOperand(instruction, 1).FloatLiteral);
                            break;
                        case OpCode.CMP_STRING:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).StringLiteral.CompareTo(ResolveOperand(instruction, 1).StringLiteral));
                            break;
                        case OpCode.CMP_LONG:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).LongLiteral - ResolveOperand(instruction, 1).LongLiteral);
                            break;
                        case OpCode.CMP_DOUBLE:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).DoubleLiteral - ResolveOperand(instruction, 1).DoubleLiteral);
                            break;
                        case OpCode.CMP_MEMORY_INDEX:
                            _registers[(int)Register.Compare].IntegerLiteral = Math.Sign(ResolveOperand(instruction, 0).MemoryIndex - ResolveOperand(instruction, 1).MemoryIndex);
                            break;
                        #endregion
                        #region JMP

                        case OpCode.JMP_EQ:
                            if (_registers[(int)Register.Compare].IntegerLiteral == 0)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP_L:
                            if (_registers[(int)Register.Compare].IntegerLiteral == -1)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP_G:
                            if (_registers[(int)Register.Compare].IntegerLiteral == 1)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP_LE:
                            if (_registers[(int)Register.Compare].IntegerLiteral == -1 || _registers[(int)Register.Compare].IntegerLiteral == 0)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP_GE:
                            if (_registers[(int)Register.Compare].IntegerLiteral == 1 || _registers[(int)Register.Compare].IntegerLiteral == 0)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP_NE:
                            if (_registers[(int)Register.Compare].IntegerLiteral != 0)
                                _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        case OpCode.JMP:
                            _instructionPointer = ResolveOperand(instruction, 0).InstrIndex;
                            break;
                        #endregion
                        #region IS
                        case OpCode.IS_EQ:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral == 0);
                            break;
                        case OpCode.IS_L:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral == -1);
                            break;
                        case OpCode.IS_G:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral == 1);
                            break;
                        case OpCode.IS_LE:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral == -1 || _registers[(int)Register.Compare].IntegerLiteral == 0);
                            break;
                        case OpCode.IS_GE:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral == 1 || _registers[(int)Register.Compare].IntegerLiteral == 0);
                            break;
                        case OpCode.IS_NE:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (_registers[(int)Register.Compare].IntegerLiteral != 0);
                            break;
                        #endregion
                        #region Logical Operations
                        case OpCode.LOGICAL_AND:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (ResolveOperand(instruction, 0).BooleanLiteral && ResolveOperand(instruction, 1).BooleanLiteral);
                            break;
                        case OpCode.LOGICAL_OR:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = (ResolveOperand(instruction, 0).BooleanLiteral || ResolveOperand(instruction, 1).BooleanLiteral);
                            break;
                        case OpCode.LOGICAL_NOT:
                            stack1 = _runtimeStack.PushEmpty(RuntimeValueType.BooleanLiteral);
                            stack1.BooleanLiteral = !ResolveOperand(instruction, 0).BooleanLiteral;
                            break;
                        #endregion
                        #region Stack Frame Manipulation
                        case OpCode.CALL:

                            // Increase instruction following this call so we don't
                            // end up going round is circles when this call returns.
                            _instructionPointer++;
                            CallFunction(ResolveOperand(instruction, 0).Symbol as FunctionSymbol, false);
                            break;

                        case OpCode.RETURN:

                            // Find the function index and throw corruption error if its not there.
                            RuntimeValue functionValue = _runtimeStack.Pop();
                            if (functionValue.ValueType != RuntimeValueType.StackFrameIndex && functionValue.ValueType != RuntimeValueType.StackBaseMarker)
                            {
                                // Ahh hell, lets try and recover.
            #if DEBUG
                                Error("Stack has been corrupted.");
            #else
                                while (functionValue.ValueType != RuntimeValueType.StackFrameIndex && functionValue.ValueType != RuntimeValueType.StackBaseMarker)
                                {
                                    if (_runtimeStack.TopIndex == 0)
                                    {
                                        Error("Stack has been corrupted.");
                                        break;
                                    }
                                    functionValue = _runtimeStack.Pop();
                                }

            #endif
                            }

                            // Find the parameter count and local data size.
                            int parameterCount = 0, localDataSize = 0;
                            if (functionValue.Symbol.Type == SymbolType.Function)
                            {
                                parameterCount = ((FunctionSymbol)functionValue.Symbol).ParameterCount;
                                localDataSize = ((FunctionSymbol)functionValue.Symbol).LocalDataSize;
                            }

                            // Find the return value stack entry and throw corruption error if its not there.
                            RuntimeValue returnAddressValue = _runtimeStack[_runtimeStack.TopIndex - (localDataSize + 1)];
                            if (returnAddressValue.ValueType != RuntimeValueType.ReturnAddress)
                                Error("Stack has been corrupted.");

                            // Reduce the reference count of any local varaibles.
                            DataTypeValue[] parameterTypes = new DataTypeValue[((FunctionSymbol)functionValue.Symbol).ParameterCount];
                            for (int i = 0; i < ((FunctionSymbol)functionValue.Symbol).ParameterCount; i++)
                                parameterTypes[(((FunctionSymbol)functionValue.Symbol).ParameterCount - 1) - i] = ((VariableSymbol)((FunctionSymbol)functionValue.Symbol).Symbols[i]).DataType;

                            // Remove reference counts for parameters.
                            //for (int i = 0; i < parameterCount; i++)
                            //{
                            //    RuntimeValue parameter = _runtimeStack[(_runtimeStack.TopIndex - (parameterCount + 1)) + i];
                            //   if (parameterTypes[i].DataType == DataType.Object && parameter.ObjectIndex != -1 && _process.ObjectHeap[parameter.ObjectIndex] != null)
                            //    {
                            //        _process.ObjectHeap[parameter.ObjectIndex].ReferenceCount--; // DIE!
                            //    }
                            //}

                            // Remove reference counts for local variables.
                            //foreach (Symbol symbol in functionValue.Symbol.Symbols)
                            //{
                            //    if (!(symbol is VariableSymbol) || ((VariableSymbol)symbol).VariableType != VariableType.Local) continue;
                            //    RuntimeValue local = GetRuntimeValueLocal(symbol.Identifier);
                            //    if (((VariableSymbol)symbol).DataType.DataType == DataType.Object && local.ObjectIndex != -1 && _process.ObjectHeap[local.ObjectIndex] != null)
                            //        _process.ObjectHeap[local.ObjectIndex].ReferenceCount--; // DIE!
                            //}

                            // Pop the functions stack frame.
                            //_runtimeStack.PopFrame(parameterCount + localDataSize + 1);
                            for (int i = 0; i < (parameterCount + localDataSize + 1); i++)
                            {
                                RuntimeValue stack = _runtimeStack.Pop();

                                if (stack.ObjectIndex != -1) SetObjectValue(stack, -1);
                                else if (stack.MemoryIndex != -1) SetMemoryIndexValue(stack, -1);
                            }

                            // Restore the previous stack.
                            _runtimeStack.FrameIndex = functionValue.InstrIndex;

                            // Jump to the return address.
                            _instructionPointer = returnAddressValue.InstrIndex;

                            //if (_process.Url == "media\\scripts\\LTTP 2.0.fs" && _callStack.Peek().ToString().ToLower() == "onrender")
                            //{
                            //    System.Console.WriteLine("\n\n--- OnRender Statistics ---");
                            //    for (int i = 0; i < opCodeTimes.Length; i++)
                            //        System.Console.WriteLine("Time spent on " + ((OpCode)i) + " = " + opCodeTimes[i] + " ms");
                            //}

                            // Pop this function off the call stack.
                            _callStack.Pop();

                            // If its a stack base marker make sure we exit the loop at the end.
                            if (functionValue.ValueType == RuntimeValueType.StackBaseMarker)
                                return 2;

                            // Out of things to run?
                            if (_callStack.Count == 0)
                                return 5;

                            break;
                        #endregion
                        #region Execution

                        // Execution related op codes.
                        case OpCode.EXIT:
                            _isRunning = false;
                            _instructionPointer++;
                            return 3;

                        case OpCode.PAUSE:
                            _isPaused = true;
                            _pauseLength = ResolveOperand(instruction, 0).IntegerLiteral;
                            _pauseTimer.Restart();
                            _instructionPointer++;
                            return 0;

                        case OpCode.GOTO_STATE:
                            _process.ChangeState(ResolveOperand(instruction, 0).Symbol as StateSymbol);
                            break;
                        //return 4;

                        #endregion
                        #region Memory Allocation

                        case OpCode.ALLOCATE_HEAP_NULL:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.Invalid, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_BOOL:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.BooleanLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_BYTE:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.ByteLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_INT:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.IntegerLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_SHORT:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.ShortLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_FLOAT:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.FloatLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_DOUBLE:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.DoubleLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_LONG:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.LongLiteral, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_Object:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.Object, null));
                            break;
                        case OpCode.ALLOCATE_HEAP_STRING:
                            SetMemoryIndexValue(ResolveOperand(instruction, 1), _process.AllocateHeap(ResolveOperand(instruction, 0).IntegerLiteral, RuntimeValueType.StringLiteral, null));
                            break;
                        case OpCode.DEALLOCATE_HEAP:
                            op1 = ResolveOperand(instruction, 0);
                            _process.MemoryHeap[op1.MemoryIndex - 1].ReferenceCount = 0;
                            break;

                        #endregion
                        #region Debug

                        // Debug op codes.
                        case OpCode.BREAKPOINT:
                            if (_debugger == null)
                                ShowDebugger();
                            else if (_debugger.NotifyOnBreakPoint == true)
                                _debugger.NotifyOfBreakPoint();
                            break;

                        // These are for the debugger. We can ignore them :P.
                        case OpCode.ENTER_STATEMENT:
                            if (_debugger != null && _debugger.NotifyOnEnter == true)
                                _debugger.NotifyOfEntry();
                            break;

                        case OpCode.EXIT_STATEMENT:
                            if (_debugger != null && _debugger.NotifyOnExit == true)
                                _debugger.NotifyOfExit();
                            break;

                        #endregion
                        #region Thread syncronization
                        case OpCode.LOCK:
                            if (instruction.Locked == true)
                                return 1; // Return and don't increment instruction pointer.
                            else
                            {
                                instruction.Locked = true;
                                _lockInstruction = instruction;
                            }
                            break;
                        case OpCode.UNLOCK:
                            _lockInstruction.Locked = false;
                            break;
                        case OpCode.ENTER_ATOM:
                            _previousInAtom = _inAtom;
                            _inAtom = true;
                            break;
                        case OpCode.LEAVE_ATOM:
                            _inAtom = _previousInAtom;
                            break;
                        #endregion
                        #region Member Modification
                        case OpCode.CALL_METHOD: // Object, Symbol
                            {
                                // Grab the object we are invoked a method off.
                                RuntimeValue objValue = ResolveOperand(instruction, 0);
                                if (objValue.ObjectIndex == -1) Error("Attempt to call method of null object.");
                                RuntimeObject obj = _process.ObjectHeap[objValue.ObjectIndex];

                                // Grab the function.
                                FunctionSymbol symbol = ResolveOperand(instruction, 1).Symbol as FunctionSymbol;

                                // Clean out the return register and push this function onto the callstack.
                                _callStack.Push(symbol);
                                _registers[(int)Register.Return].Clear();

                                // Invoke the method.
                                if (obj.InvokeMethod(this, symbol) == false)
                                    Error("An error occured while attempting to call a objects method '"+symbol.ToString()+"'. The method may not exist or may not be public.");

                                // Pop of this functions parameters.
                                for (int i = 0; i < symbol.ParameterCount; i++)
                                    _runtimeStack.Pop();

                                // Pop this value off the call stack.
                                _callStack.Pop();

                                break;
                            }
                        case OpCode.SET_MEMBER: // Object, symbol, value
                            {
                                // Grab the object we are invoked a method off.
                                RuntimeValue objValue = ResolveOperand(instruction, 0);
                                if (objValue.ObjectIndex == -1) Error("Attempt to set member of null object.");
                                RuntimeObject obj = _process.ObjectHeap[objValue.ObjectIndex];

                                // Grab the variable.
                                VariableSymbol symbol = ResolveOperand(instruction, 1).Symbol as VariableSymbol;

                                // Invoke the method.
                                if (obj.SetMember(this, symbol, ResolveOperand(instruction, 2)) == false)
                                    Error("An error occured while attempting to set an objects member. The member may not exist or may not be public.");

                                break;
                            }
                        case OpCode.SET_MEMBER_INDEXED: // Object, symbol, value, index
                            {
                                // Grab the object we are invoked a method off.
                                RuntimeValue objValue = ResolveOperand(instruction, 0);
                                if (objValue.ObjectIndex == -1) Error("Attempt to set member of null object.");
                                RuntimeObject obj = _process.ObjectHeap[objValue.ObjectIndex];

                                // Grab the variable.
                                VariableSymbol symbol = ResolveOperand(instruction, 1).Symbol as VariableSymbol;

                                // Invoke the method.
                                if (obj.SetMember(this, symbol, ResolveOperand(instruction, 2), ResolveOperand(instruction, 3)) == false)
                                    Error("An error occured while attempting to set an objects member. The member may not exist or may not be public.");

                                break;
                            }
                        case OpCode.GET_MEMBER: // Object, symbol
                            {
                                // Grab the object we are invoked a method off.
                                RuntimeValue objValue = ResolveOperand(instruction, 0);
                                if (objValue.ObjectIndex == -1) Error("Attempt to set member of null object.");
                                RuntimeObject obj = _process.ObjectHeap[objValue.ObjectIndex];

                                // Grab the variable.
                                VariableSymbol symbol = ResolveOperand(instruction, 1).Symbol as VariableSymbol;

                                // Clean out the return register.
                                _registers[(int)Register.Return].Clear();

                                // Invoke the method.
                                if (obj.SetMember(this, symbol, ResolveOperand(instruction, 2)) == false)
                                    Error("An error occured while attempting to get an objects member. The member may not exist or may not be public.");

                                break;
                            }
                        case OpCode.GET_MEMBER_INDEXED: // Object, symbol, index
                            {
                                // Grab the object we are invoked a method off.
                                RuntimeValue objValue = ResolveOperand(instruction, 0);
                                if (objValue.ObjectIndex == -1) Error("Attempt to set member of null object.");
                                RuntimeObject obj = _process.ObjectHeap[objValue.ObjectIndex];

                                // Grab the variable.
                                VariableSymbol symbol = ResolveOperand(instruction, 1).Symbol as VariableSymbol;

                                // Clean out the return register.
                                _registers[(int)Register.Return].Clear();

                                // Invoke the method.
                                if (obj.SetMember(this, symbol, ResolveOperand(instruction, 2), ResolveOperand(instruction, 3)) == false)
                                    Error("An error occured while attempting to get an objects member. The member may not exist or may not be public.");

                                break;
                            }
                        #endregion

                        // 'ello, 'ello. What goin' on 'ere then.
                        default:
                            Error("Virtual Machine encountered an invalid operation code ("+instruction.OpCode.ToString()+").");
                            break;
                    }
                    #endregion

                    // Move onto next instruction if this instruction has not progressed the instruction pointer.
                    if (_instructionPointer == originalPointer) _instructionPointer++;

                    //opCodeTimes[(int)instruction.OpCode] += (float)instructionTimer.DurationMillisecond;
                    //if (_process.Url == "media\\scripts\\LTTP 2.0.fs")
                    //    System.Console.WriteLine(instruction.OpCode.ToString() + " executed in " + instructionTimer.DurationMillisecond + "ms");

                    _instructionsExecuted++;
            #if !DEBUG
                }
                catch (Exception e)
                {
                    Error(e.Message);
                }
            #endif
            }
        }
        /// <summary>
        ///		Parses a top level expression. The top level is responsible for parsing 
        ///		any sub expressions and logical operators.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseExpression()
        {
            // Parse the left hand sub expression.
            DataTypeValue subDataType1 = ParseSubExpression();

            // Parse any subsequent sub expressions that are seperated
            // by logical operators.
            while (true)
            {
                // Check that the next token is logical or relational.
                Token operatorToken = LookAheadToken();
                if (operatorToken.IsLogical == false)
                    break;
                NextToken();

                // Parse the right hand sub expression.
                DataTypeValue subDataType2 = ParseSubExpression();

                // Check the new data type can be cast to the main data type
                if (CanImplicitlyCast(subDataType1, subDataType2) == true)
                {

                    // Check the data types are valid with this operator.
                    if (OperatorDataTypeValid(subDataType1, operatorToken.ID) == false)
                        Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + subDataType1.ToString() + "\"", false, 1);

                    // We only want to emit byte code on the second pass.
                    if (_currentPass == 1)
                    {

                        // Pop the result of the second sub expression into arithmetic
                        // register 1.
                        Instruction instruction = CreateInstruction(OpCodeByType(subDataType2, OpCodeType.POP), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);

                        // Pop the result of the first sub expression into arithmetic
                        // register 2.
                        instruction = CreateInstruction(OpCodeByType(subDataType1, OpCodeType.POP), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic1);

                        #region Logical Byte Code Emiting

                        // Create operation code based on operator.
                        // Logical instructions only take boolean values
                        // so there is no need to cast the values here.
                        switch (operatorToken.ID)
                        {
                            case TokenID.OpLogicalAnd:
                                instruction = CreateInstruction(OpCode.LOGICAL_AND, _currentScope, _currentToken);
                                new Operand(instruction, Register.Arithmetic1);
                                new Operand(instruction, Register.Arithmetic2);
                                break;
                            case TokenID.OpLogicalOr:
                                instruction = CreateInstruction(OpCode.LOGICAL_OR, _currentScope, _currentToken);
                                new Operand(instruction, Register.Arithmetic1);
                                new Operand(instruction, Register.Arithmetic2);
                                break;
                        }

                        #endregion
                    }

                    // Data type is now boolean due to the comparison operators.
                    subDataType1 = new DataTypeValue(DataType.Bool, false, false);

                }
                else
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + subDataType1.ToString() + "\" and \"" + subDataType2.ToString() + "\"", false, 1);

            }

            return subDataType1;
        }
        /// <summary>
        ///		Executes a script or native function.
        /// </summary>
        /// <param name="symbol">Symbol of function to call.</param>
        /// <param name="ignoreThread">If set and this function is a thread spawner a new thread will not be created.</param>
        private void CallFunction(FunctionSymbol symbol, bool ignoreThread)
        {
            // Can't call if debugging :S.
            if (_debugger != null && _debugger.RunScript == false)
                return;

            // Push this function onto the call stack.
            _callStack.Push(symbol);
            _registers[(int)Register.Return].Clear();
            _callingFunction = symbol;

            if (symbol.IsImport == true)
            {
                // Find and call native function.
                if (_process.VirtualMachine != null)
                {
                    DataTypeValue[] parameterTypes = null;
                    NativeFunction function = symbol.NativeFunction;
                    if (function == null)
                    {
                        // Find the functions parameter types.
                        parameterTypes = new DataTypeValue[symbol.ParameterCount];
                        for (int i = 0; i < symbol.ParameterCount; i++)
                            parameterTypes[(symbol.ParameterCount - 1) - i] = ((VariableSymbol)symbol.Symbols[i]).DataType;

                        // Find native function
                        function = _process.VirtualMachine.FindNativeFunction(symbol.Identifier, parameterTypes);
                        symbol.NativeFunction = function;
                    }

                    if (function != null)
                    {
            #if !DEBUG
                        try
                        {

            #endif
                            function.Delegate(this);
            #if !DEBUG
                        }
                        catch (Exception e)
                        {
                            Error(e.ToString());
                        }
            #endif
                    }

                    // Ok so its not a native one, lets check the script exports.
                    else
                    {
                        ScriptExportFunction callFunction = (ScriptExportFunction)ScriptExportFunction.FunctionHashTable[symbol.ToString().ToLower()];

                        /*
                        foreach (ScriptExportFunction exportFunction in ScriptExportFunction.FunctionList)
                        {
                            if (exportFunction.Symbol.Identifier.ToLower() != symbol.Identifier.ToLower()) continue;
                            if (exportFunction.Symbol.ParameterCount != parameterTypes.Length) continue;

                            bool paramsValid = true;
                            for (int i = 0; i < parameterTypes.Length; i++)
                                if (exportFunction.Symbol.CheckParameterTypeValid(i, parameterTypes[i]) == false)
                                    paramsValid = false;

                            if (paramsValid == false) continue;

                            callFunction = exportFunction;
                            break;
                        }
                        */

                        if (callFunction != null)
                        {
                            InvokeExportFunction(callFunction.Symbol, callFunction.Thread, this);
                        }
                        else
                        {
                            Error("Attempt to call unknown function '" + symbol.ToString() + "'");
                        }
                    }
                }

                // Pop of this functions parameters.
                for (int i = 0; i < symbol.ParameterCount; i++)
                {
                    RuntimeValue stack = _runtimeStack.Pop();

                    if (stack.ObjectIndex != -1) SetObjectValue(stack, -1);
                    else if (stack.MemoryIndex != -1) SetMemoryIndexValue(stack, -1);
                }

                // Pop this value off the call stack.
                _callStack.Pop();
            }
            else
            {
                if (symbol.IsThreadSpawner == true && ignoreThread == false)
                    SpawnThread(symbol);
                else
                {
                    int oldFrameIndex = _runtimeStack.FrameIndex;

                    // Push the return address which is the current instruction.
                    RuntimeValue returnAddress = _runtimeStack.PushEmpty(RuntimeValueType.ReturnAddress);
                    returnAddress.InstrIndex = _instructionPointer;

                    // Pushs this function stack frame onto stack.
                    _runtimeStack.PushFrame(symbol.LocalDataSize + 1);

                    // Place the function and old stack index into value
                    // and push it onto stack.
                    RuntimeValue stackValue = _runtimeStack.Peek();
                    stackValue.ValueType = RuntimeValueType.StackFrameIndex;
                    stackValue.Symbol = symbol;
                    stackValue.InstrIndex = oldFrameIndex;

                    // Jump to entry point of this function.
                    _instructionPointer = symbol.EntryPoint;

                    // Force this script into 'running' mode if its been stopped.
                    _isRunning = true;
                }
            }
        }
        /// <summary>
        ///		Parses a function declaration. A function is a way of isolating code that you want
        ///		to be able to call multiple times without rewriting it each time.
        ///		Syntax:
        ///			ReturnType Identifier "(" { Identifier ["=" Expression] [ "," ] } ")" Statement
        /// </summary>
        private void ParseFunction()
        {
            // Make sure we are in a state's scope.
            if (_currentToken.ID == TokenID.KeywordEvent &&
                _currentScope.Type != SymbolType.State)
                Error(ErrorCode.InvalidScope, "Events can only be declared within a state block.", false, 0);

            // Make sure we are in the global scopes as functions can't
            // be declared anywhere else.
            if (_currentScope.Type != SymbolType.State &&
                _currentScope.Type != SymbolType.Function &&
                _currentScope.Type != SymbolType.Namespace)
                Error(ErrorCode.InvalidScope, "Functions can only be declared in a function's, state's or event's scope.", false, 0);

            // Read in each flag.
            bool isThread = false;
            bool isEvent = false;
            bool isConsole = false;
            bool isExport = false;
            bool isImport = false;
            SymbolAccessModifier modifier = SymbolAccessModifier.Private;
            bool gotModifier = false;
            while (_currentToken.IsDataType == false && EndOfTokenStream() != true)
            {
                switch (_currentToken.ID)
                {
                    case TokenID.KeywordThread:
                        if (isThread == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isThread = true;
                        break;
                    case TokenID.KeywordEvent:
                        if (isEvent == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isEvent = true;
                        break;
                    case TokenID.KeywordConsole:
                        if (isConsole == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isConsole = true;
                        break;
                    case TokenID.KeywordImport:
                        if (isImport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isImport = true;
                        break;
                    case TokenID.KeywordExport:
                        if (isExport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isExport = true;
                        break;
                    case TokenID.KeywordPublic:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Public;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordPrivate:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Private;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordProtected:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Protected;
                        gotModifier = true;
                        break;
                }
                NextToken();
            }
            if (isEvent == true && (isThread == true || isExport == true || isImport == true || isConsole == true))
                Error(ErrorCode.InvalidFlag, "Events can't be declared as native, threaded, exported, imported or console.");

            // Store the return type for later.
            DataTypeValue returnDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);
            if (returnDataType.DataType == DataType.Invalid)
                Error(ErrorCode.InvalidDataType, "Functions can't be declared as \"" + _currentToken.Ident + "\".", false, 0);

            // Check for an array reference
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                NextToken();
                returnDataType.IsArray = true;
                ExpectToken(TokenID.CharCloseBracket);
            }

            // Read in the functions identifier and store it
            // for layer use.
            ExpectToken(TokenID.TypeIdentifier);
            string functionIdentifier = _currentToken.Ident;

            // Read in the opening parenthesis used to define the paremeter list.
            ExpectToken(TokenID.CharOpenParenthesis);

            // Read in each paremeter.
            ArrayList functionParameterMask = new ArrayList();
            int parameterCount = 0;
            ArrayList paramList = new ArrayList();
            if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
            {

                // Read in each parameter
                while (true)
                {

                    // Check if there is a constant keyword before this variable.
                    bool paramIsConst = false;
                    if (LookAheadToken().ID == TokenID.KeywordConst)
                    {
                        NextToken();
                        paramIsConst = true;
                    }

                    // Read in the data type keyword and store it.
                    NextToken();
                    DataTypeValue paramDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);
                    if (paramDataType.DataType == DataType.Invalid) Error(ErrorCode.InvalidDataType, "Expecting data type keyword.", false, 0);

                    // Read in array declaration.
                    bool paramIsArray = false;
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        NextToken();
                        paramIsArray = true;
                        paramDataType.IsArray = true;
                        ExpectToken(TokenID.CharCloseBracket);
                    }

                    // Increase the parameter mask
                    functionParameterMask.Add(paramDataType);
                    parameterCount++;

                    // Read in the parameters identifier.
                    ExpectToken(TokenID.TypeIdentifier);
                    string paramIdentifier = _currentToken.Ident;

                    // Process parameters depending on current pass.
                    if (_currentPass == 0)
                    {
                        VariableSymbol variableSymbol = new VariableSymbol(null);
                        variableSymbol.DataType = paramDataType;
                        variableSymbol.Identifier = paramIdentifier;
                        variableSymbol.VariableType = VariableType.Parameter;
                        variableSymbol.IsArray = paramIsArray;
                        variableSymbol.IsConstant = paramIsConst;
                        paramList.Add(variableSymbol);
                    }

                    // Read in comma if it exists.
                    if (LookAheadToken().ID == TokenID.CharComma)
                        NextToken();
                    else
                        break;

                }

            }

            // *looks arounds shiftily* ... Ok its hack like but it works.
            functionParameterMask.Reverse();

            // Create a new function symbol.
            FunctionSymbol functionSymbol;
            if (_currentPass == 0)
            {
                if (_currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) != null)
                    Error(ErrorCode.DuplicateSymbol, "Function \"" + functionIdentifier + "\" redefinition.", false, 0);

                functionSymbol = new FunctionSymbol(functionIdentifier, _currentScope);
                functionSymbol.ReturnType = returnDataType;
                functionSymbol.ParameterCount = parameterCount;
                functionSymbol.IsThreadSpawner = isThread;
                functionSymbol.IsEvent = isEvent;
                functionSymbol.IsConsole = isConsole;
                functionSymbol.IsImport = isImport;
                functionSymbol.IsExport = isExport;
                functionSymbol.AccessModifier = modifier;

                if (isConsole == true && functionSymbol.ReturnType.DataType != DataType.Void)
                    Error(ErrorCode.InvalidDataType, "Console variables cannot return a value.");

                paramList.Reverse();
                int parameterIndex = 0;
                foreach (VariableSymbol variableSymbol in paramList)
                {
                    if (functionSymbol.FindSymbol(variableSymbol.Identifier, SymbolType.Variable) != null)
                        Error(ErrorCode.DuplicateSymbol, "Variable redefinition \"" + variableSymbol.Identifier + "\"");

                    // If we're a console function we can only accept bool, int, string or float
                    if (isConsole == true &&
                        (variableSymbol.DataType.IsArray == true ||
                        variableSymbol.DataType.DataType == DataType.Byte ||
                        variableSymbol.DataType.DataType == DataType.Double ||
                        variableSymbol.DataType.DataType == DataType.Object ||
                        variableSymbol.DataType.DataType == DataType.Short))
                        Error(ErrorCode.InvalidDataType, "Console variables can only accept bool, integer, string or float parameters.");

                    functionSymbol.AddSymbol(variableSymbol);
                    variableSymbol.Scope = functionSymbol;
                    parameterIndex++;
                }
            }
            else
            {
                functionSymbol = _currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol;
                if (functionSymbol == null) functionSymbol = _globalScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol;
                if (functionSymbol == null) Error(ErrorCode.InvalidFunction, "Attempt to call undeclared function \"" + functionIdentifier + "(" + functionParameterMask + ")\".");

                for (int i = 0; i < parameterCount; i++)
                {
                    VariableSymbol variableSymbol = (VariableSymbol)functionSymbol.Symbols[i];
                    variableSymbol.StackIndex = -(functionSymbol.LocalDataSize + 2 + (i + 1));
                }
            }
            _lastMetaDataSymbol = functionSymbol;

            // Read in the closing parenthesis used to define the end of the paremeter list.
            ExpectToken(TokenID.CharCloseParenthesis);

            // Read in this function's statement block.
            if (functionSymbol.IsImport == false)
            {
                Symbol scope = _currentScope;
                Instruction instruction = null;
                _currentScope = functionSymbol;
                ParseStatement();
                _currentScope = scope;

                // Append a mandatory return instruction if we are in pass 2.
                if (_currentPass == 1)
                {
                    // Cast the return registered into the return type.
                    if (functionSymbol.ReturnType.DataType != DataType.Void)
                    {
                        instruction = CreateInstruction(OpCodeByType(functionSymbol.ReturnType, OpCodeType.CAST), functionSymbol, _currentToken);
                        new Operand(instruction, Register.Return);
                    }

                    // Return from function.
                    instruction = CreateInstruction(OpCode.RETURN, functionSymbol, _currentToken);
                }
            }
            else
                ExpectToken(TokenID.CharSemiColon);
        }
        /// <summary>
        ///		Finds a native function that has the same identifier, return type and
        ///		parameter types as those passed.
        /// </summary>
        /// <param name="identifier">Identifier of function to find.</param>
        /// <param name="returnType">Return type of function to find.</param>
        /// <param name="parameterTypes">Array of parameter types of function to find.</param>
        /// <returns>Null if no function is found, if one is then it is returned.</returns>
        public NativeFunction FindNativeFunction(string identifier, DataTypeValue[] parameterMask)
        {
            string fullName = identifier + "(";
            for (int i = 0; i < parameterMask.Length; i++)
                fullName += parameterMask[i] + (i < parameterMask.Length - 1 ? "," : "");
            fullName += ")";

            /*
            foreach (NativeFunction function in _nativeFunctions[(int)identifier[0]])
            {
                if (function.Identifier.ToLower() != identifier.ToLower()) continue;
                if (function.ParameterTypes.Length != parameterMask.Length) continue;

                bool paramsValid = true;
                for (int i = 0; i < parameterMask.Length; i++)
                    if (function.CheckParameterTypeValid(i, parameterMask[i]) == false)
                        paramsValid = false;
                if (paramsValid == false) continue;
                return function;
            }
            */

            return _nativeFunctions[fullName] as NativeFunction;
        }
        /// <summary>
        /// 
        /// </summary>
        private void ParseMemberFunctionCall(string identifier, DataTypeValue returnDataType)
        {
            // Read the opening parenthesis.
            ExpectToken(TokenID.CharOpenParenthesis);

            // Pop the object out.
            if (_currentPass == 1)
            {
                Instruction instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                new Operand(instruction, Register.Member);
            }

            // Read in each parameter's expression.
            ArrayList parameterTypeList = new ArrayList();
            string parameterMask = "";
            while (true)
            {
                // Check for parenthesis close
                if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
                {
                    // Read in the parameters expression.
                    DataTypeValue expressionType = ParseExpression();
                    parameterMask += (parameterMask != "" ? "," : "") + expressionType.ToString();
                    parameterTypeList.Add(expressionType);

                    // Read in comma if we are not at the
                    // end of the parameter list.
                    if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
                        ExpectToken(TokenID.CharComma);
                }
                else
                    break;
            }

            // *looks arounds shiftily* ... Ok its hack like but it works.
            parameterTypeList.Reverse();

            // Read the closing parenthesis.
            ExpectToken(TokenID.CharCloseParenthesis);

            // Get the function symbol if in pass 2.
            FunctionSymbol functionSymbol = null;
            if (_currentPass == 1)
            {
                functionSymbol = _memberScope.FindFunctionByMask(identifier, parameterTypeList) as FunctionSymbol;
                if (functionSymbol == null)
                {
                    // Create the function symbol.
                    functionSymbol = new FunctionSymbol(identifier, _memberScope);
                    functionSymbol.Identifier = identifier;
                    functionSymbol.ReturnType = returnDataType;
                    functionSymbol.IsMember = true;
                    functionSymbol.ParameterCount = parameterTypeList.Count;

                    // Create a symbol for each parameters.
                    foreach (DataTypeValue value in parameterTypeList)
                    {
                        VariableSymbol variableSymbol = new VariableSymbol(functionSymbol);
                        variableSymbol.DataType = value;
                        variableSymbol.Identifier = "";
                        variableSymbol.VariableType = VariableType.Parameter;
                        variableSymbol.IsArray = value.IsArray;
                    }
                }

                Instruction instruction = CreateInstruction(OpCode.CALL_METHOD, _currentScope, _currentToken);
                new Operand(instruction, Register.Member);
                new Operand(instruction, functionSymbol);
            }
        }
        /// <summary>
        ///		Registers a native function that can be imported and used by script processes.
        /// </summary>
        public void RegisterNativeFunction(string identifier, FunctionDelegate functionDelegate, DataTypeValue returnType, params DataTypeValue[] parameterTypeList)
        {
            string fullName = identifier + "(";
            for (int i = 0; i < parameterTypeList.Length; i++)
                fullName += parameterTypeList[i] + (i < parameterTypeList.Length - 1 ? "," : "");
            fullName += ")";

            _nativeFunctions.Add(fullName, new NativeFunction(identifier, functionDelegate, returnType, parameterTypeList));
        }
        /// <summary>
        ///		Parses a lower-top level expression. The lower-top level is responsible for parsing 
        ///		any leaf expression and relational operators.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseSubExpression()
        {
            // Parse the left hand leaf expression.
            DataTypeValue leafDataType1 = ParseLeafExpression();

            // Parse any subsequent leaf expressions that are seperated
            // by logical operators.
            while (true)
            {
                // Check that the next token is relational.
                Token operatorToken = LookAheadToken();
                if (operatorToken.IsRelational == false)
                    break;
                NextToken();

                // Parse the right hand lead expression.
                DataTypeValue leafDataType2 = ParseLeafExpression();

                // Check the new data type can be cast to the main data type
                if (CanImplicitlyCast(leafDataType1, leafDataType2) == true)
                {

                    // Check the data types are valid with this operator.
                    if (OperatorDataTypeValid(leafDataType1, operatorToken.ID) == false)
                        Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + leafDataType1.ToString() + "\"", false, 1);

                    // We only want to emit byte code on the second pass.
                    if (_currentPass == 1)
                    {

                        // Pop the result of the second sub expression into arithmetic
                        // register 1.
                        Instruction instruction = CreateInstruction(OpCodeByType(leafDataType2, OpCodeType.POP), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);

                        // Pop the result of the first sub expression into arithmetic
                        // register 2.
                        instruction = CreateInstruction(OpCodeByType(leafDataType1, OpCodeType.POP), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic1);

                        #region Relational Byte Code Emiting

                        // Cast rvalue into lvalues type.
                        if (leafDataType1 != leafDataType2)
                        {
                            instruction = CreateInstruction(OpCodeByType(leafDataType1, OpCodeType.CAST), _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic2);
                        }

                        // Compare the results.
                        instruction = CreateInstruction(OpCodeByType(leafDataType1, OpCodeType.CMP), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic1);
                        new Operand(instruction, Register.Arithmetic2);

                        // Create equality byte code based on the given operator.
                        switch (operatorToken.ID)
                        {
                            case TokenID.OpEqual: instruction = CreateInstruction(OpCode.IS_EQ, _currentScope, _currentToken); break;
                            case TokenID.OpGreater: instruction = CreateInstruction(OpCode.IS_G, _currentScope, _currentToken); break;
                            case TokenID.OpGreaterEqual: instruction = CreateInstruction(OpCode.IS_GE, _currentScope, _currentToken); break;
                            case TokenID.OpLess: instruction = CreateInstruction(OpCode.IS_L, _currentScope, _currentToken); break;
                            case TokenID.OpLessEqual: instruction = CreateInstruction(OpCode.IS_LE, _currentScope, _currentToken); break;
                            case TokenID.OpNotEqual: instruction = CreateInstruction(OpCode.IS_NE, _currentScope, _currentToken); break;
                        }

                        #endregion
                    }

                    // Data type is now boolean due to the comparison operators.
                    leafDataType1 = new DataTypeValue(DataType.Bool, false, false);
                }
                else
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + leafDataType1.ToString() + "\" and \"" + leafDataType2.ToString() + "\"", false, 1);

            }

            return leafDataType1;
        }
        /// <summary>
        ///		Checks if 2 data types can be used together without the need
        ///		for manual casting.
        /// </summary>
        /// <param name="dest">Destination data type.</param>
        /// <param name="src">Source data type.</param>
        /// <returns>True if types can be used together.</returns>
        private bool CanImplicitlyCast(DataTypeValue dest, DataTypeValue src)
        {
            if (_currentPass == 0) return true; // Assume everything can cast when in the first pass.
            if ((dest.IsArray != src.IsArray || dest.IsReference != src.IsReference) && src.DataType != DataType.Null) return false;
            if (dest == src || dest.DataType == DataType.Null || src.DataType == DataType.Null) return true;
            switch (dest.DataType)
            {
                case DataType.Bool:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Byte:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Float:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Double:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Int:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Long:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.Short:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;
                case DataType.String:
                    if (src.DataType == DataType.Bool || src.DataType == DataType.Byte ||
                        src.DataType == DataType.Double || src.DataType == DataType.Float ||
                        src.DataType == DataType.Int || src.DataType == DataType.Long ||
                        src.DataType == DataType.Short || src.DataType == DataType.String) return true;
                    break;

                // These type's can't be converted to anything but themselfs.
                case DataType.Object:
                    break;
                case DataType.Void:
                    break;
            }
            return false;
        }
 /// <summary>
 ///		Retrieves a symbol from this symbols scope by checking its identifier 
 ///		with the given identifier, its type against the given type and its data
 ///     type against a given data type.
 /// </summary>
 /// <param name="ident">Identifier to find symbol by.</param>
 /// <param name="type">Type of symbol to find symbol by.</param>
 /// <param name="dataType"></param>
 /// <returns>A symbol with the same indentifier as the one passed or null if one can't be found.</returns>
 public Symbol FindVariableSymbol(string ident, DataTypeValue dataType)
 {
     foreach (Symbol symbol in _symbolList)
     {
         if (symbol.Identifier == null) continue;
         if (symbol.Identifier.ToLower() == ident.ToLower() && symbol.Type == SymbolType.Variable && ((VariableSymbol)symbol).DataType == dataType) return symbol;
     }
     return null;
 }
        /// <summary>
        ///		Chooses the correct byte code based on the data type.
        /// </summary>
        /// <param name="type">Type to find operation code from.</param>
        /// <returns>The correct opcode based on the data type.</returns>
        private OpCode OpCodeByType(DataTypeValue type, OpCodeType opCodeType)
        {
            switch (opCodeType)
            {
                case OpCodeType.ALLOCATE_HEAP:
                    switch (type.DataType)
                    {
                        case DataType.Null: return OpCode.ALLOCATE_HEAP_NULL;
                        case DataType.Bool: return OpCode.ALLOCATE_HEAP_BOOL;
                        case DataType.Byte: return OpCode.ALLOCATE_HEAP_BYTE;
                        case DataType.Double: return OpCode.ALLOCATE_HEAP_DOUBLE;
                        case DataType.Object: return OpCode.ALLOCATE_HEAP_Object;
                        case DataType.Float: return OpCode.ALLOCATE_HEAP_FLOAT;
                        case DataType.Int: return OpCode.ALLOCATE_HEAP_INT;
                        case DataType.Long: return OpCode.ALLOCATE_HEAP_LONG;
                        case DataType.Short: return OpCode.ALLOCATE_HEAP_SHORT;
                        case DataType.String: return OpCode.ALLOCATE_HEAP_STRING;
                    }
                    break;
                case OpCodeType.CAST:
                    switch (type.DataType)
                    {
                        case DataType.Null: return OpCode.CAST_NULL;
                        case DataType.Bool: return OpCode.CAST_BOOL;
                        case DataType.Byte: return OpCode.CAST_BYTE;
                        case DataType.Double: return OpCode.CAST_DOUBLE;
                        case DataType.Object: return OpCode.CAST_Object;
                        case DataType.Float: return OpCode.CAST_FLOAT;
                        case DataType.Int: return OpCode.CAST_INT;
                        case DataType.Long: return OpCode.CAST_LONG;
                        case DataType.Short: return OpCode.CAST_SHORT;
                        case DataType.String: return OpCode.CAST_STRING;
                    }
                    break;
                case OpCodeType.CMP:

                    // If its an array or reference we need to compare the
                    // memory index not the value.
                    if (type.IsArray == true || type.IsReference == true)
                    {
                        return OpCode.CMP_MEMORY_INDEX;
                    }

                    switch (type.DataType)
                    {
                        case DataType.Null: return OpCode.CMP_NULL;
                        case DataType.Bool: return OpCode.CMP_BOOL;
                        case DataType.Byte: return OpCode.CMP_BYTE;
                        case DataType.Double: return OpCode.CMP_DOUBLE;
                        case DataType.Object: return OpCode.CMP_Object;
                        case DataType.Float: return OpCode.CMP_FLOAT;
                        case DataType.Int: return OpCode.CMP_INT;
                        case DataType.Long: return OpCode.CMP_LONG;
                        case DataType.Short: return OpCode.CMP_SHORT;
                        case DataType.String: return OpCode.CMP_STRING;
                    }
                    break;
                case OpCodeType.PUSH:

                    // If its an array or reference we need to push the
                    // memory index not the value.
                    if (type.IsArray == true || type.IsReference == true)
                    {
                        return OpCode.PUSH_MEMORY_INDEX;
                    }

                    switch (type.DataType)
                    {
                        case DataType.Null: return OpCode.PUSH_NULL;
                        case DataType.Bool: return OpCode.PUSH_BOOL;
                        case DataType.Byte: return OpCode.PUSH_BYTE;
                        case DataType.Double: return OpCode.PUSH_DOUBLE;
                        case DataType.Object: return OpCode.PUSH_OBJECT;
                        case DataType.Float: return OpCode.PUSH_FLOAT;
                        case DataType.Int: return OpCode.PUSH_INT;
                        case DataType.Long: return OpCode.PUSH_LONG;
                        case DataType.Short: return OpCode.PUSH_SHORT;
                        case DataType.String: return OpCode.PUSH_STRING;
                    }
                    break;
                case OpCodeType.POP:

                    // If its an array or reference we need to pop the
                    // memory index not the value.
                    if (type.IsArray == true || type.IsReference == true)
                    {
                        return OpCode.POP_MEMORY_INDEX;
                    }

                    switch (type.DataType)
                    {
                        case DataType.Null: return OpCode.POP_NULL;
                        case DataType.Bool: return OpCode.POP_BOOL;
                        case DataType.Byte: return OpCode.POP_BYTE;
                        case DataType.Double: return OpCode.POP_DOUBLE;
                        case DataType.Object: return OpCode.POP_OBJECT;
                        case DataType.Float: return OpCode.POP_FLOAT;
                        case DataType.Int: return OpCode.POP_INT;
                        case DataType.Long: return OpCode.POP_LONG;
                        case DataType.Short: return OpCode.POP_SHORT;
                        case DataType.String: return OpCode.POP_STRING;
                    }
                    break;
                case OpCodeType.MOV:

                    // If its an array or reference we need to move the
                    // memory index not the value.
                    if (type.IsArray == true || type.IsReference == true)
                    {
                        return OpCode.MOV_MEMORY_INDEX;
                    }

                    switch (type.DataType)
                    {
                        case DataType.Bool: return OpCode.MOV_BOOL;
                        case DataType.Byte: return OpCode.MOV_BYTE;
                        case DataType.Double: return OpCode.MOV_DOUBLE;
                        case DataType.Object: return OpCode.MOV_OBJECT;
                        case DataType.Null: return OpCode.MOV_NULL;
                        case DataType.Float: return OpCode.MOV_FLOAT;
                        case DataType.Int: return OpCode.MOV_INT;
                        case DataType.Long: return OpCode.MOV_LONG;
                        case DataType.Short: return OpCode.MOV_SHORT;
                        case DataType.String: return OpCode.MOV_STRING;
                    }
                    break;
                case OpCodeType.MUL:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.MUL_BYTE;
                        case DataType.Double: return OpCode.MUL_DOUBLE;
                        case DataType.Float: return OpCode.MUL_FLOAT;
                        case DataType.Int: return OpCode.MUL_INT;
                        case DataType.Long: return OpCode.MUL_LONG;
                        case DataType.Short: return OpCode.MUL_SHORT;
                    }
                    break;
                case OpCodeType.DIV:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.DIV_BYTE;
                        case DataType.Double: return OpCode.DIV_DOUBLE;
                        case DataType.Float: return OpCode.DIV_FLOAT;
                        case DataType.Int: return OpCode.DIV_INT;
                        case DataType.Long: return OpCode.DIV_LONG;
                        case DataType.Short: return OpCode.DIV_SHORT;
                    }
                    break;
                case OpCodeType.ADD:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.ADD_BYTE;
                        case DataType.Double: return OpCode.ADD_DOUBLE;
                        case DataType.Float: return OpCode.ADD_FLOAT;
                        case DataType.Int: return OpCode.ADD_INT;
                        case DataType.Long: return OpCode.ADD_LONG;
                        case DataType.Short: return OpCode.ADD_SHORT;
                        case DataType.String: return OpCode.ADD_STRING;
                    }
                    break;
                case OpCodeType.SUB:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.SUB_BYTE;
                        case DataType.Double: return OpCode.SUB_DOUBLE;
                        case DataType.Float: return OpCode.SUB_FLOAT;
                        case DataType.Int: return OpCode.SUB_INT;
                        case DataType.Long: return OpCode.SUB_LONG;
                        case DataType.Short: return OpCode.SUB_SHORT;
                    }
                    break;
                case OpCodeType.INC:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.INC_BYTE;
                        case DataType.Double: return OpCode.INC_DOUBLE;
                        case DataType.Float: return OpCode.INC_FLOAT;
                        case DataType.Int: return OpCode.INC_INT;
                        case DataType.Long: return OpCode.INC_LONG;
                        case DataType.Short: return OpCode.INC_SHORT;
                    }
                    break;
                case OpCodeType.DEC:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.DEC_BYTE;
                        case DataType.Double: return OpCode.DEC_DOUBLE;
                        case DataType.Float: return OpCode.DEC_FLOAT;
                        case DataType.Int: return OpCode.DEC_INT;
                        case DataType.Long: return OpCode.DEC_LONG;
                        case DataType.Short: return OpCode.DEC_SHORT;
                    }
                    break;
                case OpCodeType.NEG:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.NEG_BYTE;
                        case DataType.Double: return OpCode.NEG_DOUBLE;
                        case DataType.Float: return OpCode.NEG_FLOAT;
                        case DataType.Int: return OpCode.NEG_INT;
                        case DataType.Long: return OpCode.NEG_LONG;
                        case DataType.Short: return OpCode.NEG_SHORT;
                    }
                    break;
                case OpCodeType.ABS:
                    switch (type.DataType)
                    {
                        case DataType.Byte: return OpCode.ABS_BYTE;
                        case DataType.Double: return OpCode.ABS_DOUBLE;
                        case DataType.Float: return OpCode.ABS_FLOAT;
                        case DataType.Int: return OpCode.ABS_INT;
                        case DataType.Long: return OpCode.ABS_LONG;
                        case DataType.Short: return OpCode.ABS_SHORT;
                    }
                    break;
            }
            return OpCode.INVALID;
        }
        /// <summary>
        ///		Loads this scene node from a given binary reader.
        /// </summary>
        /// <param name="reader">Binary reader to load this scene node from.</param>
        public override void Load(BinaryReader reader)
        {
            // Load all the basic entity details.
            base.Load(reader);

            // Load all the scripted specific details.
            if (reader.ReadBoolean() == true)
            {
                string url = reader.ReadString();

                // Load the objects script from the memory stream we dumped it into.
                ScriptProcess process = VirtualMachine.GlobalInstance.LoadScript(url);

                #region Property Loading
                int propertyCount = reader.ReadInt16();
                for (int i = 0; i < propertyCount; i++)
                {
                    string identifier = reader.ReadString();
                    DataTypeValue dataTypeValue = new DataTypeValue((DataType)reader.ReadByte(), false, false);
                    bool isArray = reader.ReadBoolean();

                    // Look through the script processes global variables to see if this
                    // variable exists.
                    VariableSymbol variableSymbol = null;
                    if (process != null)
                    {
                        foreach (Symbol symbol in process.GlobalScope.Symbols)
                        {
                            if (symbol is VariableSymbol == false || ((VariableSymbol)symbol).Identifier != identifier || ((VariableSymbol)symbol).DataType != dataTypeValue) continue;
                            variableSymbol = symbol as VariableSymbol;
                            break;
                        }
                    }

                    // Quickly find out the meta data of this symbol.
                    string editMethod = "";
                    if (variableSymbol != null)
                    {
                        foreach (Symbol subSymbol in variableSymbol.Symbols)
                            if (subSymbol is MetaDataSymbol)
                                if (((MetaDataSymbol)subSymbol).Identifier.ToLower() == "editmethod")
                                {
                                    editMethod = ((MetaDataSymbol)subSymbol).Value;
                                    break;
                                }
                    }

                    // Read in value based on data type.
                    if (isArray == true && reader.ReadBoolean() == true)
                    {
                        int arrayLength = reader.ReadInt32();
                        int arrayIndex = process == null ? 0 : process[0].AllocateArray(dataTypeValue.DataType, arrayLength);
                        for (int k = 0; k < arrayLength; k++)
                        {
                            switch (dataTypeValue.DataType)
                            {
                                case DataType.Bool:
                                    {
                                        bool value = reader.ReadBoolean();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Byte:
                                    {
                                        byte value = reader.ReadByte();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Double:
                                    {
                                        double value = reader.ReadDouble();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Float:
                                    {
                                        float value = reader.ReadSingle();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Int:
                                    {
                                        int value = reader.ReadInt32();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Long:
                                    {
                                        long value = reader.ReadInt64();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.Short:
                                    {
                                        short value = reader.ReadInt16();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, k, value);
                                    }
                                    break;
                                case DataType.String:
                                    {
                                        string value = reader.ReadString();
                                        if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, i, value);
                                    }
                                    break;
                                case DataType.Object:
                                    {
                                        if (reader.ReadBoolean() == true)
                                        {
                                            int type = reader.ReadByte();
                                            if (type == 0)
                                            {
                                                string imageUrl = reader.ReadString();
                                                int cellWidth = reader.ReadInt32();
                                                int cellHeight = reader.ReadInt32();
                                                int hSpacing = reader.ReadInt16();
                                                int vSpacing = reader.ReadInt16();
                                                if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, i, new Fusion.Engine.ScriptingFunctions.ImageScriptObject(GraphicsManager.LoadImage(imageUrl, cellWidth, cellHeight, hSpacing, vSpacing, 0)));
                                            }
                                            else if (type == 1)
                                            {
                                                string soundUrl = reader.ReadString();
                                                int freq = reader.ReadInt32();
                                                float innerRadius = reader.ReadSingle();
                                                float outerRadius = reader.ReadSingle();
                                                bool loop = reader.ReadBoolean();
                                                float pan = reader.ReadSingle();
                                                float volume = reader.ReadSingle();
                                                bool streaming = reader.ReadBoolean();
                                                bool positional = reader.ReadBoolean();
                                                Audio.SoundFlags flags = 0;
                                                if (streaming == true) flags |= Audio.SoundFlags.Streamed;
                                                if (positional == true) flags |= Audio.SoundFlags.Positional;

                                                Audio.Sound sound = Audio.AudioManager.LoadSound(soundUrl, flags);
                                                sound.Frequency = freq;
                                                sound.InnerRadius = innerRadius;
                                                sound.OuterRadius = outerRadius;
                                                sound.Looping = loop;
                                                sound.Pan = pan;
                                                sound.Volume = volume;
                                                if (process != null && variableSymbol != null) process[0].SetArrayElement(arrayIndex, i, new Fusion.Engine.ScriptingFunctions.SoundScriptObject(sound));
                                            }
                                        }
                                    }
                                    break;
                            }
                        }
                    }
                    else
                    {
                        switch (dataTypeValue.DataType)
                        {
                            case DataType.Bool:
                                {
                                    bool value = reader.ReadBoolean();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Byte:
                                {
                                    byte value = reader.ReadByte();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Double:
                                {
                                    double value = reader.ReadDouble();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Float:
                                {
                                    float value = reader.ReadSingle();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Int:
                                {
                                    int value = reader.ReadInt32();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Long:
                                {
                                    long value = reader.ReadInt64();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Short:
                                {
                                    short value = reader.ReadInt16();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.String:
                                {
                                    string value = reader.ReadString();
                                    if (process != null && variableSymbol != null) process[0].SetGlobalVariable(identifier, value);
                                }
                                break;
                            case DataType.Object:
                                {
                                    if (reader.ReadBoolean() == true)
                                    {
                                        int type = reader.ReadByte();
                                        if (type == 0)
                                        {
                                            string imageUrl = reader.ReadString();
                                            int cellWidth = reader.ReadInt32();
                                            int cellHeight = reader.ReadInt32();
                                            int hSpacing = reader.ReadInt16();
                                            int vSpacing = reader.ReadInt16();
                                            if (ResourceManager.ResourceExists(imageUrl) == true && process != null && variableSymbol != null)
                                                process[0].SetGlobalVariable(identifier, new Fusion.Engine.ScriptingFunctions.ImageScriptObject(GraphicsManager.LoadImage(imageUrl, cellWidth, cellHeight, hSpacing, vSpacing, 0)));
                                        }
                                        else if (type == 1)
                                        {
                                            string soundUrl = reader.ReadString();
                                            int freq = reader.ReadInt32();
                                            float innerRadius = reader.ReadSingle();
                                            float outerRadius = reader.ReadSingle();
                                            bool loop = reader.ReadBoolean();
                                            float pan = reader.ReadSingle();
                                            float volume = reader.ReadSingle();
                                            bool streaming = reader.ReadBoolean();
                                            bool positional = reader.ReadBoolean();
                                            Audio.SoundFlags flags = 0;
                                            if (streaming == true) flags |= Audio.SoundFlags.Streamed;
                                            if (positional == true) flags |= Audio.SoundFlags.Positional;

                                            if (ResourceManager.ResourceExists(soundUrl) == true && process != null && variableSymbol != null)
                                            {
                                                Audio.Sound sound = Audio.AudioManager.LoadSound(soundUrl, flags);
                                                sound.Frequency = freq;
                                                sound.InnerRadius = innerRadius;
                                                sound.OuterRadius = outerRadius;
                                                sound.Looping = loop;
                                                sound.Pan = pan;
                                                sound.Volume = volume;
                                                process[0].SetGlobalVariable(identifier, new Fusion.Engine.ScriptingFunctions.SoundScriptObject(sound));
                                            }
                                        }
                                    }
                                }
                                break;
                        }
                    }
                }
                #endregion

                // Now set the process!
                _process.Process = process;
                if (_process.Process != null) _process.Process.OnStateChange += OnStateChange;
                if (_process.Process != null && _process.Process.State != null) OnStateChange(_process.Process, _process.Process.State);

                SyncCollisionEvents();
            }
        }
        /// <summary>
        ///     Converts this instance to a textural form.
        /// </summary>
        /// <returns>Textural form of this instance.</returns>
        public override string ToString()
        {
            DataTypeValue[] parameterTypes = new DataTypeValue[_parameterCount];
            for (int i = 0; i < _parameterCount; i++)
                parameterTypes[i] = (_symbolList[i] as VariableSymbol).DataType;

            string fullName = _ident + "(";
            for (int i = 0; i < parameterTypes.Length; i++)
                fullName += parameterTypes[i] + (i < parameterTypes.Length - 1 ? "," : "");
            fullName += ")";

            return fullName;
        }