예제 #1
0
        public static CSharpType TryParse(TokenStream tokens)
        {
            tokens.SetTypeParsingMode(true);
            CSharpType type = TryParseImpl(tokens, true);

            tokens.SetTypeParsingMode(false);
            return(type);
        }
예제 #2
0
        public static CSharpType ParseWithoutNullable(TokenStream tokens)
        {
            CSharpType type = TryParseWithoutNullable(tokens);

            if (type == null)
            {
                throw new ParserException(tokens.Peek(), "Expected a type.");
            }
            return(type);
        }
예제 #3
0
        public static TopLevelEntity ParseClassMember(
            ClassLikeDefinition classDef,
            Token className,
            ParserContext context,
            TokenStream tokens)
        {
            Token firstToken = tokens.Peek();
            Dictionary <string, Token> modifiers = ParseModifiers(context, tokens);

            if (tokens.IsNext("enum"))
            {
                return(ParseEnumDefinition(context, classDef, firstToken, modifiers, tokens));
            }

            if (tokens.IsNext("class"))
            {
                return(ParseClass(context, classDef, firstToken, modifiers, tokens));
            }

            if (tokens.IsNext("const"))
            {
                return(ParseConstDefinition(context, classDef, firstToken, modifiers, tokens));
            }

            CSharpType type = CSharpType.TryParse(tokens);

            if (tokens.IsNext("(") && type.SimpleTypeName == className.Value)
            {
                return(ParseClassConstructor(context, classDef, firstToken, modifiers, type, tokens));
            }

            Token memberName = tokens.PopWord();

            if (tokens.IsNext(";") || tokens.IsNext("="))
            {
                return(ParseClassField(context, classDef, firstToken, modifiers, type, memberName, tokens));
            }

            if (tokens.IsNext("[") && memberName.Value == "this")
            {
                return(ParseIndexProperty(context, classDef, firstToken, modifiers, type, tokens));
            }

            if (tokens.IsNext("{"))
            {
                return(ParseClassProperty(context, classDef, firstToken, modifiers, type, memberName, tokens));
            }

            if (tokens.IsNext("("))
            {
                return(ParseClassMethod(classDef, context, firstToken, modifiers, type, memberName, tokens));
            }

            throw new ParserException(tokens.Peek(), "Not implemented");
        }
예제 #4
0
        private static TopLevelEntity ParseIndexProperty(
            ParserContext context,
            ClassLikeDefinition parent,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            CSharpType type,
            TokenStream tokens)
        {
            tokens.PopExpected("[");
            CSharpType indexType         = CSharpType.Parse(tokens);
            Token      indexVariableName = tokens.PopWord();

            tokens.PopExpected("]");
            tokens.PopExpected("{");

            PropertyDefinition indexProperty = new PropertyDefinition(firstToken, modifiers, type, null, parent);

            PropertyBody getter = null;
            PropertyBody setter = null;

            while (tokens.IsNext("get") || tokens.IsNext("set"))
            {
                Token getOrSetToken = tokens.Peek();
                bool  isGet         = getOrSetToken.Value == "get";
                if (!isGet && setter != null)
                {
                    tokens.PopExpected("}");                           // intentionally throw
                }
                if (isGet && getter != null)
                {
                    tokens.PopExpected("set"); //intentionally throw
                }
                tokens.Pop();                  // get/set already fetched with Peek() above.
                PropertyBody body = new PropertyBody(getOrSetToken, new Dictionary <string, Token>(), isGet, indexProperty);
                Executable[] code = ExecutableParser.ParseCodeBlock(context, tokens, body, true);
                body.Code = code;
                if (isGet)
                {
                    getter = body;
                }
                else
                {
                    setter = body;
                }
            }

            indexProperty.IndexType         = indexType;
            indexProperty.IndexVariableName = indexVariableName;

            indexProperty.Getter = getter;
            indexProperty.Setter = setter;

            return(indexProperty);
        }
예제 #5
0
        private static TopLevelEntity ParseClassProperty(
            ParserContext context,
            ClassLikeDefinition parent,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            CSharpType type,
            Token propertyName,
            TokenStream tokens)
        {
            tokens.PopExpected("{");

            PropertyDefinition propertyDefinition = new PropertyDefinition(firstToken, modifiers, type, propertyName, parent);

            PropertyBody getter = null;
            PropertyBody setter = null;

            while (!tokens.IsNext("}") && (getter == null || setter == null))
            {
                Token bodyFirstToken = tokens.Peek();
                Dictionary <string, Token> bodyModifiers = ParseModifiers(context, tokens);
                if (tokens.IsNext("get") && getter == null)
                {
                    Token getToken = tokens.Pop();
                    getter = new PropertyBody(bodyFirstToken, bodyModifiers, true, propertyDefinition);
                    if (!tokens.PopIfPresent(";"))
                    {
                        getter.Code = ExecutableParser.ParseCodeBlock(context, tokens, getter, true);
                    }
                }
                else if (tokens.IsNext("set") && setter == null)
                {
                    Token setToken = tokens.Pop();
                    setter = new PropertyBody(bodyFirstToken, bodyModifiers, false, propertyDefinition);
                    if (!tokens.PopIfPresent(";"))
                    {
                        setter.Code = ExecutableParser.ParseCodeBlock(context, tokens, setter, true);
                    }
                }
                else if (getter == null)
                {
                    tokens.PopExpected("get"); // intentionally throw
                }
                else
                {
                    tokens.PopExpected("set"); // intentionally throw
                }
            }
            tokens.PopExpected("}");

            propertyDefinition.Getter = getter;
            propertyDefinition.Setter = setter;

            return(propertyDefinition);
        }
예제 #6
0
 private static CSharpType ParseOutArraySuffix(CSharpType current, TokenStream tokens)
 {
     while (tokens.AreNext("[", "]"))
     {
         Token openBracket = tokens.Pop();
         tokens.Pop();
         Token firstToken = current.FirstToken;
         current            = new CSharpType(new Token[] { openBracket }, new CSharpType[] { current });
         current.FirstToken = firstToken;
     }
     return(current);
 }
예제 #7
0
        private static Executable ParseForEachLoop(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Token foreachToken = tokens.PopExpected("foreach");

            tokens.PopExpected("(");
            CSharpType type          = CSharpType.Parse(tokens);
            Token      variableToken = tokens.PopWord();

            tokens.PopExpected("in");
            Expression listExpression = ExpressionParser.Parse(context, tokens, parent);

            tokens.PopExpected(")");
            Executable[] loopBody = ParseCodeBlock(context, tokens, parent, false);
            return(new ForEachLoop(foreachToken, type, variableToken, listExpression, loopBody, parent));
        }
예제 #8
0
        private static Executable ParseTryStatement(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Token tryToken = tokens.PopExpected("try");

            Executable[] tryCode = ExecutableParser.ParseCodeBlock(context, tokens, parent, true);

            List <Token>        catchTokens         = new List <Token>();
            List <CSharpType>   catchBlockTypes     = new List <CSharpType>();
            List <Token>        catchBlockVariables = new List <Token>();
            List <Executable[]> catchBlockCode      = new List <Executable[]>();
            Token finallyToken = null;

            Executable[] finallyCode = null;

            while (tokens.IsNext("catch"))
            {
                catchTokens.Add(tokens.Pop());
                tokens.PopExpected("(");
                catchBlockTypes.Add(CSharpType.Parse(tokens));
                if (!tokens.PopIfPresent(")"))
                {
                    catchBlockVariables.Add(tokens.PopWord());
                    tokens.PopExpected(")");
                }
                else
                {
                    catchBlockVariables.Add(null);
                }
                catchBlockCode.Add(ParseCodeBlock(context, tokens, parent, true));
            }

            if (tokens.IsNext("finally"))
            {
                finallyToken = tokens.Pop();
                finallyCode  = ParseCodeBlock(context, tokens, parent, true);
            }

            return(new TryStatement(
                       tryToken,
                       tryCode,
                       catchTokens,
                       catchBlockTypes,
                       catchBlockVariables,
                       catchBlockCode,
                       finallyToken,
                       finallyCode,
                       parent));
        }
예제 #9
0
        private static TopLevelEntity ParseClassConstructor(
            ParserContext context,
            ClassLikeDefinition classDef,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            CSharpType type,
            TokenStream tokens)
        {
            List <CSharpType> argTypes     = new List <CSharpType>();
            List <Token>      argNames     = new List <Token>();
            List <Token>      argModifiers = new List <Token>();

            ParseArgList(argTypes, argNames, argModifiers, tokens);

            ConstructorDefinition constructorDef = new ConstructorDefinition(
                firstToken,
                modifiers,
                argTypes,
                argNames,
                argModifiers,
                classDef);

            if (tokens.PopIfPresent(":"))
            {
                if (!tokens.IsNext("base") && !tokens.IsNext("this"))
                {
                    tokens.PopExpected("base"); // intentionally throw
                }
                constructorDef.BaseConstructorInvocation = tokens.Pop();

                tokens.PopExpected("(");
                List <Expression> baseConstructorArgs = new List <Expression>();
                while (!tokens.PopIfPresent(")"))
                {
                    if (baseConstructorArgs.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    baseConstructorArgs.Add(ExpressionParser.Parse(context, tokens, constructorDef));
                }
                constructorDef.BaseConstructorArgs = baseConstructorArgs.ToArray();
            }

            constructorDef.Code = ExecutableParser.ParseCodeBlock(context, tokens, constructorDef, true);

            return(constructorDef);
        }
예제 #10
0
        private static TopLevelEntity ParseConstDefinition(
            ParserContext context,
            TopLevelEntity parent,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            TokenStream tokens)
        {
            Token      constToken = tokens.PopExpected("const");
            CSharpType constType  = CSharpType.Parse(tokens);
            Token      name       = tokens.PopWord();

            tokens.PopExpected("=");
            ConstDefinition constDef = new ConstDefinition(firstToken, modifiers, constType, name, parent);
            Expression      value    = ExpressionParser.Parse(context, tokens, constDef);

            tokens.PopExpected(";");
            constDef.Value = value;
            return(constDef);
        }
예제 #11
0
        public static ClassLikeDefinition ParseClass(ParserContext context, TopLevelEntity parent, Token firstToken, Dictionary <string, Token> modifiers, TokenStream tokens)
        {
            if (!tokens.IsNext("class") && !tokens.IsNext("interface"))
            {
                tokens.PopExpected("class"); // intentionally throw
            }
            Token classToken  = tokens.Pop();
            bool  isInterface = classToken.Value == "interface";

            Token             classNameToken    = tokens.PopWord();
            List <CSharpType> subClassesAndSuch = new List <CSharpType>();

            if (tokens.PopIfPresent(":"))
            {
                while (!tokens.IsNext("{"))
                {
                    if (subClassesAndSuch.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    subClassesAndSuch.Add(CSharpType.Parse(tokens));
                }
            }

            tokens.PopExpected("{");
            ClassLikeDefinition cd;

            if (isInterface)
            {
                cd = new InterfaceDefinition(firstToken, modifiers, classToken, classNameToken, subClassesAndSuch, parent);
            }
            else
            {
                cd = new ClassDefinition(firstToken, modifiers, classToken, classNameToken, subClassesAndSuch, parent);
            }

            while (!tokens.PopIfPresent("}"))
            {
                TopLevelEntity classMember = ParseClassMember(cd, classNameToken, context, tokens);
                cd.AddMember(classMember);
            }
            return(cd);
        }
예제 #12
0
        private static TopLevelEntity ParseClassField(
            ParserContext context,
            ClassLikeDefinition parent,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            CSharpType type,
            Token fieldName,
            TokenStream tokens)
        {
            FieldDefinition fieldDef = new FieldDefinition(firstToken, modifiers, type, fieldName, null, parent);

            if (!tokens.PopIfPresent(";"))
            {
                tokens.PopExpected("=");
                Expression initialValue = ExpressionParser.Parse(context, tokens, fieldDef);
                tokens.PopExpected(";");
                fieldDef.InitialValue = initialValue;
            }
            return(fieldDef);
        }
예제 #13
0
        private static Executable ParseUsingStatement(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Token usingToken = tokens.PopExpected("using");

            tokens.PopExpected("(");
            CSharpType type        = null;
            Token      variable    = null;
            Token      equalsToken = null;

            if (!tokens.IsNext("new"))
            {
                type        = CSharpType.Parse(tokens);
                variable    = tokens.PopWord();
                equalsToken = tokens.PopExpected("=");
            }
            Expression expression = ExpressionParser.Parse(context, tokens, parent);

            tokens.PopExpected(")");
            Executable[] code = ExecutableParser.ParseCodeBlock(context, tokens, parent, false);
            return(new UsingStatement(usingToken, type, variable, expression, code, parent));
        }
예제 #14
0
        private static void ParseArgList(List <CSharpType> typesOut, List <Token> namesOut, List <Token> modifiers, TokenStream tokens)
        {
            tokens.PopExpected("(");

            while (!tokens.IsNext(")"))
            {
                if (namesOut.Count > 0)
                {
                    tokens.PopExpected(",");
                }
                if (tokens.IsNext("params") || tokens.IsNext("out"))
                {
                    modifiers.Add(tokens.Pop());
                }
                else
                {
                    modifiers.Add(null);
                }
                typesOut.Add(CSharpType.Parse(tokens));
                namesOut.Add(tokens.PopWord());
            }
            tokens.PopExpected(")");
        }
예제 #15
0
        private static TopLevelEntity ParseClassMethod(
            ClassLikeDefinition classDef,
            ParserContext context,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            CSharpType returnType,
            Token methodName,
            TokenStream tokens)
        {
            List <CSharpType> argTypes     = new List <CSharpType>();
            List <Token>      argNames     = new List <Token>();
            List <Token>      argModifiers = new List <Token>();

            ParseArgList(argTypes, argNames, argModifiers, tokens);

            MethodDefinition methodDef = new MethodDefinition(
                firstToken,
                modifiers,
                returnType,
                methodName,
                argNames,
                argTypes,
                argModifiers,
                classDef);

            if (methodDef.IsAbstract || classDef is InterfaceDefinition)
            {
                tokens.PopExpected(";");
            }
            else
            {
                methodDef.Code = ExecutableParser.ParseCodeBlock(context, tokens, methodDef, true);
            }

            return(methodDef);
        }
예제 #16
0
        // this function is called after the first ( is popped off the token stream.
        // It is destructive to the token stream.
        private static ParenthesisSituation IdentifyParenthesisSituationImpl(TokenStream tokens)
        {
            int state = tokens.CurrentState;

            // if any of these cause an EOF exception, it's a legit EOF exception.
            // The }'s alone for any body of code that an expression can appear in would be enough padding
            // to avoid non-legit errors.
            Token t1 = tokens.Pop();
            Token t2 = tokens.Pop();
            Token t3 = tokens.Pop();

            if (!t1.IsIdentifier)
            {
                return(ParenthesisSituation.WRAPPED_EXPRESSION);
            }
            if (t2.Value == ",")
            {
                return(ParenthesisSituation.LAMBDA_ARG);
            }
            if (t2.Value == ")" && t3.Value == "=>")
            {
                return(ParenthesisSituation.LAMBDA_ARG);
            }

            if (t2.Value == ")")
            {
                switch (t1.Value)
                {
                case "string":
                case "int":
                case "float":
                case "double":
                case "bool":
                case "object":
                case "byte":
                case "char":
                case "long":
                    return(ParenthesisSituation.CAST);
                }
            }

            tokens.RestoreState(state);

            CSharpType type = CSharpType.TryParse(tokens);

            if (type == null || !tokens.IsNext(")"))
            {
                return(ParenthesisSituation.WRAPPED_EXPRESSION);
            }
            if (type.Generics.Length > 0)
            {
                return(ParenthesisSituation.CAST);
            }
            if (!tokens.PopIfPresent(")"))
            {
                return(ParenthesisSituation.WRAPPED_EXPRESSION);
            }
            if (!tokens.HasMore)
            {
                return(ParenthesisSituation.WRAPPED_EXPRESSION);
            }
            // At this point you have a sequence words and dots in parentheses.
            Token next = tokens.Peek();

            if (next.IsIdentifier || next.IsNumber)
            {
                return(ParenthesisSituation.CAST);
            }
            char c = next.Value[0];

            if (c == '(')
            {
                return(ParenthesisSituation.CAST);
            }
            if (c == '@')
            {
                return(ParenthesisSituation.CAST);
            }
            if (c == '.')
            {
                return(ParenthesisSituation.WRAPPED_EXPRESSION);
            }
            if (c == '!')
            {
                return(ParenthesisSituation.CAST);
            }
            return(ParenthesisSituation.WRAPPED_EXPRESSION);
        }
예제 #17
0
        public static ResolvedType Create(CSharpType type, string[] prefixes, ParserContext context)
        {
            ResolvedType[] generics = EMPTY_GENERICS;
            if (type.Generics.Length > 0)
            {
                generics = type.Generics.Select(g => Create(g, prefixes, context)).ToArray();
            }

            string typeString = type.RootTypeString;

            if (typeString == "[" || typeString == "?")
            {
                return(new ResolvedType()
                {
                    IsArray = typeString == "[",
                    IsNullable = typeString == "?",
                    Generics = generics,
                });
            }

            if (PRIMITIVE_TYPES.Contains(typeString))
            {
                return(new ResolvedType()
                {
                    Generics = EMPTY_GENERICS,
                    PrimitiveType = typeString,
                    IsVoid = typeString == "void",
                });
            }
            foreach (string prefix in prefixes)
            {
                string fullyQualifiedName = prefix + typeString;
                if (FRAMEWORK_CLASSES_AND_PARENTS.ContainsKey(fullyQualifiedName))
                {
                    return(new ResolvedType()
                    {
                        FrameworkClass = fullyQualifiedName,
                        Generics = generics,
                    });
                }

                if (GetFrameworkEnum(fullyQualifiedName) != null)
                {
                    return(new ResolvedType()
                    {
                        FrameworkClass = fullyQualifiedName,
                        Generics = EMPTY_GENERICS,
                        IsEnum = true,
                    });
                }
                if (context != null)
                {
                    TopLevelEntity tle = context.DoLookup(fullyQualifiedName);
                    if (tle != null)
                    {
                        return(new ResolvedType()
                        {
                            CustomType = tle,
                            Generics = generics,
                            IsEnum = tle is EnumDefinition,
                        });
                    }
                }
            }

            return(null);
        }
예제 #18
0
        private static CSharpType TryParseImpl(TokenStream tokens, bool allowNullable)
        {
            int           tokenState = tokens.CurrentState;
            IList <Token> rootType   = GetRootType(tokens);

            if (rootType == null)
            {
                tokens.RestoreState(tokenState);
                return(null);
            }

            if (!PRIMITIVES_LOOKUP.Contains(rootType[0].Value))
            {
                int preGenerics = tokens.CurrentState;
                if (tokens.PopIfPresent("<"))
                {
                    bool              isValid  = true;
                    CSharpType        first    = TryParseImpl(tokens, allowNullable);
                    List <CSharpType> generics = new List <CSharpType>();
                    if (first != null)
                    {
                        generics.Add(first);

                        while (isValid && !tokens.IsNext(">"))
                        {
                            if (!tokens.PopIfPresent(","))
                            {
                                isValid = false;
                            }
                            else
                            {
                                CSharpType next = TryParseImpl(tokens, allowNullable);
                                if (next == null)
                                {
                                    isValid = false;
                                }

                                generics.Add(next);
                            }
                        }

                        if (isValid && tokens.PopIfPresent(">"))
                        {
                            CSharpType o = new CSharpType(rootType, generics);
                            if (tokens.IsNext("["))
                            {
                                o = ParseOutArraySuffix(o, tokens);
                            }
                            return(o);
                        }
                    }
                }
                tokens.RestoreState(preGenerics);
            }

            CSharpType output = new CSharpType(rootType, EMPTY_GENERICS);

            if (allowNullable && tokens.IsNext("?"))
            {
                Token questionMark = tokens.Pop();
                output = new CSharpType(new Token[] { questionMark }, new CSharpType[] { output });
            }

            if (tokens.IsNext("["))
            {
                output = ParseOutArraySuffix(output, tokens);
            }
            return(output);
        }
예제 #19
0
        public static Executable Parse(ParserContext context, TokenStream tokens, TopLevelEntity parent, bool enableSemicolon)
        {
            switch (tokens.PeekValue())
            {
            case "for": return(ParseForLoop(context, tokens, parent));

            case "foreach": return(ParseForEachLoop(context, tokens, parent));

            case "if": return(ParseIfStatement(context, tokens, parent));

            case "while": return(ParseWhileLoop(context, tokens, parent));

            case "do": return(ParseDoWhileLoop(context, tokens, parent));

            case "switch": return(ParseSwitchStatement(context, tokens, parent));

            case "throw": return(ParseThrowStatement(context, tokens, parent));

            case "return": return(ParseReturnStatement(context, tokens, parent));

            case "using": return(ParseUsingStatement(context, tokens, parent));

            case "try": return(ParseTryStatement(context, tokens, parent));

            default:
                break;
            }

            // check for variable declaration
            int        state = tokens.CurrentState;
            CSharpType variableDeclarationType = CSharpType.TryParse(tokens);

            if (variableDeclarationType != null)
            {
                Token variableName = tokens.PopWordIfPresent();
                if (variableName != null && (tokens.IsNext(";") || tokens.IsNext("=") || tokens.IsNext(",")))
                {
                    // This is a variable declaration.
                    Executable varDecl = ParseVariableDeclaration(context, tokens, variableDeclarationType, variableName, parent);
                    if (enableSemicolon)
                    {
                        tokens.PopExpected(";");
                    }
                    return(varDecl);
                }

                tokens.RestoreState(state);
            }

            Expression expr = ExpressionParser.Parse(context, tokens, parent);

            Executable exec;

            string nextToken = tokens.PeekValue();

            switch (nextToken)
            {
            case "=":
            case "+=":
            case "-=":
            case "*=":
            case "/=":
            case "%=":
            case "|=":
            case "&=":
            case "^=":
            case "<<=":
            case ">>=":
                Token      assignmentOpToken = tokens.Pop();
                Expression assignmentValue   = ExpressionParser.Parse(context, tokens, parent);
                exec = new AssignmentStatement(expr.FirstToken, expr, assignmentOpToken, assignmentValue, parent);
                break;

            default:
                exec = new ExpressionAsExecutable(expr, parent);
                break;
            }

            if (enableSemicolon)
            {
                tokens.PopExpected(";");
            }
            return(exec);
        }
예제 #20
0
        private static Expression ParseAtomWithSuffix(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Expression root;

            if (tokens.IsNext("("))
            {
                Token openParen = tokens.Pop();

                switch (IdentifyParenthesisSituation(tokens))
                {
                case ParenthesisSituation.CAST:
                    CSharpType castType = CSharpType.Parse(tokens);
                    tokens.PopExpected(")");
                    Expression castValue = ParseAtomWithSuffix(context, tokens, parent);
                    return(new CastExpression(openParen, castType, castValue, parent));

                case ParenthesisSituation.LAMBDA_ARG:
                    List <Token> lambdaArgs = new List <Token>()
                    {
                        tokens.PopWord()
                    };

                    while (tokens.PopIfPresent(","))
                    {
                        lambdaArgs.Add(tokens.PopWord());
                    }
                    tokens.PopExpected(")");
                    Token        arrowToken = tokens.PopExpected("=>");
                    Executable[] lambdaBody;
                    if (tokens.IsNext("{"))
                    {
                        lambdaBody = ExecutableParser.ParseCodeBlock(context, tokens, parent, true);
                    }
                    else
                    {
                        Expression expr = Parse(context, tokens, parent);
                        lambdaBody = new Executable[] {
                            new ReturnStatement(expr.FirstToken, expr, parent)
                        };
                    }
                    return(new Lambda(openParen, lambdaArgs, arrowToken, lambdaBody, parent));

                case ParenthesisSituation.WRAPPED_EXPRESSION:
                    root = Parse(context, tokens, parent);
                    tokens.PopExpected(")");
                    break;

                default:
                    throw new Exception();     // not valid
                }
            }
            else
            {
                root = ParseAtom(context, tokens, parent);
            }
            bool   anythingInteresting = true;
            string next = tokens.PeekValue();

            while (anythingInteresting)
            {
                switch (next)
                {
                case ".":
                    Token dotToken  = tokens.Pop();
                    Token fieldName = tokens.PopWord();
                    root = new DotField(root.FirstToken, root, dotToken, fieldName, parent);
                    break;

                case "[":
                    Token      openBracket = tokens.Pop();
                    Expression index       = Parse(context, tokens, parent);
                    tokens.PopExpected("]");
                    root = new BracketIndex(root, openBracket, index, parent);
                    break;

                case "<":
                    if (root is DotField)
                    {
                        CSharpType[] functionInvocationTypeSpecification = MaybeParseOutOneOfThoseInlineTypeSpecificationsForFunctionInvocations(tokens);
                        if (functionInvocationTypeSpecification != null)
                        {
                            ((DotField)root).InlineTypeSpecification = functionInvocationTypeSpecification;
                        }
                        else
                        {
                            anythingInteresting = false;
                        }
                    }
                    else
                    {
                        anythingInteresting = false;
                    }
                    break;

                case "(":
                    Token             openParen = tokens.Pop();
                    List <Expression> args      = new List <Expression>();
                    List <Token>      outTokens = new List <Token>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (args.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }
                        if (tokens.IsNext("out"))
                        {
                            outTokens.Add(tokens.Pop());
                        }
                        else
                        {
                            outTokens.Add(null);
                        }
                        args.Add(Parse(context, tokens, parent));
                    }
                    root = new FunctionInvocation(root.FirstToken, root, openParen, args, outTokens, parent);
                    break;

                case "{":     // e.g. new List<int>() { 1, 2, 3 }. This only follows a constructor.
                    FunctionInvocation            fi  = root as FunctionInvocation;
                    ConstructorInvocationFragment cif = fi == null ? null : (ConstructorInvocationFragment)fi.Root;
                    if (root is FunctionInvocation && ((FunctionInvocation)root).Root is ConstructorInvocationFragment)
                    {
                        tokens.Pop();     // {

                        ConstructorSuffixData format = DetermineConstructorSuffixDataFormat(tokens);

                        bool nextAllowed                = true;
                        List <Expression> values        = new List <Expression>();
                        List <Expression> kvpKeys       = new List <Expression>();
                        List <Token>      propertyNames = new List <Token>();
                        while (!tokens.PopIfPresent("}"))
                        {
                            if (!nextAllowed)
                            {
                                tokens.PopExpected("}");                   // intentionally throw
                            }
                            switch (format)
                            {
                            case ConstructorSuffixData.KVP_ENTRIES:
                                tokens.PopExpected("{");
                                kvpKeys.Add(Parse(context, tokens, parent));
                                tokens.PopExpected(",");
                                values.Add(Parse(context, tokens, parent));
                                tokens.PopExpected("}");
                                break;

                            case ConstructorSuffixData.PROPERTIES:
                                propertyNames.Add(tokens.PopWord());
                                tokens.PopExpected("=");
                                values.Add(Parse(context, tokens, parent));
                                break;

                            case ConstructorSuffixData.SEQUENTIAL_ITEMS:
                                values.Add(Parse(context, tokens, parent));
                                break;
                            }
                            nextAllowed = tokens.PopIfPresent(",");
                        }
                        cif.InitialDataValues = values.ToArray();
                        int t = cif.InitialDataValues.Length;
                        if (kvpKeys.Count == t)
                        {
                            cif.InitialDataKeys = kvpKeys.ToArray();
                        }
                        if (propertyNames.Count == t)
                        {
                            cif.InitialDataPropertyNames = propertyNames.ToArray();
                        }
                    }
                    else
                    {
                        throw new ParserException(tokens.Peek(), "Unexpected '{'");
                    }
                    break;

                default:
                    anythingInteresting = false;
                    break;
                }
                next = tokens.PeekValue();
            }

            if (next == "++" || next == "--")
            {
                Token incrementToken = tokens.Pop();
                root = new InlineIncrement(root.FirstToken, incrementToken, false, root, parent);
            }

            return(root);
        }
예제 #21
0
        private static Expression ParseAtom(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            string next = tokens.PeekValue();

            switch (next)
            {
            case "true":
            case "false":
                Token booleanToken = tokens.Pop();
                return(new BooleanConstant(booleanToken, booleanToken.Value == "true", parent));

            case "null":
                Token nullToken = tokens.Pop();
                return(new NullConstant(nullToken, parent));

            case "new":
                Token      newToken  = tokens.Pop();
                CSharpType className = CSharpType.TryParse(tokens);
                if (className == null)
                {
                    throw new ParserException(newToken, "'new' keyword must be followed by a className");
                }
                if (!tokens.IsNext("("))
                {
                    // could be a new array of which there are two ways to define it...
                    if (className.IsArray && tokens.IsNext("{"))
                    {
                        List <Expression> arrayItems = new List <Expression>();
                        tokens.PopExpected("{");
                        bool nextAllowed = true;
                        while (!tokens.PopIfPresent("}"))
                        {
                            if (!nextAllowed)
                            {
                                tokens.PopExpected("}");
                            }
                            arrayItems.Add(ExpressionParser.Parse(context, tokens, parent));
                            nextAllowed = tokens.PopIfPresent(",");
                        }
                        return(new ArrayInitialization(newToken, className.Generics[0], null, arrayItems, parent));
                    }

                    if (tokens.IsNext("["))
                    {
                        // a new array with specified length
                        tokens.PopExpected("[");
                        Expression arrayLength = ExpressionParser.Parse(context, tokens, parent);
                        tokens.PopExpected("]");
                        return(new ArrayInitialization(newToken, className, arrayLength, null, parent));
                    }

                    // if this isn't an array construction, then give a reasonable error message...
                    tokens.PopExpected("(");
                }
                return(new ConstructorInvocationFragment(newToken, className, parent));

            case "@":
                // raw string
                Token  rawStringAt       = tokens.Pop();
                Token  stringValue       = tokens.Pop();
                string stringValueActual = stringValue.Value;
                if (stringValueActual[0] != '"')
                {
                    throw new ParserException(stringValue, "Expected a string value");
                }
                return(new StringConstant(rawStringAt, stringValueActual.Substring(1, stringValueActual.Length - 2), parent));

            default: break;
            }

            Token token = tokens.Pop();
            char  c     = next[0];

            if (c == '"' || c == '\'')
            {
                string stringValue = StringUtil.ConvertStringTokenToValue(token);
                if (c == '"')
                {
                    return(new StringConstant(token, stringValue, parent));
                }
                else
                {
                    return(new CharConstant(token, stringValue, parent));
                }
            }

            if (c == '0' && next.Length > 2 && next[1] == 'x')
            {
                string hex         = next.Substring(2);
                int    parsedValue = 0;

                for (int i = 0; i < hex.Length; ++i)
                {
                    c = hex[i];
                    if (c >= '0' && c <= '9')
                    {
                        parsedValue = parsedValue * 16 + (c - '0');
                    }
                    else if (c >= 'a' && c <= 'f')
                    {
                        parsedValue = parsedValue * 16 + (10 + c - 'a');
                    }
                    else if (c >= 'A' && c <= 'F')
                    {
                        parsedValue = parsedValue * 16 + (10 + c - 'A');
                    }
                    else
                    {
                        throw new ParserException(token, "Invalid hexidecimal value: '" + hex + "'");
                    }
                }
                return(new IntegerConstant(token, parsedValue, parent));
            }

            if (c == '.' && next.Length > 1)
            {
                double value;
                if (!double.TryParse(next, out value))
                {
                    throw new ParserException(token, "Invalid double constant: '" + next + "'");
                }
                return(new DoubleConstant(token, value, parent));
            }

            if (c >= '0' && c <= '9')
            {
                if (next.Contains('.'))
                {
                    if (next.EndsWith("f") || next.EndsWith("F"))
                    {
                        throw new NotImplementedException();
                    }
                    double floatValue;
                    if (!double.TryParse(next, out floatValue))
                    {
                        throw new ParserException(token, "Invalid number: '" + next + "'");
                    }
                    return(new DoubleConstant(token, floatValue, parent));
                }
                else
                {
                    if (next.EndsWith("f") || next.EndsWith("F"))
                    {
                        throw new NotImplementedException();
                    }

                    int intValue;
                    if (!int.TryParse(next, out intValue))
                    {
                        throw new ParserException(token, "Invalid number: '" + next + "'");
                    }

                    return(new IntegerConstant(token, intValue, parent));
                }
            }

            if ((c >= 'a' && c <= 'z') ||
                (c >= 'A' && c <= 'Z') ||
                c == '_')
            {
                if (tokens.IsNext("=>"))
                {
                    List <Token> args = new List <Token>()
                    {
                        token
                    };
                    Token        arrowToken = tokens.Pop();
                    Executable[] lambdaBody;
                    if (tokens.IsNext("{"))
                    {
                        lambdaBody = ExecutableParser.ParseCodeBlock(context, tokens, parent, true);
                    }
                    else
                    {
                        Expression lambdaBodyExpr = Parse(context, tokens, parent);
                        lambdaBody = new Executable[] {
                            new ReturnStatement(lambdaBodyExpr.FirstToken, lambdaBodyExpr, parent),
                        };
                    }
                    return(new Lambda(token, args, arrowToken, lambdaBody, parent));
                }
                return(new Variable(token, parent));
            }

            throw new ParserException(token, "Unexpected token: '" + token.Value + "'");
        }
예제 #22
0
        private static Executable ParseVariableDeclaration(ParserContext context, TokenStream tokens, CSharpType type, Token name, TopLevelEntity parent)
        {
            Expression targetValue     = null;
            Token      assignmentToken = null;

            if (tokens.IsNext("="))
            {
                assignmentToken = tokens.Pop();
                targetValue     = ExpressionParser.Parse(context, tokens, parent);
            }
            else if (tokens.IsNext(","))
            {
                List <Token> variableNames = new List <Token>()
                {
                    name
                };
                while (tokens.PopIfPresent(","))
                {
                    variableNames.Add(tokens.PopWord());
                }
                return(new MultiVariableDeclaration(type.FirstToken, type, variableNames, parent));
            }

            return(new VariableDeclaration(type.FirstToken, type, name, assignmentToken, targetValue, parent));
        }