private ConstructorDefinition ParseConstructor(
            TokenStream tokens,
            TopLevelConstruct owner,
            AnnotationCollection annotations)
        {
            Token constructorToken = tokens.PopExpected(this.parser.Keywords.CONSTRUCTOR);

            tokens.PopExpected("(");
            List <Token>      argNames  = new List <Token>();
            List <Expression> argValues = new List <Expression>();
            bool optionalArgFound       = false;

            while (!tokens.PopIfPresent(")"))
            {
                if (argNames.Count > 0)
                {
                    tokens.PopExpected(",");
                }

                Token argName = tokens.Pop();
                this.parser.VerifyIdentifier(argName);
                Expression defaultValue = null;
                if (tokens.PopIfPresent("="))
                {
                    defaultValue     = this.parser.ExpressionParser.Parse(tokens, owner);
                    optionalArgFound = true;
                }
                else if (optionalArgFound)
                {
                    throw this.parser.GenerateParseError(
                              ErrorMessages.OPTIONAL_ARGUMENT_WAS_NOT_AT_END_OF_ARGUMENT_LIST,
                              argName);
                }

                argNames.Add(argName);
                argValues.Add(defaultValue);
            }

            List <Expression> baseArgs  = new List <Expression>();
            Token             baseToken = null;

            if (tokens.PopIfPresent(":"))
            {
                baseToken = tokens.PopExpected(this.parser.Keywords.BASE);
                tokens.PopExpected("(");
                while (!tokens.PopIfPresent(")"))
                {
                    if (baseArgs.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }

                    baseArgs.Add(this.parser.ExpressionParser.Parse(tokens, owner));
                }
            }

            IList <Executable> code = ParserContext.ParseBlock(parser, tokens, true, owner);

            return(new ConstructorDefinition(constructorToken, argNames, argValues, baseArgs, code, baseToken, annotations, owner));
        }
        private Executable ParseFor(TokenStream tokens, TopLevelConstruct owner)
        {
            Token forToken = tokens.PopExpected(this.parser.Keywords.FOR);

            tokens.PopExpected("(");
            if (!tokens.HasMore)
            {
                tokens.ThrowEofException();
            }

            if (this.parser.IsValidIdentifier(tokens.PeekValue()) && tokens.PeekValue(1) == ":")
            {
                Token iteratorToken = tokens.Pop();
                if (this.parser.IsReservedKeyword(iteratorToken.Value))
                {
                    throw new ParserException(iteratorToken, "Cannot use this name for an iterator.");
                }
                tokens.PopExpected(":");
                Expression iterationExpression = this.parser.ExpressionParser.Parse(tokens, owner);
                tokens.PopExpected(")");
                IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner);

                return(new ForEachLoop(forToken, iteratorToken, iterationExpression, body, owner));
            }
            else
            {
                List <Executable> init = new List <Executable>();
                while (!tokens.PopIfPresent(";"))
                {
                    if (init.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    init.Add(this.Parse(tokens, true, false, owner));
                }
                Expression condition = null;
                if (!tokens.PopIfPresent(";"))
                {
                    condition = this.parser.ExpressionParser.Parse(tokens, owner);
                    tokens.PopExpected(";");
                }
                List <Executable> step = new List <Executable>();
                while (!tokens.PopIfPresent(")"))
                {
                    if (step.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    step.Add(this.Parse(tokens, true, false, owner));
                }

                IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner);

                return(new ForLoop(forToken, init, condition, step, body, owner));
            }
        }
        private FunctionDefinition ParseFunction(
            TokenStream tokens,
            TopLevelConstruct nullableOwner,
            FileScope fileScope,
            AnnotationCollection annotations)
        {
            bool isStatic =
                nullableOwner != null &&
                nullableOwner is ClassDefinition &&
                tokens.PopIfPresent(this.parser.Keywords.STATIC);

            Token functionToken = tokens.PopExpected(this.parser.Keywords.FUNCTION);

            Token functionNameToken = tokens.Pop();

            this.parser.VerifyIdentifier(functionNameToken);

            FunctionDefinition fd = new FunctionDefinition(functionToken, parser.CurrentLibrary, nullableOwner, isStatic, functionNameToken, annotations, fileScope);

            tokens.PopExpected("(");
            List <Token>      argNames      = new List <Token>();
            List <Expression> defaultValues = new List <Expression>();
            bool optionalArgFound           = false;

            while (!tokens.PopIfPresent(")"))
            {
                if (argNames.Count > 0)
                {
                    tokens.PopExpected(",");
                }

                Token      argName      = tokens.Pop();
                Expression defaultValue = null;
                this.parser.VerifyIdentifier(argName);
                if (tokens.PopIfPresent("="))
                {
                    optionalArgFound = true;
                    defaultValue     = this.parser.ExpressionParser.Parse(tokens, fd);
                }
                else if (optionalArgFound)
                {
                    throw new ParserException(argName, "All optional arguments must come at the end of the argument list.");
                }
                argNames.Add(argName);
                defaultValues.Add(defaultValue);
            }

            IList <Executable> code = ParserContext.ParseBlock(parser, tokens, true, fd);

            fd.ArgNames      = argNames.ToArray();
            fd.DefaultValues = defaultValues.ToArray();
            fd.Code          = code.ToArray();

            return(fd);
        }
        private Executable ParseWhile(TokenStream tokens, TopLevelConstruct owner)
        {
            Token whileToken = tokens.PopExpected(this.parser.Keywords.WHILE);

            tokens.PopExpected("(");
            Expression condition = this.parser.ExpressionParser.Parse(tokens, owner);

            tokens.PopExpected(")");
            IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner);

            return(new WhileLoop(whileToken, condition, body, owner));
        }
        private Executable ParseDoWhile(TokenStream tokens, TopLevelConstruct owner)
        {
            Token doToken           = tokens.PopExpected(this.parser.Keywords.DO);
            IList <Executable> body = ParserContext.ParseBlock(parser, tokens, true, owner);

            tokens.PopExpected(this.parser.Keywords.DO_WHILE_END);
            tokens.PopExpected("(");
            Expression condition = this.parser.ExpressionParser.Parse(tokens, owner);

            tokens.PopExpected(")");
            tokens.PopExpected(";");
            return(new DoWhileLoop(doToken, body, condition, owner));
        }
        private Executable ParseIf(TokenStream tokens, TopLevelConstruct owner)
        {
            Token ifToken = tokens.PopExpected(this.parser.Keywords.IF);

            tokens.PopExpected("(");
            Expression condition = this.parser.ExpressionParser.Parse(tokens, owner);

            tokens.PopExpected(")");
            IList <Executable> body = ParserContext.ParseBlock(parser, tokens, false, owner);
            IList <Executable> elseBody;

            if (tokens.PopIfPresent(this.parser.Keywords.ELSE))
            {
                elseBody = ParserContext.ParseBlock(parser, tokens, false, owner);
            }
            else
            {
                elseBody = new Executable[0];
            }
            return(new IfStatement(ifToken, condition, body, elseBody, owner));
        }
        private Executable ParseTry(TokenStream tokens, TopLevelConstruct owner)
        {
            Token tryToken = tokens.PopExpected(this.parser.Keywords.TRY);
            IList <Executable> tryBlock = ParserContext.ParseBlock(parser, tokens, true, owner);

            List <Token>        catchTokens         = new List <Token>();
            List <string[]>     exceptionTypes      = new List <string[]>();
            List <Token[]>      exceptionTypeTokens = new List <Token[]>();
            List <Token>        exceptionVariables  = new List <Token>();
            List <Executable[]> catchBlocks         = new List <Executable[]>();

            Token finallyToken = null;
            IList <Executable> finallyBlock = null;

            while (tokens.IsNext(this.parser.Keywords.CATCH))
            {
                /*
                 *  Parse patterns:
                 *      All exceptions:
                 *          1a: catch { ... }
                 *          1b: catch (e) { ... }
                 *
                 *      A certain exception:
                 *          2a: catch (ExceptionName) { ... }
                 *          2b: catch (ExceptionName e) { ... }
                 *
                 *      Certain exceptions:
                 *          3a: catch (ExceptionName1 | ExceptionName2) { ... }
                 *          3b: catch (ExceptionName1 | ExceptionName2 e) { ... }
                 *
                 *  Non-Context-Free alert:
                 *      Note that if the exception variable does not contain a '.' character, 1b and 2a are
                 *      ambiguous at parse time. Treat them both as 1b and then if the classname resolution
                 *      fails, treat this as a variable.
                 *
                 *      This is actually kind of bad because a typo in the classname will not be known.
                 *      e.g "catch (Excpetion) {" will compile as a variable called "Excpetion"
                 *
                 *      End-user workarounds:
                 *      - always use a variable name OR
                 *      - always fully qualify exception types e.g. Core.Exception
                 *      Long-term plan:
                 *      - add warning support and emit warnings for:
                 *          - unused variables
                 *          - style-breaking uppercase variables.
                 */

                Token catchToken = tokens.PopExpected(this.parser.Keywords.CATCH);

                List <string> classNames    = new List <string>();
                List <Token>  classTokens   = new List <Token>();
                Token         variableToken = null;

                if (tokens.PopIfPresent("("))
                {
                    // This first one might actually be a variable. Assume class for now and sort it out later.
                    // (and by "later" I mean the ResolveNames phase)
                    Token  classFirstToken = tokens.Pop();
                    string className       = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken);
                    classNames.Add(className);
                    classTokens.Add(classFirstToken);

                    while (tokens.PopIfPresent("|"))
                    {
                        classFirstToken = tokens.Pop();
                        className       = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classFirstToken);
                        classNames.Add(className);
                        classTokens.Add(classFirstToken);
                    }

                    if (!tokens.IsNext(")"))
                    {
                        variableToken = tokens.Pop();
                        this.parser.VerifyIdentifier(variableToken);
                    }

                    tokens.PopExpected(")");
                }
                else
                {
                    classNames.Add(null);
                    classTokens.Add(null);
                }

                Executable[] catchBlockCode = ParserContext.ParseBlock(parser, tokens, true, owner).ToArray();


                catchTokens.Add(catchToken);
                exceptionTypes.Add(classNames.ToArray());
                exceptionTypeTokens.Add(classTokens.ToArray());
                exceptionVariables.Add(variableToken);
                catchBlocks.Add(catchBlockCode);
            }

            if (tokens.IsNext(this.parser.Keywords.FINALLY))
            {
                finallyToken = tokens.Pop();
                finallyBlock = ParserContext.ParseBlock(parser, tokens, true, owner);
            }

            return(new TryStatement(tryToken, tryBlock, catchTokens, exceptionVariables, exceptionTypeTokens, exceptionTypes, catchBlocks, finallyToken, finallyBlock, owner));
        }