コード例 #1
0
 protected MethodDecl(Parser parser, CodeObject parent, bool parse, ParseFlags flags)
     : base(parser, parent)
 {
     if (parse)
     {
         ParseMethodNameAndType(parser, parent, true, false);
         ParseParameters(parser);
         ParseModifiersAndAnnotations(parser);  // Parse any attributes and/or modifiers
         ParseTerminatorOrBody(parser, flags);
     }
 }
コード例 #2
0
        /// <summary>
        /// Parse an orphaned <see cref="ElseIf"/>.
        /// </summary>
        public static ElseIf ParseOrphan(Parser parser, CodeObject parent, ParseFlags flags)
        {
            Token  token  = parser.Token;
            ElseIf elseIf = Parse(parser, parent);

            if (elseIf != null)
            {
                parser.AttachMessage(elseIf, "Orphaned 'else if' - missing parent 'if'", token);
            }
            return(elseIf);
        }
コード例 #3
0
 /// <summary>
 /// Parse a <see cref="ConversionOperatorDecl"/>.
 /// </summary>
 public ConversionOperatorDecl(Parser parser, CodeObject parent, ParseFlags flags)
     : base(parser, parent, false, flags)
 {
     parser.NextToken();                                 // Move past 'operator'
     _modifiers = ModifiersHelpers.Parse(parser, this);  // Parse any modifiers in reverse from the Unused list
     _name      = GetInternalName(_modifiers);           // Get the name
     ParseUnusedAnnotations(parser, this, false);        // Parse attributes and/or doc comments from the Unused list
     SetField(ref _returnType, Expression.Parse(parser, this, true, Expression.ParseTokenStartGroup), false);
     ParseParameters(parser);
     ParseTerminatorOrBody(parser, flags);
 }
コード例 #4
0
 /// <summary>
 /// Parse a <see cref="GenericMethodDecl"/> using alternate type argument delimiters.
 /// </summary>
 public static GenericMethodDecl ParseAlt(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // Verify that this alternate form is inside a doc comment (subroutines will look for the appropriate
     // delimiters according to the parser state) in addition to passing other verifications as above.
     // If it doesn't seem to match the proper pattern, abort so that other types can try parsing it.
     if (parser.InDocComment && ((parent is TypeDecl && parser.HasUnusedIdentifier) || parser.HasUnusedTypeRefAndIdentifier) &&
         TypeRefBase.PeekTypeArguments(parser, TypeRefBase.ParseTokenAltArgumentEnd, flags) && parser.LastPeekedTokenText == ParseTokenStart)
     {
         return(new GenericMethodDecl(parser, parent, false, flags));
     }
     return(null);
 }
コード例 #5
0
 /// <summary>
 /// Parse a <see cref="GenericMethodDecl"/>.
 /// </summary>
 public static new GenericMethodDecl Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // If our parent is a TypeDecl, verify that we have an unused identifier (a Dot operator is possible
     // for explicit interface implementations, but is handled by MethodDecl, which then calls the constructor
     // below).  Otherwise, require a possible return type in addition to the identifier.  Also verify that
     // we seem to match a type argument list pattern followed by a '('.
     // If it doesn't seem to match the proper pattern, abort so that other types can try parsing it.
     if (((parent is TypeDecl && parser.HasUnusedIdentifier) || parser.HasUnusedTypeRefAndIdentifier) &&
         TypeRefBase.PeekTypeArguments(parser, TypeRefBase.ParseTokenArgumentEnd, flags) && parser.LastPeekedTokenText == ParseTokenStart)
     {
         return(new GenericMethodDecl(parser, parent, false, flags));
     }
     return(null);
 }
コード例 #6
0
        /// <summary>
        /// Parse a <see cref="ThisRef"/>.
        /// </summary>
        public static SymbolicRef Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Handle the special case of 'this' being used on the right side of a Dot for an explicit interface declaration
            // of an indexer, or to specify an Indexer member of a type, such as 'IDictionary.this[object]' (which can occur
            // in a doc comment).
            if (parent is Dot && ((Dot)parent).Left != null)
            {
                parser.NextToken();  // Move past 'this'
                return(new UnresolvedThisRef(parser.LastToken));
            }

            // By default, assume 'this' is a ThisRef
            return(new ThisRef(parser, parent));
        }
コード例 #7
0
        /// <summary>
        /// Parse a <see cref="FieldDecl"/>.
        /// </summary>
        public static FieldDecl Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Validate that we have an unused identifier token preceeded by a type, and double-check the constraint that our
            // parent is a TypeDecl (necessary when constraints are relaxed for code embedded in doc comments).
            if (parser.HasUnusedTypeRefAndIdentifier && parent is TypeDecl)
            {
                FieldDecl fieldDecl = new FieldDecl(parser, parent, false);

                // Handle additional FieldDecls after any commas
                if (!fieldDecl.HasTerminator && parser.TokenText == Expression.ParseTokenSeparator)
                {
                    // If it's a multi, create one, and transfer any new lines and annotations
                    MultiFieldDecl multiFieldDecl = new MultiFieldDecl(fieldDecl)
                    {
                        NewLines = fieldDecl.NewLines, HasTerminator = false
                    };
                    multiFieldDecl.SetLineCol(fieldDecl);
                    fieldDecl.NewLines = 0;
                    do
                    {
                        Token commaToken = parser.Token;
                        parser.NextToken();  // Move past ','

                        // Associate any EOL comment on the ',' to the last FieldDecl
                        fieldDecl.MoveEOLComment(commaToken, false, false);

                        fieldDecl = new FieldDecl(parser, null, true);

                        // Force the expression to first-on-line if the last comma was (handles special-case
                        // formatting where the commas preceed the list items instead of following them).
                        if (commaToken.IsFirstOnLine)
                        {
                            fieldDecl.IsFirstOnLine = true;
                        }

                        // Move any comments after the ',' to the current FieldDecl
                        fieldDecl.MoveComments(commaToken);

                        multiFieldDecl.Add(fieldDecl);
                    }while (parser.TokenText == Expression.ParseTokenSeparator);
                    fieldDecl = multiFieldDecl;

                    multiFieldDecl.ParseTerminator(parser);
                }

                return(fieldDecl);
            }
            return(null);
        }
コード例 #8
0
 /// <summary>
 /// Parse a <see cref="PropertyDecl"/> or <see cref="EventDecl"/>.
 /// </summary>
 public static PropertyDeclBase Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // If our parent is a TypeDecl, verify that we have an unused Expression (it can be either an
     // identifier or a Dot operator for explicit interface implementations).  Otherwise, require a
     // possible type in addition to the Expression.
     // If it doesn't seem to match the proper pattern, abort so that other types can try parsing it.
     if ((parent is TypeDecl && parser.HasUnusedExpression) || parser.HasUnusedTypeRefAndExpression)
     {
         // If we have an unused 'event' modifier, it's an event, otherwise treat it as a property
         string eventModifier = ModifiersHelpers.AsString(Modifiers.Event).Trim();
         bool   isEvent       = (Enumerable.Any(parser.Unused, delegate(ParsedObject parsedObject) { return(parsedObject is Token && ((Token)parsedObject).Text == eventModifier); }));
         return(isEvent ? (PropertyDeclBase) new EventDecl(parser, parent) : new PropertyDecl(parser, parent));
     }
     return(null);
 }
コード例 #9
0
        /// <summary>
        /// Parse a <see cref="YieldBreak"/> or <see cref="YieldReturn"/>.
        /// </summary>
        public static YieldStatement Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Only parse 'yield' if it's followed by 'break' or 'return'
            string nextTokenText = parser.PeekNextTokenText();

            if (nextTokenText == YieldBreak.ParseToken2)
            {
                return(new YieldBreak(parser, parent));
            }
            if (nextTokenText == YieldReturn.ParseToken2)
            {
                return(new YieldReturn(parser, parent));
            }
            return(null);
        }
コード例 #10
0
        /// <summary>
        /// Parse a <see cref="For"/>.
        /// </summary>
        public static BlockStatement Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            For @for = new For(parser, parent);

            if (AutomaticCodeCleanup && !parser.IsGenerated)
            {
                // Normalize 'for (;;)' to 'while (true)' (with a null conditional)
                if (@for._initializations == null && @for._conditional == null && @for._iterations == null && [email protected])
                {
                    While @while = new While(@for);
                    @while.SetLineCol(@for);
                    return(@while);
                }
            }

            return(@for);
        }
コード例 #11
0
        /// <summary>
        /// Parse a <see cref="Conditional"/> operator.
        /// </summary>
        public static Conditional Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Disallow conditionals at the TypeDecl or NamespaceDecl levels - this prevents the possibility of matching when
            // parsing a return type expression that is a nullable type for a generic method that has constraints.
            if (parent is TypeDecl || parent is NamespaceDecl)
            {
                return(null);
            }

            // Verify that we have a matching ':' for the '?', otherwise abort (so TypeRef can try parsing it as a nullable type).
            // If we're nested without parens, we must find one extra ':' for each nested level.
            if (PeekConditional(parser, parent, parser.ConditionalNestingLevel + 1, flags))
            {
                return(new Conditional(parser, parent));
            }

            return(null);
        }
コード例 #12
0
 /// <summary>
 /// Parse an <see cref="IndexerDecl"/>.
 /// </summary>
 public static new IndexerDecl Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // If our parent is a TypeDecl, verify that we have an unused Expression (it can be either an
     // identifier or a Dot operator for explicit interface implementations).  Otherwise, require a
     // possible type in addition to the Expression.
     // If it doesn't seem to match the proper pattern, abort so that other types can try parsing it.
     if ((parent is TypeDecl && parser.HasUnusedExpression) || parser.HasUnusedTypeRefAndExpression)
     {
         // Verify that we have a 'this' or 'Interface.this' (in the first case, the 'this' will be
         // a ThisRef, in the second case, it will be an UnresolvedThisRef).
         CodeObject lastUnusedCodeObject = parser.LastUnusedCodeObject;
         if (lastUnusedCodeObject is ThisRef || (lastUnusedCodeObject is Dot && ((Dot)lastUnusedCodeObject).Right is UnresolvedThisRef))
         {
             return(new IndexerDecl(parser, parent));
         }
     }
     return(null);
 }
コード例 #13
0
        /// <summary>
        /// Parse a <see cref="Cast"/> operator.
        /// </summary>
        public static Cast Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Verify that we have a pattern of "(Type)", otherwise abort (so the expression parens logic can try parsing it).
            // Do NOT set the ParseFlags.Type flag here, because it might not be a type (it might be "(A * B)").
            // Also, verify that we're not inside a directive expression - casts aren't legal there.
            if (TypeRefBase.PeekType(parser, parser.PeekNextToken(), false, flags) && !parser.InDirectiveExpression)
            {
                Token last = parser.LastPeekedToken;
                if (last != null && last.Text == ParseTokenEnd)
                {
                    // Verify that the cast is either followed by a non-symbol, or various legal symbols (those that
                    // can only be unary operators).
                    Token next = parser.PeekNextToken();
                    if (next != null)
                    {
                        if (!next.IsSymbol || next.Text == ParseTokenStartGroup || next.Text == Complement.ParseToken ||
                            next.Text == Increment.ParseToken || next.Text == Decrement.ParseToken || next.Text == Not.ParseToken)
                        {
                            return(new Cast(parser, parent));
                        }

                        // In the case of the Negative and Positive unary operators following the Cast,
                        // it's impossible to be sure they aren't actually binary operators, such as "(v1)-v2" or
                        // "(v1)-(v2)" (yes, programmers actually write code like that for some reason!).
                        // For now, assume if the operator is followed by a space and/or a '(', it's a binary
                        // operator (so we don't have a Cast).  This will cover most cases, but not 100%.
                        // Any parse issues could be easily worked around by adding parens around the entire right
                        // expression being cast, such as "(v1)(-(v2))" to force a cast, or around either both sides
                        // or neither side of a binary operator to avoid a cast.
                        if (next.Text == Positive.ParseToken || next.Text == Negative.ParseToken)
                        {
                            next = parser.PeekNextToken();
                            if (next.Text != ParseTokenStartGroup && next.LeadingWhitespace.Length == 0)
                            {
                                return(new Cast(parser, parent));
                            }
                        }
                    }

                    // Otherwise, fail and treat it as a grouped expression instead.
                }
            }
            return(null);
        }
コード例 #14
0
        /// <summary>
        /// Parse a <see cref="PragmaDirective"/>.
        /// </summary>
        public static PragmaDirective Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Abort if there isn't a pragma sub-directive name on the same line
            Token next = parser.PeekNextToken();

            if (next == null || next.NewLines > 0)
            {
                return(null);
            }

            // Execute the callback if we have a parse-point for the token
            Parser.ParseDelegate callback;
            if (_parsePoints.TryGetValue(next.Text, out callback))
            {
                return((PragmaDirective)callback(parser, parent, flags));
            }

            return(null);
        }
コード例 #15
0
        /// <summary>
        /// Parse a <see cref="MethodDecl"/>.
        /// </summary>
        public static MethodDeclBase Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // If our parent is a TypeDecl, verify that we have an unused Expression (it can be either an
            // identifier or a Dot operator for explicit interface implementations).  Otherwise, require a
            // possible return type in addition to the Expression.
            // If it doesn't seem to match the proper pattern, abort so that other types can try parsing it.
            if ((parent is TypeDecl && parser.HasUnusedExpression) || parser.HasUnusedTypeRefAndExpression)
            {
                // If we have a Dot expression with an UnresolvedRef with type arguments on the right side,
                // then this is a special-case GenericMethodDecl and we need to turn parsing over to that
                // class (it's normal parsing of the type arguments fails to activate due to the Dot operator
                // activating expression parsing).
                Dot dot = parser.LastUnusedCodeObject as Dot;
                if (dot != null && dot.Right is UnresolvedRef && ((UnresolvedRef)dot.Right).HasTypeArguments)
                {
                    return(new GenericMethodDecl(parser, parent, true, flags));
                }

                return(new MethodDecl(parser, parent, true, flags));
            }
            return(null);
        }
コード例 #16
0
        protected void ParseTerminatorOrBody(Parser parser, ParseFlags flags)
        {
            // Check for an optional ';' in place of the body
            if (parser.TokenText == Terminator)
            {
                ParseTerminator(parser);

                // Check for compiler directives, storing them as postfix annotations on the parent
                Block.ParseCompilerDirectives(parser, this, AnnotationFlags.IsPostfix, false);
            }
            else
            {
                if (flags.HasFlag(ParseFlags.SkipMethodBodies))
                {
                    Block.SkipParsingBlock(parser, this, true);
                }
                else
                {
                    new Block(out _body, parser, this, true);  // Parse the body
                }
            }
        }
コード例 #17
0
        /// <summary>
        /// Parse a <see cref="NewObject"/> or <see cref="NewArray"/> operator.
        /// </summary>
        public static NewOperator Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Abort if our parent is a TypeDecl (the 'new' is probably part of a method declaration)
            if (parent is TypeDecl)
            {
                return(null);
            }

            NewOperator result = null;

            // Peek ahead to see if we have a valid non-array type
            TypeRefBase.PeekType(parser, parser.PeekNextToken(), true, flags | ParseFlags.Type);
            Token token = parser.LastPeekedToken;

            if (token != null)
            {
                // If we found a '[', assume NewArray
                if (token.Text == NewArray.ParseTokenStart)
                {
                    result = new NewArray(parser, parent);
                }
                // If we found '(' or '{', assume NewObject
                else if (token.Text == ParameterDecl.ParseTokenStart || token.Text == Initializer.ParseTokenStart)
                {
                    result = new NewObject(parser, parent);
                }
            }

            // Last chance - invalid code might still parse better as a NewObject, so assume that's
            // what it is if our parent is a VariableDecl.
            if (result == null && parent is VariableDecl)
            {
                result = new NewObject(parser, parent);
            }

            // If we didn't create an object, return null (the 'new' is probably part of a method declaration)
            return(result);
        }
コード例 #18
0
        protected void ParseKeywordAndArgument(Parser parser, ParseFlags flags)
        {
            // Save the starting token of the expression for later
            Token startingToken = parser.ParentStartingToken;

            parser.NextToken();  // Move past the keyword

            // If the argument has parens, it's a normal operator, like 'typeof()', otherwise it's a top-level
            // operator (ref/out) and we have to parse it as such.
            if (HasArgumentParens)
            {
                ParseExpectedToken(parser, ParseTokenStartGroup); // Move past '('
                SetField(ref _expression, Parse(parser, this, false, ParseTokenEndGroup, flags), false);
                ParseExpectedToken(parser, ParseTokenEndGroup);   // Move past ')'
            }
            else
            {
                SetField(ref _expression, Parse(parser, this, true, null, flags), false);
            }

            // Set the parent starting token to the beginning of the expression
            parser.ParentStartingToken = startingToken;
        }
コード例 #19
0
        protected void ParseAccessor(Parser parser, ParseFlags flags)
        {
            // Preserve the parsed NewLines value (MethodDeclBase forces it to 1 if it's 0), but
            // we'll allow accessors to be inlined by default.
            NewLines = parser.Token.NewLines;

            ParseModifiersAndAnnotations(parser);  // Parse any attributes and/or modifiers
            parser.NextToken();                    // Move past keyword
            ParseTerminatorOrBody(parser, flags);

            if (AutomaticFormattingCleanup && !parser.IsGenerated)
            {
                // Force property accessors (get/set) to a single line if they have a single-line body,
                // and remove any blank lines preceeding them in the property declaration (includes events).
                if (_body != null && _body.Count < 2 && _body.IsSingleLine)
                {
                    IsSingleLine = true;
                }
                if (NewLines > 1)
                {
                    NewLines = 1;
                }
            }
        }
コード例 #20
0
        /// <summary>
        /// Parse the <see cref="CodeUnit"/> from its file.
        /// </summary>
        public void Parse(ParseFlags flags)
        {
            // Abort if it's not C#
            if (!IsCSharp)
            {
                return;
            }

            // Check that the file exists (to avoid an exception)
            if (IsFile && !File.Exists(_fileName))
            {
                // Only record the error if there isn't a similar message already
                if (Annotations == null || !Enumerable.Any(Annotations, delegate(Annotation annotation) { return(annotation.Text.Contains("doesn't exist") || annotation.Text.Contains("is missing")); }))
                {
                    LogAndAttachMessage("File '" + _fileName + "' doesn't exist!", MessageSeverity.Error, MessageSource.Parse);
                }
                return;
            }

            // If we're loading a generated file, record it as such so we can disable saving it
            if (_fileName.EndsWith(Project.XamlCSharpGeneratedExtension) || _fileName.EndsWith(Project.DesignerCSharpGeneratedExtension))
            {
                IsGenerated = true;
            }

            // Get any compiler directive symbols from the project (copy them, because
            // they can be both defined and un-defined at the file level).
            _compilerDirectiveSymbols.Clear();
            if (_parent != null && Project.CurrentConfiguration != null)
            {
                _compilerDirectiveSymbols = new HashSet <string>(Project.CurrentConfiguration.Constants);
            }

            try
            {
                // Create a parser instance and parse the file
                using (Parser parser = new Parser(this, flags, IsGenerated))
                {
                    // Parse the body until we hit EOF, and add types to the namespace
                    new Block(out _body, parser, this, false, null);
                    _totalLines   = parser.LineNumber;
                    _SLOC         = parser.SLOC;
                    FileUsingTabs = (AutoDetectTabs ? parser.UsingMoreTabsThanSpaces() : UseTabs);
                }

                // Also check for other types of generated files, to disable saving them
                if (Body != null && Body.Count > 0)
                {
                    CodeObject firstCodeObject = Body[0];
                    if (firstCodeObject is CommentBase)
                    {
                        CheckIfGenerated((CommentBase)firstCodeObject);
                    }
                    else if (firstCodeObject.Annotations != null)
                    {
                        foreach (Annotation annotation in firstCodeObject.Annotations)
                        {
                            if (annotation is CommentBase)
                            {
                                CheckIfGenerated((CommentBase)annotation);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogAndAttachException(ex, "parsing", MessageSource.Parse);
            }
            finally
            {
                // Make certain the body is set to IsFirstOnLine
                if (_body != null)
                {
                    _body.IsFirstOnLine = true;
                }
            }
        }
コード例 #21
0
 /// <summary>
 /// Parse an <see cref="Or"/> operator.
 /// </summary>
 public static Or Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new Or(parser, parent));
 }
コード例 #22
0
 /// <summary>
 /// Parse a <see cref="RegionDirective"/>.
 /// </summary>
 public static RegionDirective Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new RegionDirective(parser, parent));
 }
コード例 #23
0
 /// <summary>
 /// Parse a <see cref="SizeOf"/> operator.
 /// </summary>
 public static SizeOf Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new SizeOf(parser, parent));
 }
コード例 #24
0
 /// <summary>
 /// Parse a <see cref="Divide"/> operator.
 /// </summary>
 public static Divide Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new Divide(parser, parent));
 }
コード例 #25
0
 /// <summary>
 /// Parse a <see cref="DefineSymbol"/>.
 /// </summary>
 public static DefineSymbol Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new DefineSymbol(parser, parent));
 }
コード例 #26
0
 /// <summary>
 /// Parse a <see cref="Complement"/>.
 /// </summary>
 public static Complement Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new Complement(parser, parent));
 }
コード例 #27
0
 /// <summary>
 /// Parse type arguments using the alternate delimiters.
 /// </summary>
 public static Expression ParseAltTypeArguments(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // Verify that we seem to match a type argument list pattern
     // (otherwise abort so that PropertyDeclBase will get a chance to parse it)
     // Only supported inside documentation comments - subroutines will look for the
     // appropriate delimiters according to the parser state.
     if (parser.InDocComment && parser.HasUnusedIdentifier && PeekTypeArguments(parser, ParseTokenAltArgumentEnd, flags))
     {
         return(new UnresolvedRef(parser, parent, false, true));
     }
     return(null);
 }
コード例 #28
0
 /// <summary>
 /// Parse type arguments.
 /// </summary>
 public static Expression ParseTypeArguments(Parser parser, CodeObject parent, ParseFlags flags)
 {
     // Verify that we seem to match a type argument list pattern
     // (otherwise abort so that the LessThan operator will get a chance to parse it)
     if (parser.HasUnusedIdentifier && PeekTypeArguments(parser, ParseTokenArgumentEnd, flags))
     {
         return(new UnresolvedRef(parser, parent, false, true));
     }
     return(null);
 }
コード例 #29
0
 /// <summary>
 /// Parse a <see cref="DocI"/>.
 /// </summary>
 public static new DocI Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new DocI(parser, parent));
 }
コード例 #30
0
 /// <summary>
 /// Parse a <see cref="Lookup"/> operator.
 /// </summary>
 public static Lookup Parse(Parser parser, CodeObject parent, ParseFlags flags)
 {
     return(new Lookup(parser, parent));
 }