예제 #1
0
 public BracketIndex(Expression root, Token openBracket, Expression index, TopLevelEntity parent)
     : base(root.FirstToken, parent)
 {
     this.Root        = root;
     this.OpenBracket = openBracket;
     this.Index       = index;
 }
예제 #2
0
        protected override FunctionDefinition ParseFunction(
            TokenStream tokens,
            TopLevelEntity nullableOwner,
            FileScope fileScope,
            ModifierCollection modifiers,
            AnnotationCollection annotations)
        {
            AType returnType        = this.parser.TypeParser.Parse(tokens);
            Token firstToken        = modifiers.FirstToken ?? returnType.FirstToken;
            Token functionNameToken = tokens.Pop();

            this.parser.VerifyIdentifier(functionNameToken);

            FunctionDefinition fd = new FunctionDefinition(firstToken, returnType, nullableOwner, functionNameToken, modifiers, annotations, fileScope);

            tokens.PopExpected("(");
            List <AType>      argTypes      = new List <AType>();
            List <Token>      argNames      = new List <Token>();
            List <Expression> defaultValues = new List <Expression>();

            this.ParseArgumentListDeclaration(tokens, fd, argTypes, argNames, defaultValues);

            fd.ArgTypes      = argTypes.ToArray();
            fd.ArgNames      = argNames.ToArray();
            fd.DefaultValues = defaultValues.ToArray();
            fd.FinalizeArguments();

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

            fd.Code = code.ToArray();

            return(fd);
        }
예제 #3
0
파일: FileScope.cs 프로젝트: djlw78/crayon
        internal ClassDefinition DoClassLookup(Node fromWhere, Token nameToken, string name, bool failSilently)
        {
            TopLevelEntity ex = this.FileScopeEntityLookup.DoEntityLookup(name, fromWhere);

            if (ex == null)
            {
                if (failSilently)
                {
                    return(null);
                }

                string message = "No class named '" + name + "' was found.";
                if (name.Contains("."))
                {
                    message += " Did you forget to import a library?";
                }
                throw new ParserException(nameToken, message);
            }

            if (ex is ClassDefinition)
            {
                return((ClassDefinition)ex);
            }

            // Still throw an exception if the found item is not a class. This is used by code to check if
            // something is a valid variable name or a class name. Colliding with something else is bad.
            throw new ParserException(nameToken, "This is not a class.");
        }
예제 #4
0
        private void BuildEntityMapImpl(TopLevelEntity tle, string prefix)
        {
            if (tle is ClassLikeDefinition)
            {
                string name = ((ClassLikeDefinition)tle).Name.Value;
                this.entityMap[prefix + name] = tle;

                ClassDefinition cd = tle as ClassDefinition;
                if (cd != null)
                {
                    string nestedPrefix = prefix + name + ".";
                    foreach (ClassLikeDefinition nestedClass in cd.NestedClasses)
                    {
                        this.BuildEntityMapImpl(nestedClass, nestedPrefix);
                    }

                    foreach (EnumDefinition enumDef in cd.NestedEnums)
                    {
                        this.BuildEntityMapImpl(enumDef, nestedPrefix);
                    }
                }
            }
            else if (tle is EnumDefinition)
            {
                string name = ((EnumDefinition)tle).Name.Value;
                this.entityMap[prefix + name] = tle;
            }
            else
            {
                throw new System.NotImplementedException();
            }
        }
예제 #5
0
        public static TopLevelEntity Parse(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            TopLevelEntity tle = ParseImpl(context, tokens, parent);

            tle.FileContext = context.ActiveFileContext;
            return(tle);
        }
예제 #6
0
 public StringConstant(Token firstToken, string actualValue, TopLevelEntity parent)
     : base(firstToken, parent)
 {
     if (firstToken.Value[0] == '\'')
     {
         throw new System.Exception();
     }
     this.Value = Value;
 }
예제 #7
0
 public CharConstant(Token firstToken, string value, TopLevelEntity parent)
     : base(firstToken, parent)
 {
     if (value.Length > 1)
     {
         throw new ParserException(firstToken, "This character is longer than 1 character.");
     }
     this.Value = value[0];
 }
예제 #8
0
        public StaticFrameworkClassReference(Token firstToken, TopLevelEntity parent, ResolvedType frameworkType)
            : base(firstToken, parent)
        {
            if (frameworkType.FrameworkClass == null)
            {
                throw new System.InvalidOperationException();
            }

            this.ResolvedType = frameworkType;
        }
예제 #9
0
        protected virtual Namespace ParseNamespace(
            TokenStream tokens,
            Node owner,
            FileScope fileScope,
            AnnotationCollection annotations)
        {
            Token namespaceToken = tokens.PopExpected(this.parser.Keywords.NAMESPACE);
            Token first          = tokens.Pop();

            this.parser.VerifyIdentifier(first);
            List <Token> namespacePieces = new List <Token>()
            {
                first
            };
            string namespaceBuilder = first.Value;

            parser.RegisterNamespace(namespaceBuilder);
            while (tokens.PopIfPresent("."))
            {
                Token nsToken = tokens.Pop();
                this.parser.VerifyIdentifier(nsToken);
                namespacePieces.Add(nsToken);
                namespaceBuilder += "." + nsToken.Value;
                parser.RegisterNamespace(namespaceBuilder);
            }

            string name = string.Join(".", namespacePieces.Select <Token, string>(t => t.Value));

            Namespace namespaceInstance = new Namespace(namespaceToken, name, owner, fileScope, ModifierCollection.EMPTY, annotations);

            tokens.PopExpected("{");
            List <TopLevelEntity> namespaceMembers = new List <TopLevelEntity>();

            while (!tokens.PopIfPresent("}"))
            {
                TopLevelEntity executable = this.Parse(tokens, namespaceInstance, fileScope);
                if (executable is FunctionDefinition ||
                    executable is ClassDefinition ||
                    executable is EnumDefinition ||
                    executable is ConstDefinition ||
                    executable is Namespace)
                {
                    namespaceMembers.Add(executable);
                }
                else
                {
                    throw new ParserException(executable, "Only function, class, and nested namespace declarations may exist as direct members of a namespace.");
                }
            }

            namespaceInstance.Code = namespaceMembers.ToArray();

            return(namespaceInstance);
        }
예제 #10
0
 public TernaryExpression(
     Expression condition,
     Token ternaryToken,
     Expression trueExpression,
     Expression falseExpression,
     TopLevelEntity parent)
     : base(condition.FirstToken, parent)
 {
     this.Condition       = condition;
     this.TernaryToken    = ternaryToken;
     this.TrueExpression  = trueExpression;
     this.FalseExpression = falseExpression;
 }
예제 #11
0
 internal void CompileTopLevelEntity(ParserContext parser, ByteBuffer buffer, TopLevelEntity entity)
 {
     if (entity is FunctionDefinition)
     {
         FunctionDefinitionEncoder.Compile(this, parser, buffer, (FunctionDefinition)entity, false);
     }
     else if (entity is ClassDefinition)
     {
         this.CompileClass(parser, buffer, (ClassDefinition)entity);
     }
     else
     {
         throw new NotImplementedException("Invalid target for byte code compilation");
     }
 }
예제 #12
0
 public void AddExecutable(TopLevelEntity executable)
 {
     if (executable is Namespace)
     {
         Namespace ns = (Namespace)executable;
         this.namespaceFlattener.AddNamespace(ns);
         foreach (TopLevelEntity tlc in ns.Code)
         {
             this.AddExecutable(tlc);
         }
     }
     else
     {
         this.executables.Add(executable);
     }
 }
예제 #13
0
 internal void AddExecutable(TopLevelEntity entity)
 {
     if (entity is Namespace)
     {
         Namespace ns = (Namespace)entity;
         this.namespaceFlattener.AddNamespace(ns);
         foreach (TopLevelEntity tlc in ns.Code)
         {
             this.AddExecutable(tlc);
         }
     }
     else
     {
         this.entities.Add(entity);
     }
 }
예제 #14
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);
        }
예제 #15
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);
        }
예제 #16
0
        public static Namespace ParseNamespace(ParserContext context, TopLevelEntity parent, TokenStream tokens)
        {
            Token        namespaceToken = tokens.PopExpected("namespace");
            List <Token> nsNameParts    = new List <Token>();

            nsNameParts.Add(tokens.PopWord());
            while (tokens.IsNext("."))
            {
                tokens.PopExpected(".");
                nsNameParts.Add(tokens.PopWord());
            }
            Namespace ns = new Namespace(namespaceToken, nsNameParts, parent);

            tokens.PopExpected("{");
            while (!tokens.PopIfPresent("}"))
            {
                TopLevelEntity tle = Parse(context, tokens, ns);
                ns.AddMember(tle);
            }
            return(ns);
        }
예제 #17
0
        public void ParseFile(string fileName, string code)
        {
            this.ActiveFileContext = new FileContext(fileName);
            TokenStream tokens = new TokenStream(
                fileName,
                code,
                buildConstants);

            while (tokens.HasMore)
            {
                TopLevelEntity tle = TopLevelParser.Parse(this, tokens, null);
                if (tle is UsingDirective)
                {
                    this.ActiveFileContext.AddUsing((UsingDirective)tle);
                }
                else
                {
                    this.topLevelEntities.Add(tle);
                }
            }
            this.ActiveFileContext = null;
        }
예제 #18
0
        // Generally this is used with the name resolver. So for example, you have a refernce to a ClassDefinition
        // instance from the resolver, but you want to turn it into a ClassReference instance.
        // TODO: put this in a method on these classes and implement an interface. The function signatures are all close enough.
        public static Expression ConvertStaticReferenceToExpression(TopLevelEntity item, Token primaryToken, Node owner)
        {
            Expression     output           = null;
            TopLevelEntity referencedEntity = null;

            if (item is ClassDefinition)
            {
                ClassDefinition classDef = (ClassDefinition)item;
                output           = new ClassReference(primaryToken, classDef, owner);
                referencedEntity = classDef;
            }
            else if (item is EnumDefinition)
            {
                EnumDefinition enumDef = (EnumDefinition)item;
                output           = new EnumReference(primaryToken, enumDef, owner);
                referencedEntity = enumDef;
            }
            else if (item is ConstDefinition)
            {
                ConstDefinition constDef = (ConstDefinition)item;
                output           = new ConstReference(primaryToken, constDef, owner);
                referencedEntity = constDef;
            }
            else if (item is FunctionDefinition)
            {
                FunctionDefinition funcDef = (FunctionDefinition)item;
                output           = new FunctionReference(primaryToken, funcDef, owner);
                referencedEntity = funcDef;
            }
            else
            {
                throw new InvalidOperationException();
            }

            Node.EnsureAccessIsAllowed(primaryToken, owner, referencedEntity);

            return(output);
        }
예제 #19
0
 private static void BuildAncestorLookupForClassImpl(string className, ParserContext parserContext, HashSet <string> lookup)
 {
     lookup.Add(className);
     if (FRAMEWORK_CLASSES_AND_PARENTS.ContainsKey(className))
     {
         foreach (string parent in FRAMEWORK_CLASSES_AND_PARENTS[className])
         {
             BuildAncestorLookupForClassImpl(parent, parserContext, lookup);
         }
     }
     else
     {
         TopLevelEntity tle = parserContext.DoLookup(className);
         if (tle is ClassLikeDefinition)
         {
             ClassLikeDefinition cd = (ClassLikeDefinition)tle;
             foreach (ResolvedType parentType in cd.ParentClasses)
             {
                 if (parentType.CustomType != null)
                 {
                     BuildAncestorLookupForClassImpl(parentType.CustomType.FullyQualifiedName, parserContext, lookup);
                 }
                 else if (parentType.FrameworkClass != null)
                 {
                     BuildAncestorLookupForClassImpl(parentType.FrameworkClass, parserContext, lookup);
                 }
                 else
                 {
                     throw new System.NotImplementedException();
                 }
             }
         }
         else
         {
             throw new System.NotImplementedException();
         }
     }
 }
예제 #20
0
파일: FileScope.cs 프로젝트: jimjag/crayon
        internal ClassDefinition DoClassLookup(Node fromWhere, Token nameToken, string name, bool failSilently)
        {
            TopLevelEntity ex = this.FileScopeEntityLookup.DoEntityLookup(name, fromWhere);

            if (ex == null)
            {
                if (failSilently)
                {
                    return(null);
                }

                string message = "No class named '" + name + "' was found.";
                if (name.Contains("."))
                {
                    string[] nameParts                 = name.Split('.');
                    string   rootNamespace             = nameParts[0];
                    object   didTheyImportTheNamespace = this.FileScopeEntityLookup.DoLookupImpl(rootNamespace, fromWhere);
                    if (didTheyImportTheNamespace == null)
                    {
                        message += " Did you forget to import a library?";
                    }
                    else
                    {
                        message = "The namespace '" + rootNamespace + "' does not include a class named '" + (nameParts.Length == 2 ? nameParts[1] : name) + "'.";
                    }
                }
                throw new ParserException(nameToken, message);
            }

            if (ex is ClassDefinition)
            {
                return((ClassDefinition)ex);
            }

            // Still throw an exception if the found item is not a class. This is used by code to check if
            // something is a valid variable name or a class name. Colliding with something else is bad.
            throw new ParserException(nameToken, "This is not a class.");
        }
예제 #21
0
        protected override FunctionDefinition ParseFunction(
            TokenStream tokens,
            TopLevelEntity nullableOwner,
            FileScope fileScope,
            ModifierCollection modifiers,
            AnnotationCollection annotations)
        {
            bool isStatic =
                nullableOwner != null &&
                nullableOwner is ClassDefinition &&
                tokens.PopIfPresent(this.parser.Keywords.STATIC);

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

            Token functionNameToken = tokens.Pop();

            this.parser.VerifyIdentifier(functionNameToken);

            FunctionDefinition fd = new FunctionDefinition(functionToken, AType.Any(functionToken), nullableOwner, functionNameToken, modifiers, annotations, fileScope);

            tokens.PopExpected("(");
            List <Token>      argNames      = new List <Token>();
            List <Expression> defaultValues = new List <Expression>();
            List <AType>      argTypes      = new List <AType>();

            this.ParseArgumentListDeclaration(tokens, fd, argTypes, argNames, defaultValues);

            fd.ArgTypes      = argTypes.ToArray();
            fd.ArgNames      = argNames.ToArray();
            fd.DefaultValues = defaultValues.ToArray();
            fd.FinalizeArguments();

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

            fd.Code = code.ToArray();

            return(fd);
        }
예제 #22
0
        private static TopLevelEntity ParseEnumDefinition(
            ParserContext context,
            TopLevelEntity parent,
            Token firstToken,
            Dictionary <string, Token> modifiers,
            TokenStream tokens)
        {
            Token             enumToken   = tokens.PopExpected("enum");
            Token             enumName    = tokens.PopWord();
            List <Token>      fieldNames  = new List <Token>();
            List <Expression> fieldValues = new List <Expression>();

            tokens.PopExpected("{");
            bool           nextAllowed = true;
            EnumDefinition enumDef     = new EnumDefinition(firstToken, modifiers, enumName, parent);

            while (!tokens.PopIfPresent("}"))
            {
                if (!nextAllowed)
                {
                    tokens.PopExpected("}");               // intentionally throw
                }
                Token      enumFieldName  = tokens.PopWord();
                Expression enumFieldValue = null;
                if (tokens.PopIfPresent("="))
                {
                    enumFieldValue = ExpressionParser.Parse(context, tokens, enumDef);
                }
                fieldNames.Add(enumFieldName);
                fieldValues.Add(enumFieldValue);

                nextAllowed = tokens.PopIfPresent(",");
            }
            enumDef.FieldNames  = fieldNames.ToArray();
            enumDef.FieldValues = fieldValues.ToArray();
            return(enumDef);
        }
예제 #23
0
 public IntegerConstant(Token firstToken, int value, TopLevelEntity parent)
     : base(firstToken, parent)
 {
     this.Value = value;
 }
예제 #24
0
        private static Expression ParseEqualityComparison(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Expression root = ParseInequalityComparison(context, tokens, parent);
            string     next = tokens.PeekValue();

            if (next == "==" || next == "!=")
            {
                List <Token> ops = new List <Token>()
                {
                    tokens.Pop()
                };
                List <Expression> expressions = new List <Expression>()
                {
                    root, ParseInequalityComparison(context, tokens, parent)
                };
                return(new OpChain(expressions, ops, parent));
            }
            return(root);
        }
예제 #25
0
 public static Expression Parse(ParserContext context, TokenStream tokens, TopLevelEntity parent)
 {
     return(ParseTernary(context, tokens, parent));
 }
예제 #26
0
        private static Expression ParseBitwiseOps(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Expression root = ParseEqualityComparison(context, tokens, parent);
            string     next = tokens.PeekValue();

            if (next == "|" || next == "&" || next == "^")
            {
                List <Expression> expressions = new List <Expression>()
                {
                    root
                };
                List <Token> ops = new List <Token>();
                while (tokens.IsNext("|") || tokens.IsNext("&") || tokens.IsNext("^"))
                {
                    ops.Add(tokens.Pop());
                    expressions.Add(ParseEqualityComparison(context, tokens, parent));
                }
                return(new OpChain(expressions, ops, parent));
            }
            return(root);
        }
예제 #27
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 + "'");
        }
예제 #28
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);
        }
예제 #29
0
        private static Expression ParseNullCoalescer(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            Expression root = ParseBooleanCombination(context, tokens, parent);

            if (tokens.IsNext("??"))
            {
                List <Expression> expressions = new List <Expression>()
                {
                    root
                };
                List <Token> ops = new List <Token>();
                while (tokens.IsNext("??"))
                {
                    ops.Add(tokens.Pop());
                    expressions.Add(ParseBooleanCombination(context, tokens, parent));
                }
                return(new OpChain(expressions, ops, parent));
            }
            return(root);
        }
예제 #30
0
        private static Expression ParseUnary(ParserContext context, TokenStream tokens, TopLevelEntity parent)
        {
            string next = tokens.PeekValue();

            if (next == "!" || next == "-" || next == "--" || next == "++")
            {
                Token      unaryToken = tokens.Pop();
                Expression root       = ParseAtomWithSuffix(context, tokens, parent);
                switch (next)
                {
                case "!": return(new BooleanNot(unaryToken, root, parent));

                case "-": return(new NegativeSign(unaryToken, root, parent));

                case "++":
                case "--":
                    return(new InlineIncrement(unaryToken, unaryToken, true, root, parent));

                default: throw new NotImplementedException();
                }
            }

            return(ParseAtomWithSuffix(context, tokens, parent));
        }