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); } }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
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 } } }
/// <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); }
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; }
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; } } }
/// <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; } } }
/// <summary> /// Parse an <see cref="Or"/> operator. /// </summary> public static Or Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new Or(parser, parent)); }
/// <summary> /// Parse a <see cref="RegionDirective"/>. /// </summary> public static RegionDirective Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new RegionDirective(parser, parent)); }
/// <summary> /// Parse a <see cref="SizeOf"/> operator. /// </summary> public static SizeOf Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new SizeOf(parser, parent)); }
/// <summary> /// Parse a <see cref="Divide"/> operator. /// </summary> public static Divide Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new Divide(parser, parent)); }
/// <summary> /// Parse a <see cref="DefineSymbol"/>. /// </summary> public static DefineSymbol Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new DefineSymbol(parser, parent)); }
/// <summary> /// Parse a <see cref="Complement"/>. /// </summary> public static Complement Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new Complement(parser, parent)); }
/// <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); }
/// <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); }
/// <summary> /// Parse a <see cref="DocI"/>. /// </summary> public static new DocI Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new DocI(parser, parent)); }
/// <summary> /// Parse a <see cref="Lookup"/> operator. /// </summary> public static Lookup Parse(Parser parser, CodeObject parent, ParseFlags flags) { return(new Lookup(parser, parent)); }