コード例 #1
0
        private Expression ParseLambda(
            TokenStream tokens,
            Token firstToken,
            IList <AType> argTypes,
            IList <Token> args,
            Node owner)
        {
            tokens.PopExpected("=>");
            Lambda             lambda = new Lambda(firstToken, owner, args, argTypes);
            IList <Executable> lambdaCode;

            if (tokens.IsNext("{"))
            {
                lambdaCode = this.parser.ExecutableParser.ParseBlock(tokens, false, lambda, false);
            }
            else
            {
                Expression lambdaBodyExpression = this.parser.ExpressionParser.ParseTernary(tokens, lambda);
                lambdaCode = new Executable[] { new ExpressionAsExecutable(lambdaBodyExpression, lambda) };
            }

            if (lambdaCode.Count == 1 && lambdaCode[0] is ExpressionAsExecutable)
            {
                // If a lambda contains a single expression as its code body, then this is an implicit return statement.
                ExpressionAsExecutable eae = (ExpressionAsExecutable)lambdaCode[0];
                lambdaCode[0] = new ReturnStatement(eae.FirstToken, eae.Expression, lambda);
            }
            lambda.Code = lambdaCode.ToArray();
            return(lambda);
        }
コード例 #2
0
        private Expression ParseIncrement(TokenStream tokens, Node owner)
        {
            Expression root;

            if (tokens.IsNext("++") || tokens.IsNext("--"))
            {
                Token incrementToken = tokens.Pop();
                root = this.ParseEntity(tokens, owner);
                return(new Increment(incrementToken, incrementToken, incrementToken.Value == "++", true, root, owner));
            }

            root = this.ParseEntity(tokens, owner);
            if (tokens.IsNext("++") || tokens.IsNext("--"))
            {
                Token incrementToken = tokens.Pop();
                return(new Increment(root.FirstToken, incrementToken, incrementToken.Value == "++", false, root, owner));
            }

            return(root);
        }
コード例 #3
0
        internal virtual AnnotationCollection ParseAnnotations(TokenStream tokens)
        {
            AnnotationCollection annotationCollection = new AnnotationCollection(this.parser);

            while (tokens.IsNext("@"))
            {
                annotationCollection.Add(this.ParseAnnotation(tokens));
            }

            annotationCollection.Validate();

            return(annotationCollection);
        }
コード例 #4
0
        public void ParseFile(string filename, string code)
        {
            FileScope fileScope = new FileScope(filename, code, this.CurrentScope, this.GetNextFileId());

            this.RegisterFileUsed(fileScope, code);
            TokenStream tokens = new TokenStream(fileScope);

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

            // Implicitly import the Core library for the current locale.
            LocalizedAssemblyView implicitCoreImport = this.ScopeManager.GetCoreLibrary(this);

            namespaceImportsBuilder.Add(implicitCoreImport.Name);
            fileScope.Imports.Add(new ImportStatement(null, implicitCoreImport.Name, fileScope));

            while (tokens.HasMore &&
                   (tokens.IsNext(this.Keywords.IMPORT) ||
                    (this.IsCSharpCompat && tokens.IsNext("using"))))
            {
                ImportStatement importStatement = this.TopLevelParser.ParseImport(tokens, fileScope);
                if (importStatement == null)
                {
                    throw new Exception();
                }
                namespaceImportsBuilder.Add(importStatement.ImportPath);
                LocalizedAssemblyView localizedAssemblyView = this.ScopeManager.GetOrImportAssembly(this, importStatement.FirstToken, importStatement.ImportPath);
                if (localizedAssemblyView == null)
                {
                    this.unresolvedImports.Add(importStatement);
                }
            }

            string[] namespaceImports = namespaceImportsBuilder.ToArray();

            while (tokens.HasMore)
            {
                this.CurrentScope.AddExecutable(this.TopLevelParser.Parse(tokens, null, fileScope));
            }
        }
コード例 #5
0
        public void ParseInterpretedCode(string filename, string code)
        {
            FileScope fileScope = new FileScope(filename, this.CurrentScope);
            int       fileId    = this.GetNextFileId();

            this.RegisterFileUsed(filename, code, fileId);
            Token[]     tokenList = Tokenizer.Tokenize(filename, code, fileId, true);
            TokenStream tokens    = new TokenStream(tokenList, filename);

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

            // Implicitly import the Core library for the current locale.
            LocalizedLibraryView implicitCoreImport = this.LibraryManager.GetCoreLibrary(this);

            namespaceImportsBuilder.Add(implicitCoreImport.Name);
            fileScope.Imports.Add(new ImportStatement(null, implicitCoreImport.Name, this.CurrentLibrary, fileScope));

            while (tokens.HasMore && tokens.IsNext(this.Keywords.IMPORT))
            {
                ImportStatement importStatement = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope) as ImportStatement;
                if (importStatement == null)
                {
                    throw new Exception();
                }
                namespaceImportsBuilder.Add(importStatement.ImportPath);
                LocalizedLibraryView localizedLibraryView = this.LibraryManager.GetOrImportLibrary(this, importStatement.FirstToken, importStatement.ImportPath);
                if (localizedLibraryView == null)
                {
                    this.unresolvedImports.Add(importStatement);
                }
            }

            string[] namespaceImports = namespaceImportsBuilder.ToArray();

            while (tokens.HasMore)
            {
                TopLevelConstruct executable = this.ExecutableParser.ParseTopLevel(tokens, null, fileScope);

                if (executable is ImportStatement)
                {
                    throw this.GenerateParseError(
                              ErrorMessages.ALL_IMPORTS_MUST_OCCUR_AT_BEGINNING_OF_FILE,
                              executable.FirstToken);
                }

                this.CurrentScope.AddExecutable(executable);
            }
        }
コード例 #6
0
        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));
        }
コード例 #7
0
        private Executable ParseSwitch(TokenStream tokens, TopLevelConstruct owner)
        {
            Token switchToken = tokens.PopExpected(this.parser.Keywords.SWITCH);

            Expression explicitMax      = null;
            Token      explicitMaxToken = null;

            if (tokens.IsNext("{"))
            {
                explicitMaxToken = tokens.Pop();
                explicitMax      = this.parser.ExpressionParser.Parse(tokens, owner);
                tokens.PopExpected("}");
            }

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

            tokens.PopExpected(")");
            tokens.PopExpected("{");
            List <List <Expression> > cases = new List <List <Expression> >();
            List <Token> firstTokens        = new List <Token>();
            List <List <Executable> > code  = new List <List <Executable> >();
            char state = '?'; // ? - first, O - code, A - case
            bool defaultEncountered = false;

            while (!tokens.PopIfPresent("}"))
            {
                if (tokens.IsNext(this.parser.Keywords.CASE))
                {
                    if (defaultEncountered)
                    {
                        throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition.");
                    }

                    Token caseToken = tokens.PopExpected(this.parser.Keywords.CASE);
                    if (state != 'A')
                    {
                        cases.Add(new List <Expression>());
                        firstTokens.Add(caseToken);
                        code.Add(null);
                        state = 'A';
                    }
                    cases[cases.Count - 1].Add(this.parser.ExpressionParser.Parse(tokens, owner));
                    tokens.PopExpected(":");
                }
                else if (tokens.IsNext(this.parser.Keywords.DEFAULT))
                {
                    Token defaultToken = tokens.PopExpected(this.parser.Keywords.DEFAULT);
                    if (state != 'A')
                    {
                        cases.Add(new List <Expression>());
                        firstTokens.Add(defaultToken);
                        code.Add(null);
                        state = 'A';
                    }
                    cases[cases.Count - 1].Add(null);
                    tokens.PopExpected(":");
                    defaultEncountered = true;
                }
                else
                {
                    if (state != 'O')
                    {
                        cases.Add(null);
                        firstTokens.Add(null);
                        code.Add(new List <Executable>());
                        state = 'O';
                    }
                    code[code.Count - 1].Add(this.parser.ExecutableParser.Parse(tokens, false, true, owner));
                }
            }

            return(new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner));
        }
コード例 #8
0
        private ClassDefinition ParseClassDefinition(TokenStream tokens, TopLevelConstruct owner, Token staticToken, Token finalToken, FileScope fileScope, AnnotationCollection classAnnotations)
        {
            Token classToken     = tokens.PopExpected(this.parser.Keywords.CLASS);
            Token classNameToken = tokens.Pop();

            this.parser.VerifyIdentifier(classNameToken);
            List <Token>  baseClassTokens  = new List <Token>();
            List <string> baseClassStrings = new List <string>();

            if (tokens.PopIfPresent(":"))
            {
                if (baseClassTokens.Count > 0)
                {
                    tokens.PopExpected(",");
                }

                Token  baseClassToken = tokens.Pop();
                string baseClassName  = baseClassToken.Value;

                this.parser.VerifyIdentifier(baseClassToken);
                while (tokens.PopIfPresent("."))
                {
                    Token baseClassTokenNext = tokens.Pop();
                    this.parser.VerifyIdentifier(baseClassTokenNext);
                    baseClassName += "." + baseClassTokenNext.Value;
                }

                baseClassTokens.Add(baseClassToken);
                baseClassStrings.Add(baseClassName);
            }

            ClassDefinition cd = new ClassDefinition(
                classToken,
                classNameToken,
                baseClassTokens,
                baseClassStrings,
                owner,
                parser.CurrentLibrary,
                staticToken,
                finalToken,
                fileScope,
                classAnnotations);

            tokens.PopExpected("{");
            List <FunctionDefinition> methods              = new List <FunctionDefinition>();
            List <FieldDeclaration>   fields               = new List <FieldDeclaration>();
            ConstructorDefinition     constructorDef       = null;
            ConstructorDefinition     staticConstructorDef = null;

            while (!tokens.PopIfPresent("}"))
            {
                AnnotationCollection annotations = this.parser.AnnotationParser.ParseAnnotations(tokens);

                if (tokens.IsNext(this.parser.Keywords.FUNCTION) ||
                    tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FUNCTION))
                {
                    methods.Add(this.parser.ExecutableParser.ParseFunction(tokens, cd, fileScope, annotations));
                }
                else if (tokens.IsNext(this.parser.Keywords.CONSTRUCTOR))
                {
                    if (constructorDef != null)
                    {
                        throw this.parser.GenerateParseError(
                                  ErrorMessages.CLASS_CANNOT_HAVE_MULTIPLE_CONSTRUCTORS,
                                  tokens.Pop());
                    }

                    constructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations);
                }
                else if (tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.CONSTRUCTOR))
                {
                    tokens.Pop(); // static token
                    if (staticConstructorDef != null)
                    {
                        throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed.");
                    }

                    staticConstructorDef = this.parser.ExecutableParser.ParseConstructor(tokens, cd, annotations);
                }
                else if (tokens.IsNext(this.parser.Keywords.FIELD) ||
                         tokens.AreNext(this.parser.Keywords.STATIC, this.parser.Keywords.FIELD))
                {
                    fields.Add(this.parser.ExecutableParser.ParseField(tokens, cd, annotations));
                }
                else
                {
                    tokens.PopExpected("}");
                }

                TODO.CheckForUnusedAnnotations();
            }

            cd.Methods           = methods.ToArray();
            cd.Constructor       = constructorDef;
            cd.StaticConstructor = staticConstructorDef;
            cd.Fields            = fields.ToArray();

            return(cd);
        }
コード例 #9
0
        private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Node owner)
        {
            tokens.EnsureNotEof();

            Token  nextToken = tokens.Peek();
            string next      = nextToken.Value;

            if (next == this.parser.Keywords.NULL)
            {
                return(new NullConstant(tokens.Pop(), owner));
            }
            if (next == this.parser.Keywords.TRUE)
            {
                return(new BooleanConstant(tokens.Pop(), true, owner));
            }
            if (next == this.parser.Keywords.FALSE)
            {
                return(new BooleanConstant(tokens.Pop(), false, owner));
            }
            if (next == this.parser.Keywords.THIS)
            {
                return(new ThisKeyword(tokens.Pop(), owner));
            }
            if (next == this.parser.Keywords.BASE)
            {
                return(new BaseKeyword(tokens.Pop(), owner));
            }

            Token peekToken = tokens.Peek();

            if (next.StartsWith("'"))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next.StartsWith("\""))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next == "@") // Raw strings (no escape sequences, a backslash is a literal backslash)
            {
                Token atToken         = tokens.Pop();
                Token stringToken     = tokens.Pop();
                char  stringTokenChar = stringToken.Value[0];
                if (stringTokenChar != '"' && stringTokenChar != '\'')
                {
                    throw new ParserException(atToken, "Unexpected token: '@'");
                }
                string stringValue = stringToken.Value.Substring(1, stringToken.Value.Length - 2);
                return(new StringConstant(atToken, stringValue, owner));
            }
            if (next == this.parser.Keywords.NEW)
            {
                return(this.ParseInstantiate(tokens, owner));
            }

            char firstChar = next[0];

            if (nextToken.Type == TokenType.WORD)
            {
                Token varToken = tokens.Pop();
                if (tokens.IsNext("=>"))
                {
                    return(this.ParseLambda(
                               tokens,
                               varToken,
                               new AType[] { AType.Any() },
                               new Token[] { varToken },
                               owner));
                }
                else
                {
                    return(new Variable(varToken, varToken.Value, owner));
                }
            }

            if (firstChar == '[' && nextToken.File.CompilationScope.IsCrayon)
            {
                Token             bracketToken = tokens.PopExpected("[");
                List <Expression> elements     = new List <Expression>();
                bool previousHasCommaOrFirst   = true;
                while (!tokens.PopIfPresent("]"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("]");                           // throws appropriate error
                    }
                    elements.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new ListDefinition(bracketToken, elements, AType.Any(), owner, false, null));
            }

            if (firstChar == '{' && nextToken.File.CompilationScope.IsCrayon)
            {
                Token             braceToken = tokens.PopExpected("{");
                List <Expression> keys       = new List <Expression>();
                List <Expression> values     = new List <Expression>();
                bool previousHasCommaOrFirst = true;
                while (!tokens.PopIfPresent("}"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("}");                           // throws appropriate error
                    }
                    keys.Add(Parse(tokens, owner));
                    tokens.PopExpected(":");
                    values.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new DictionaryDefinition(braceToken, AType.Any(), AType.Any(), keys, values, owner));
            }

            if (nextToken.Type == TokenType.NUMBER)
            {
                if (next.Contains("."))
                {
                    double floatValue;
                    if (double.TryParse(next, out floatValue))
                    {
                        return(new FloatConstant(tokens.Pop(), floatValue, owner));
                    }
                    throw new ParserException(nextToken, "Invalid float literal.");
                }
                return(new IntegerConstant(
                           tokens.Pop(),
                           IntegerConstant.ParseIntConstant(nextToken, next),
                           owner));
            }

            throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'");
        }
コード例 #10
0
        private Expression ParseEntity(TokenStream tokens, Node owner)
        {
            Expression root;
            Token      firstToken = tokens.Peek();
            AType      castPrefix = firstToken.Value == "(" ? this.MaybeParseCastPrefix(tokens) : null;

            if (castPrefix != null)
            {
                root = this.ParseEntity(tokens, owner);
                return(new Cast(firstToken, castPrefix, root, owner, true));
            }

            Token maybeOpenParen = tokens.Peek();

            if (tokens.PopIfPresent("("))
            {
                if (tokens.PopIfPresent(")"))
                {
                    root = this.ParseLambda(tokens, firstToken, new AType[0], new Token[0], owner);
                }
                else
                {
                    if (this.parser.CurrentScope.IsStaticallyTyped)
                    {
                        TokenStream.StreamState state = tokens.RecordState();
                        AType lambdaArgType           = this.parser.TypeParser.TryParse(tokens);
                        Token lambdaArg = null;
                        if (lambdaArgType != null)
                        {
                            lambdaArg = tokens.PopIfWord();
                        }

                        if (lambdaArg != null)
                        {
                            List <AType> lambdaArgTypes = new List <AType>()
                            {
                                lambdaArgType
                            };
                            List <Token> lambdaArgs = new List <Token>()
                            {
                                lambdaArg
                            };
                            while (tokens.PopIfPresent(","))
                            {
                                lambdaArgTypes.Add(this.parser.TypeParser.Parse(tokens));
                                lambdaArgs.Add(tokens.PopWord());
                            }
                            tokens.PopExpected(")");
                            return(this.ParseLambda(tokens, maybeOpenParen, lambdaArgTypes, lambdaArgs, owner));
                        }
                        else
                        {
                            tokens.RestoreState(state);
                        }
                    }

                    root = this.Parse(tokens, owner);
                    if (root is Variable)
                    {
                        if (tokens.PopIfPresent(")"))
                        {
                            if (tokens.IsNext("=>"))
                            {
                                root = this.ParseLambda(tokens, firstToken, new AType[] { AType.Any(root.FirstToken) }, new Token[] { root.FirstToken }, owner);
                            }
                        }
                        else if (tokens.IsNext(","))
                        {
                            List <Token> lambdaArgs = new List <Token>()
                            {
                                root.FirstToken
                            };
                            List <AType> lambdaArgTypes = new List <AType>()
                            {
                                AType.Any(root.FirstToken)
                            };
                            Token comma = tokens.Peek();
                            while (tokens.PopIfPresent(","))
                            {
                                Token nextArg = tokens.Pop();
                                if (nextArg.Type != TokenType.WORD)
                                {
                                    throw new ParserException(comma, "Unexpected comma.");
                                }
                                lambdaArgTypes.Add(AType.Any(nextArg));
                                lambdaArgs.Add(nextArg);
                                comma = tokens.Peek();
                            }
                            tokens.PopExpected(")");

                            root = this.ParseLambda(tokens, firstToken, lambdaArgTypes, lambdaArgs, owner);
                        }
                        else
                        {
                            // This will purposely cause an unexpected token error
                            // since it's none of the above conditions.
                            tokens.PopExpected(")");
                        }
                    }
                    else
                    {
                        tokens.PopExpected(")");
                    }
                }
            }
            else
            {
                root = ParseEntityWithoutSuffixChain(tokens, owner);
            }
            bool anySuffixes    = true;
            bool isPreviousADot = false;

            while (anySuffixes)
            {
                if (tokens.IsNext("."))
                {
                    isPreviousADot = true;
                    Token dotToken   = tokens.Pop();
                    Token fieldToken = tokens.Pop();
                    // HACK alert: "class" is a valid field on a class.
                    // ParserVerifyIdentifier is invoked downstream for non-resolved fields.
                    if (fieldToken.Value != this.parser.Keywords.CLASS)
                    {
                        this.parser.VerifyIdentifier(fieldToken);
                    }
                    root = new DotField(root, dotToken, fieldToken, owner);
                }
                else if (tokens.IsNext("["))
                {
                    Token             openBracket     = tokens.Pop();
                    List <Expression> sliceComponents = new List <Expression>();
                    if (tokens.IsNext(":"))
                    {
                        sliceComponents.Add(null);
                    }
                    else
                    {
                        sliceComponents.Add(Parse(tokens, owner));
                    }

                    for (int i = 0; i < 2; ++i)
                    {
                        if (tokens.PopIfPresent(":"))
                        {
                            if (tokens.IsNext(":") || tokens.IsNext("]"))
                            {
                                sliceComponents.Add(null);
                            }
                            else
                            {
                                sliceComponents.Add(Parse(tokens, owner));
                            }
                        }
                    }

                    tokens.PopExpected("]");

                    if (sliceComponents.Count == 1)
                    {
                        Expression index = sliceComponents[0];
                        root = new BracketIndex(root, openBracket, index, owner);
                    }
                    else
                    {
                        root = new ListSlice(root, sliceComponents, openBracket, owner);
                    }
                }
                else if (tokens.IsNext("("))
                {
                    Token             openParen = tokens.Pop();
                    List <Expression> args      = new List <Expression>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (args.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }

                        args.Add(Parse(tokens, owner));
                    }
                    root = new FunctionCall(root, openParen, args, owner);
                }
                else if (tokens.IsNext(this.parser.Keywords.IS))
                {
                    Token  isToken    = tokens.Pop();
                    Token  classToken = tokens.Pop();
                    string className  = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken);
                    root = new IsComparison(root, isToken, classToken, className, owner);
                }
                else if (isPreviousADot && this.parser.IsCSharpCompat && tokens.IsNext("<"))
                {
                    TokenStream.StreamState s = tokens.RecordState();
                    Token openBracket         = tokens.Pop();
                    AType funcType            = this.parser.TypeParser.TryParse(tokens);

                    List <AType> types = new List <AType>()
                    {
                        funcType
                    };
                    if (funcType != null)
                    {
                        while (tokens.PopIfPresent(","))
                        {
                            types.Add(this.parser.TypeParser.Parse(tokens));
                        }
                    }

                    if (funcType == null)
                    {
                        anySuffixes = false;
                        tokens.RestoreState(s);
                    }
                    else if (!tokens.PopIfPresent(">") || !tokens.IsNext("("))
                    {
                        anySuffixes = false;
                        tokens.RestoreState(s);
                    }
                    else
                    {
                        // TODO(acrylic-conversion): do something with this types list.
                    }
                }
                else
                {
                    anySuffixes = false;
                }
            }
            return(root);
        }
コード例 #11
0
        private Expression ParseEntityWithoutSuffixChain(TokenStream tokens, TopLevelConstruct owner)
        {
            string next = tokens.PeekValue();

            if (next == null)
            {
                tokens.ThrowEofException();
            }
            if (next == this.parser.Keywords.NULL)
            {
                return(new NullConstant(tokens.Pop(), owner));
            }
            if (next == this.parser.Keywords.TRUE)
            {
                return(new BooleanConstant(tokens.Pop(), true, owner));
            }
            if (next == this.parser.Keywords.FALSE)
            {
                return(new BooleanConstant(tokens.Pop(), false, owner));
            }

            Token peekToken = tokens.Peek();

            if (next.StartsWith("'"))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next.StartsWith("\""))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next == this.parser.Keywords.NEW)
            {
                return(this.ParseInstantiate(tokens, owner));
            }

            char firstChar = next[0];

            if (VARIABLE_STARTER.Contains(firstChar))
            {
                Token varToken = tokens.Pop();
                return(new Variable(varToken, varToken.Value, owner));
            }

            if (firstChar == '[')
            {
                Token             bracketToken = tokens.PopExpected("[");
                List <Expression> elements     = new List <Expression>();
                bool previousHasCommaOrFirst   = true;
                while (!tokens.PopIfPresent("]"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("]");                           // throws appropriate error
                    }
                    elements.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new ListDefinition(bracketToken, elements, owner));
            }

            if (firstChar == '{')
            {
                Token             braceToken = tokens.PopExpected("{");
                List <Expression> keys       = new List <Expression>();
                List <Expression> values     = new List <Expression>();
                bool previousHasCommaOrFirst = true;
                while (!tokens.PopIfPresent("}"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("}");                           // throws appropriate error
                    }
                    keys.Add(Parse(tokens, owner));
                    tokens.PopExpected(":");
                    values.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new DictionaryDefinition(braceToken, keys, values, owner));
            }

            if (next.Length > 2 && next.Substring(0, 2) == "0x")
            {
                Token intToken = tokens.Pop();
                int   intValue = IntegerConstant.ParseIntConstant(intToken, intToken.Value);
                return(new IntegerConstant(intToken, intValue, owner));
            }

            if (ParserContext.IsInteger(next))
            {
                Token  numberToken = tokens.Pop();
                string numberValue = numberToken.Value;

                if (tokens.IsNext("."))
                {
                    Token decimalToken = tokens.Pop();
                    if (decimalToken.HasWhitespacePrefix)
                    {
                        throw new ParserException(decimalToken, "Decimals cannot have whitespace before them.");
                    }

                    Token afterDecimal = tokens.Pop();
                    if (afterDecimal.HasWhitespacePrefix)
                    {
                        throw new ParserException(afterDecimal, "Cannot have whitespace after the decimal.");
                    }
                    if (!ParserContext.IsInteger(afterDecimal.Value))
                    {
                        throw new ParserException(afterDecimal, "Decimal must be followed by an integer.");
                    }

                    numberValue += "." + afterDecimal.Value;

                    double floatValue = FloatConstant.ParseValue(numberToken, numberValue);
                    return(new FloatConstant(numberToken, floatValue, owner));
                }

                int intValue = IntegerConstant.ParseIntConstant(numberToken, numberToken.Value);
                return(new IntegerConstant(numberToken, intValue, owner));
            }

            if (tokens.IsNext("."))
            {
                Token  dotToken    = tokens.PopExpected(".");
                string numberValue = "0.";
                Token  postDecimal = tokens.Pop();
                if (postDecimal.HasWhitespacePrefix || !ParserContext.IsInteger(postDecimal.Value))
                {
                    throw new ParserException(dotToken, "Unexpected dot.");
                }

                numberValue += postDecimal.Value;

                double floatValue;
                if (Util.ParseDouble(numberValue, out floatValue))
                {
                    return(new FloatConstant(dotToken, floatValue, owner));
                }

                throw new ParserException(dotToken, "Invalid float literal.");
            }

            throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'");
        }
コード例 #12
0
        private Expression ParseEntity(TokenStream tokens, TopLevelConstruct owner)
        {
            Expression root;

            if (tokens.PopIfPresent("("))
            {
                root = this.Parse(tokens, owner);
                tokens.PopExpected(")");
            }
            else
            {
                root = ParseEntityWithoutSuffixChain(tokens, owner);
            }
            bool anySuffixes = true;

            while (anySuffixes)
            {
                if (tokens.IsNext("."))
                {
                    Token dotToken  = tokens.Pop();
                    Token stepToken = tokens.Pop();
                    // HACK alert: "class" is a valid field on a class.
                    // ParserVerifyIdentifier is invoked downstream for non-resolved fields.
                    if (stepToken.Value != this.parser.Keywords.CLASS)
                    {
                        this.parser.VerifyIdentifier(stepToken);
                    }
                    root = new DotStep(root, dotToken, stepToken, owner);
                }
                else if (tokens.IsNext("["))
                {
                    Token             openBracket     = tokens.Pop();
                    List <Expression> sliceComponents = new List <Expression>();
                    if (tokens.IsNext(":"))
                    {
                        sliceComponents.Add(null);
                    }
                    else
                    {
                        sliceComponents.Add(Parse(tokens, owner));
                    }

                    for (int i = 0; i < 2; ++i)
                    {
                        if (tokens.PopIfPresent(":"))
                        {
                            if (tokens.IsNext(":") || tokens.IsNext("]"))
                            {
                                sliceComponents.Add(null);
                            }
                            else
                            {
                                sliceComponents.Add(Parse(tokens, owner));
                            }
                        }
                    }

                    tokens.PopExpected("]");

                    if (sliceComponents.Count == 1)
                    {
                        Expression index = sliceComponents[0];
                        root = new BracketIndex(root, openBracket, index, owner);
                    }
                    else
                    {
                        root = new ListSlice(root, sliceComponents, openBracket, owner);
                    }
                }
                else if (tokens.IsNext("("))
                {
                    Token             openParen = tokens.Pop();
                    List <Expression> args      = new List <Expression>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (args.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }

                        args.Add(Parse(tokens, owner));
                    }
                    root = new FunctionCall(root, openParen, args, owner);
                }
                else if (tokens.IsNext(this.parser.Keywords.IS))
                {
                    Token  isToken    = tokens.Pop();
                    Token  classToken = tokens.Pop();
                    string className  = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken);
                    root = new IsComparison(root, isToken, classToken, className, owner);
                }
                else
                {
                    anySuffixes = false;
                }
            }
            return(root);
        }