Ejemplo n.º 1
0
        public static ExpressionToken TryParse(Scope scope, IEnumerable <string> endTokens,
                                               WordTokenCallback wordCallback = null, DataType expectedDataType = null)
        {
            var code = scope.Code;

            code.SkipWhiteSpace();
            var startPos = code.Position;

            // Statement breaking tokens
            if (code.PeekExact(';') || code.PeekExact('{') || code.PeekExact('}'))
            {
                return(null);
            }

            // Caller-specific end tokens
            if (endTokens != null)
            {
                code.Peek();
                if (endTokens.Contains(code.Text))
                {
                    return(null);
                }
            }

            var exp = new ExpressionToken(scope);

            var dataTypeArgs = new DataType.ParseArgs
            {
                Code             = code,
                DataTypeCallback = (name) =>
                {
                    return(scope.DefinitionProvider.GetAny <DataTypeDefinition>(code.Position, name).FirstOrDefault());
                },
                VariableCallback = (name) =>
                {
                    return(scope.DefinitionProvider.GetLocal <VariableDefinition>(code.Position, name).FirstOrDefault());
                },
                Scope = scope,
                TokenCreateCallback = (token) =>
                {
                    exp.AddToken(token);
                },
                VisibleModel = true
            };

            var abortParsing  = false;
            var parseDataType = expectedDataType;

            while (!code.EndOfFile && !abortParsing)
            {
                // Statement breaking tokens
                if (code.PeekExact(';') || code.PeekExact('{') || code.PeekExact('}'))
                {
                    break;
                }
                if (endTokens != null && code.Peek() && endTokens.Contains(code.Text))
                {
                    break;
                }

                if (!code.Read())
                {
                    break;
                }

                switch (code.Type)
                {
                case CodeType.Word:
                {
                    var word     = code.Text;
                    var wordSpan = code.Span;

                    Token token;
                    if (wordCallback != null && (token = wordCallback(word, wordSpan)) != null)
                    {
                        exp.AddToken(token);
                    }
                    else if (parseDataType != null && parseDataType.HasCompletionOptions && parseDataType.IsValidEnumOption(word))
                    {
                        exp.AddToken(new EnumOptionToken(scope, wordSpan, word, parseDataType));
                    }
                    else
                    {
                        var oldPos = code.Position;
                        code.Position = wordSpan.Start;                                         // DataType.TryParse() needs to be before the first word
                        var dt = DataType.TryParse(dataTypeArgs);
                        if (dt == null)
                        {
                            code.Position = oldPos;
                            var wordToken = ProcessWord(exp, scope, word, wordSpan);
                            if (wordToken != null)
                            {
                                exp.AddToken(wordToken);
                            }
                            else
                            {
                                code.Position = wordSpan.Start;
                                abortParsing  = true;
                            }
                        }
                    }
                }
                break;

                case CodeType.Number:
                    exp.AddToken(new NumberToken(scope, code.Span, code.Text));
                    break;

                case CodeType.StringLiteral:
                    if (parseDataType != null && parseDataType.HasCompletionOptions && parseDataType.IsValidEnumOption(code.Text))
                    {
                        exp.AddToken(new EnumOptionToken(scope, code.Span, code.Text, parseDataType));
                    }
                    else
                    {
                        exp.AddToken(new StringLiteralToken(scope, code.Span, code.Text));
                    }
                    break;

                case CodeType.Operator:
                    switch (code.Text)
                    {
                    case "(":
                    {
                        code.Position = code.Span.Start;
                        var bracketsToken = BracketsToken.Parse(scope, parseDataType);
                        if (bracketsToken.IsCast)
                        {
                            exp.AddToken(Statements.CastStatement.Parse(scope, bracketsToken, endTokens));
                        }
                        else
                        {
                            exp.AddToken(bracketsToken);
                        }
                    }
                    break;

                    case "{":
                        code.Position = code.Span.Start;
                        exp.AddToken(BracesToken.Parse(scope, null));
                        break;

                    case "[":
                        code.Position = code.Span.Start;
                        exp.AddToken(ArrayBracesToken.Parse(scope));
                        break;

                    case ",":
                        exp.AddToken(new DelimiterToken(scope, code.Span));
                        break;

                    case ".":
                        exp.AddToken(new DotToken(scope, code.Span));
                        break;

                    case "&":
                        exp.AddToken(new ReferenceToken(scope, code.Span));
                        break;

                    case "==":
                    case "!=":
                    case "<":
                    case "<=":
                    case ">":
                    case ">=":
                        if ((scope.Hint & ScopeHint.SuppressLogic) == 0)
                        {
                            if (exp.ChildrenCount > 0)
                            {
                                var dataType = exp.LastChild.ValueDataType;
                                if (dataType != null)
                                {
                                    parseDataType = dataType;
                                }
                            }
                            exp.AddToken(ComparisonOperator.Parse(scope, exp.LastChild, new OperatorToken(scope, code.Span, code.Text), endTokens));
                        }
                        else
                        {
                            exp.AddToken(new OperatorToken(scope, code.Span, code.Text));
                        }
                        break;

                    case "=":
                        if ((scope.Hint & ScopeHint.SuppressLogic) == 0)
                        {
                            if (exp.ChildrenCount > 0)
                            {
                                var dataType = exp.LastChild.ValueDataType;
                                if (dataType != null)
                                {
                                    parseDataType = dataType;
                                }
                            }
                            exp.AddToken(AssignmentOperator.Parse(scope, exp.LastChild, new OperatorToken(scope, code.Span, code.Text), endTokens));
                        }
                        else
                        {
                            exp.AddToken(new OperatorToken(scope, code.Span, code.Text));
                        }
                        break;

                    case "+=":
                    case "-=":
                    case "*=":
                    case "/=":
                    case "%=":
                        if ((scope.Hint & ScopeHint.SuppressLogic) == 0)
                        {
                            exp.AddToken(AssignmentOperator.Parse(scope, exp.LastChild, new OperatorToken(scope, code.Span, code.Text), endTokens));
                        }
                        else
                        {
                            exp.AddToken(new OperatorToken(scope, code.Span, code.Text));
                        }
                        break;

                    case "?":
                        parseDataType = expectedDataType;
                        exp.AddToken(ConditionalOperator.Parse(scope, exp.LastChild, new OperatorToken(scope, code.Span, code.Text),
                                                               endTokens, parseDataType));
                        break;

                    default:
                        exp.AddToken(new OperatorToken(scope, code.Span, code.Text));
                        break;
                    }
                    break;

                case CodeType.Preprocessor:
                    exp.AddToken(new PreprocessorToken(scope, code.Span, code.Text));
                    break;

                default:
                    exp.AddToken(new UnknownToken(scope, code.Span, code.Text));
                    break;
                }
            }

            if (exp.ChildrenCount == 0)
            {
                return(null);
            }
            return(exp);
        }