//////////////////////////////////////////////////////////////////////////
        private ScriptScope ParseEventHandler(ref List<ScriptToken>.Enumerator TokenEnum)
        {
            ScriptToken Token = TokenEnum.Current;
            if (Token == null) return null;

            // setup handler
            ScriptEventHandler Handler = new ScriptEventHandler();
            Handler.Signature = Token.Value + " ";
            Handler.Line = Token.OrigLine;
            Handler.Filename = Token.Filename;

            // setup scope
            ScriptScope Scope = new ScriptScope();
            Scope.Owner = Handler;
            Scope.StartLine = Token.StartLine;
            Scope.StartCol = Token.StartCol;

            while (TokenEnum.MoveNext())
            {
                Token = TokenEnum.Current;
                if (Token.IsComment) continue;

                if (Token.IsString)
                {
                    Handler.Signature += Token.Value;
                    Handler.Name = Token.Value.Trim(new char[] { '\"' });
                    break;
                }
                else return null;
            }
            EventHandlers.Add(Handler);
            return Scope;
        }
        //////////////////////////////////////////////////////////////////////////
        private ScriptScope ParseFunction(ref List<ScriptToken>.Enumerator TokenEnum)
        {
            ScriptToken Token = TokenEnum.Current;
            if(Token==null) return null;

            // setup function
            ScriptFunction Func = new ScriptFunction();
            Func.Signature = Token.Value + " ";
            Func.Line = Token.OrigLine;
            Func.Filename = Token.Filename;
            switch(Token.Value)
            {
                case "function":
                    Func.Type = ScriptFunctionType.Function;
                    break;
                case "method":
                    Func.Type = ScriptFunctionType.Method;
                    break;
                case "external":
                    Func.Type = ScriptFunctionType.External;
                    break;
                default:
                    Func.Type = ScriptFunctionType.Unknown;
                    break;
            }

            // setup scope
            ScriptScope Scope = new ScriptScope();
            Scope.Owner = Func;
            Scope.StartLine = Token.StartLine;
            Scope.StartCol = Token.StartCol;

            bool ReadingName = true;
            bool ReadingParams = false;

            while (TokenEnum.MoveNext())
            {
                Token = TokenEnum.Current;
                if (Token.IsComment) continue;

                if (ReadingName)
                {
                    if (!Token.IsIdentifier)
                    {
                        if(Func.Type==ScriptFunctionType.External)
                        {
                            Func.Signature += Token.Value + " ";
                        }
                        else return null;
                    }
                    else
                    {
                        Func.Name = Token.Value;
                        Func.Signature += Token.Value;

                        ReadingName = false;
                    }
                }
                else if(ReadingParams)
                {
                    if (Token.IsOperator && Token.Value == ")")
                    {
                        Func.Signature += Token.Value;
                        break;
                    }
                    else if(Token.IsOperator && Token.Value==",")
                    {
                        Func.Signature += Token.Value + " ";
                    }
                    else
                    {
                        ScriptVariable Var = ParseVariable(ref TokenEnum, true);
                        if (Var == null) return null;
                        else
                        {
                            Func.Signature += Var.Signature;
                            Func.Params.Add(Var.Signature);

                            if(Var.Name!="") Scope.Variables.Add(Var);

                            // hack because of unnamed external's parameters
                            Token = TokenEnum.Current;
                            if(Token.IsOperator && Token.Value==")")
                            {
                                Func.Signature += Token.Value;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    if (Token.IsOperator && Token.Value == "(")
                    {
                        ReadingParams = true;
                        Func.Signature += Token.Value;
                    }
                    else return null;
                }
            }

            Functions.Add(Func);
            return Scope;
        }
        //////////////////////////////////////////////////////////////////////////
        private bool Parse()
        {
            // cleanup
            GlobalScope = new ScriptScope();
            Scopes = new List<ScriptScope>();
            Functions = new List<ScriptFunction>();
            EventHandlers = new List<ScriptEventHandler>();

            _Tokenizer = new ScriptTokenizer(Reader);
            if (!_Tokenizer.GetTokens()) return false;

            ScriptScope CurrentScope = GlobalScope;

            bool ReadingBlock = false;
            int BlockNest = 0;

            List<ScriptToken>.Enumerator TokenEnum = _Tokenizer.Tokens.GetEnumerator();
            while(TokenEnum.MoveNext())
            {
                ScriptToken Token = TokenEnum.Current;
                if (Token.IsComment) continue;

                // functions
                if (Token.IsKeyword && (Token.Value == "function" || Token.Value == "method" || Token.Value == "external"))
                {
                    ScriptScope Scope = ParseFunction(ref TokenEnum);
                    if(Scope != null)
                    {
                        if(ReadingBlock)
                        {
                            CurrentScope.EndLine = Token.StartLine;
                            CurrentScope.EndCol = Token.StartCol;
                        }

                        CurrentScope = Scope;
                        Scopes.Add(Scope);
                        ReadingBlock = true;
                        BlockNest = 0;
                    }
                }

                // event handles
                else if(Token.IsKeyword && Token.Value=="on")
                {
                    ScriptScope Scope = ParseEventHandler(ref TokenEnum);
                    if (Scope != null)
                    {
                        if (ReadingBlock)
                        {
                            CurrentScope.EndLine = Token.StartLine;
                            CurrentScope.EndCol = Token.StartCol;
                        }

                        CurrentScope = Scope;
                        Scopes.Add(Scope);
                        ReadingBlock = true;
                        BlockNest = 0;
                    }
                }

                // variables
                else if(Token.IsKeyword && (Token.Value=="var" || Token.Value=="global" || Token.Value=="const"))
                {
                    ScriptVariable Var = ParseVariable(ref TokenEnum, false);
                    if(Var!=null && Var.Name!="")
                    {
                        if(ReadingBlock && BlockNest>0)	CurrentScope.Variables.Add(Var);
                        else GlobalScope.Variables.Add(Var);
                    }
                }

                // curly braces
                else if(Token.IsOperator)
                {
                    if (Token.Value == "{" && ReadingBlock) BlockNest++;
                    else if(Token.Value=="}" && ReadingBlock)
                    {
                        BlockNest--;
                        if (BlockNest <= 0)
                        {
                            ReadingBlock = false;
                            CurrentScope.EndLine = Token.EndLine;
                            CurrentScope.EndCol = Token.EndCol;
                        }
                    }
                    else if(Token.Value==";" && ReadingBlock && BlockNest==0)
                    {
                        ReadingBlock = false;
                        CurrentScope.EndLine = Token.EndLine;
                        CurrentScope.EndCol = Token.EndCol;
                    }

                }
            }

            return true;
        }