private InterpolationSyntax ParseInterpolation(string text, Lexer.Interpolation interpolation, bool isVerbatim) { SyntaxToken openBraceToken; ExpressionSyntax expression; InterpolationAlignmentClauseSyntax alignment = null; InterpolationFormatClauseSyntax format = null; var closeBraceToken = interpolation.CloseBraceMissing ? SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken) : SyntaxFactory.Token(SyntaxKind.CloseBraceToken); var parsedText = Substring(text, interpolation.OpenBracePosition, interpolation.HasColon ? interpolation.ColonPosition - 1 : interpolation.CloseBracePosition - 1); using (var tempLexer = new Lexer(Text.SourceText.From(parsedText), this.Options, allowPreprocessorDirectives: false, interpolationFollowedByColon: interpolation.HasColon)) { // TODO: some of the trivia in the interpolation maybe should be trailing trivia of the openBraceToken using (var tempParser = new LanguageParser(tempLexer, null, null)) { SyntaxToken commaToken = null; ExpressionSyntax alignmentExpression = null; tempParser.ParseInterpolationStart(out openBraceToken, out expression, out commaToken, out alignmentExpression); if (alignmentExpression != null) { alignment = SyntaxFactory.InterpolationAlignmentClause(commaToken, alignmentExpression); } var extraTrivia = tempParser.CurrentToken.GetLeadingTrivia(); if (interpolation.HasColon) { var colonToken = SyntaxFactory.Token(SyntaxKind.ColonToken).TokenWithLeadingTrivia(extraTrivia); var formatText = Substring(text, interpolation.ColonPosition + 1, interpolation.FormatEndPosition); var formatString = MakeStringToken(formatText, formatText, isVerbatim, SyntaxKind.InterpolatedStringTextToken); format = SyntaxFactory.InterpolationFormatClause(colonToken, formatString); } else { // Move the leading trivia from the insertion's EOF token to the following token. closeBraceToken = closeBraceToken.TokenWithLeadingTrivia(extraTrivia); } } } var result = SyntaxFactory.Interpolation(openBraceToken, expression, alignment, format, closeBraceToken); Debug.Assert(Substring(text, interpolation.OpenBracePosition, interpolation.LastPosition) == result.ToFullString()); // yield from text equals yield from node return(result); }
protected static SyntaxToken ConvertToKeyword(SyntaxToken token) { if (token.Kind != token.ContextualKind) { var kw = token.IsMissing ? SyntaxFactory.MissingToken(token.LeadingTrivia.Node, token.ContextualKind, token.TrailingTrivia.Node) : SyntaxFactory.Token(token.LeadingTrivia.Node, token.ContextualKind, token.TrailingTrivia.Node); var d = token.GetDiagnostics(); if (d != null && d.Length > 0) { kw = kw.WithDiagnosticsGreen(d); } return(kw); } return(token); }
protected SyntaxToken EatToken(SyntaxKind kind, bool reportError) { if (reportError) { return(EatToken(kind)); } Debug.Assert(SyntaxFacts.IsAnyToken(kind)); if (this.CurrentToken.Kind != kind) { // should we eat the current ParseToken's leading trivia? return(SyntaxFactory.MissingToken(kind)); } else { return(this.EatToken()); } }
private ExpressionSyntax ParseInterpolatedStringToken() { // We don't want to make the scanner stateful (between tokens) if we can possibly avoid it. // The approach implemented here is // // (1) Scan the whole interpolated string literal as a single token. Now the statefulness of // the scanner (to match { }'s) is limited to its behavior while scanning a single token. // // (2) When the parser gets such a token, here, it spins up another scanner / parser on each of // the holes and builds a tree for the whole thing (resulting in an InterpolatedStringExpressionSyntax). // // (3) The parser discards the original token and replaces it with this tree. (In other words, // it replaces one token with a different set of tokens that have already been parsed) // // (4) On an incremental change, we widen the invalidated region to include any enclosing interpolated // string nonterminal so that we never reuse tokens inside a changed interpolated string. // // This has the secondary advantage that it can reasonably be specified. // // The substitution will end up being invisible to external APIs and clients such as the IDE, as // they have no way to ask for the stream of tokens before parsing. // var originalToken = this.EatToken(); var originalText = originalToken.ValueText; // this is actually the source text Debug.Assert(originalText[0] == '$' || originalText[0] == '@'); var isAltInterpolatedVerbatim = originalText.Length > 2 && originalText[0] == '@'; // @$ var isVerbatim = isAltInterpolatedVerbatim || (originalText.Length > 2 && originalText[1] == '@'); Debug.Assert(originalToken.Kind == SyntaxKind.InterpolatedStringToken); var interpolations = ArrayBuilder <Lexer.Interpolation> .GetInstance(); SyntaxDiagnosticInfo error = null; bool closeQuoteMissing; using (var tempLexer = new Lexer(Text.SourceText.From(originalText), this.Options, allowPreprocessorDirectives: false)) { // compute the positions of the interpolations in the original string literal, and also compute/preserve // lexical errors var info = default(Lexer.TokenInfo); tempLexer.ScanInterpolatedStringLiteralTop(interpolations, isVerbatim, ref info, ref error, out closeQuoteMissing); } // Make a token for the open quote $" or $@" or @$" var openQuoteIndex = isVerbatim ? 2 : 1; Debug.Assert(originalText[openQuoteIndex] == '"'); var openQuoteKind = isVerbatim ? SyntaxKind.InterpolatedVerbatimStringStartToken // $@ or @$ : SyntaxKind.InterpolatedStringStartToken; // $ var openQuoteText = isAltInterpolatedVerbatim ? "@$\"" : isVerbatim ? "$@\"" : "$\""; var openQuote = SyntaxFactory.Token(originalToken.GetLeadingTrivia(), openQuoteKind, openQuoteText, openQuoteText, trailing: null); if (isAltInterpolatedVerbatim) { openQuote = CheckFeatureAvailability(openQuote, MessageID.IDS_FeatureAltInterpolatedVerbatimStrings); } // Make a token for the close quote " (even if it was missing) var closeQuoteIndex = closeQuoteMissing ? originalText.Length : originalText.Length - 1; Debug.Assert(closeQuoteMissing || originalText[closeQuoteIndex] == '"'); var closeQuote = closeQuoteMissing ? SyntaxFactory.MissingToken(SyntaxKind.InterpolatedStringEndToken).TokenWithTrailingTrivia(originalToken.GetTrailingTrivia()) : SyntaxFactory.Token(null, SyntaxKind.InterpolatedStringEndToken, originalToken.GetTrailingTrivia()); var builder = _pool.Allocate <InterpolatedStringContentSyntax>(); if (interpolations.Count == 0) { // In the special case when there are no interpolations, we just construct a format string // with no inserts. We must still use String.Format to get its handling of escapes such as {{, // so we still treat it as a composite format string. var text = Substring(originalText, openQuoteIndex + 1, closeQuoteIndex - 1); if (text.Length > 0) { var token = MakeStringToken(text, text, isVerbatim, SyntaxKind.InterpolatedStringTextToken); builder.Add(SyntaxFactory.InterpolatedStringText(token)); } } else { for (int i = 0; i < interpolations.Count; i++) { var interpolation = interpolations[i]; // Add a token for text preceding the interpolation var text = Substring(originalText, (i == 0) ? (openQuoteIndex + 1) : (interpolations[i - 1].CloseBracePosition + 1), interpolation.OpenBracePosition - 1); if (text.Length > 0) { var token = MakeStringToken(text, text, isVerbatim, SyntaxKind.InterpolatedStringTextToken); builder.Add(SyntaxFactory.InterpolatedStringText(token)); } // Add an interpolation var interp = ParseInterpolation(originalText, interpolation, isVerbatim); builder.Add(interp); } // Add a token for text following the last interpolation var lastText = Substring(originalText, interpolations[interpolations.Count - 1].CloseBracePosition + 1, closeQuoteIndex - 1); if (lastText.Length > 0) { var token = MakeStringToken(lastText, lastText, isVerbatim, SyntaxKind.InterpolatedStringTextToken); builder.Add(SyntaxFactory.InterpolatedStringText(token)); } } interpolations.Free(); var result = SyntaxFactory.InterpolatedStringExpression(openQuote, builder, closeQuote); _pool.Free(builder); if (error != null) { result = result.WithDiagnosticsGreen(new[] { error }); } Debug.Assert(originalToken.ToFullString() == result.ToFullString()); // yield from text equals yield from node return(CheckFeatureAvailability(result, MessageID.IDS_FeatureInterpolatedStrings)); }
private static SyntaxToken CreateMissingIdentifierToken() { return(SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken)); }
private JavaImportDeclarationSyntax ParseJavaImportDeclaration() { if (this.IsIncrementalAndFactoryContextMatches && this.CurrentNodeKind == SyntaxKind.JavaImportDeclaration) { return((JavaImportDeclarationSyntax)this.EatNode()); } Debug.Assert(this.CurrentToken.Kind == SyntaxKind.ImportKeyword); var importKeywordToken = this.EatToken(SyntaxKind.ImportKeyword); SyntaxToken staticKeyword = null; if (this.CurrentToken.Kind == SyntaxKind.StaticKeyword) { staticKeyword = this.EatToken(SyntaxKind.StaticKeyword); } NameSyntax name; SyntaxToken semicolon; JavaImportOnDemandSuffixSyntax importOnDemand = null; //this.ParseTypeName() if (IsPossiblePackageMemberDeclaration()) { //We're worried about the case where someone already has a correct program //and they've gone back to add a using directive, but have not finished the //new directive. e.g. // // import // class Foo { // //... // } // //If the token we see after "using" could be its own top-level construct, then //we just want to insert a missing identifier and semicolon and then return to //parsing at the top-level. // //NB: there's no way this could be true for a set of tokens that form a valid //using directive, so there's no danger in checking the error case first. name = WithAdditionalDiagnostics(CreateMissingIdentifierName(), GetExpectedTokenError(SyntaxKind.IdentifierToken, this.CurrentToken.Kind)); if (this.CurrentToken.Kind == SyntaxKind.DotToken && this.PeekToken(1).Kind == SyntaxKind.AsteriskToken) { importOnDemand = _syntaxFactory.JavaImportOnDemandSuffix(this.EatToken(SyntaxKind.DotToken), this.EatToken(SyntaxKind.AsteriskToken)); } semicolon = SyntaxFactory.MissingToken(SyntaxKind.SemicolonToken); } else { //var a = this.ParseType(false); name = this.ParseQualifiedName(); if (name.IsMissing && this.PeekToken(1).Kind == SyntaxKind.SemicolonToken) { //if we can see a semicolon ahead, then the current token was //probably supposed to be an identifier name = AddTrailingSkippedSyntax(name, this.EatToken()); } if (this.CurrentToken.Kind == SyntaxKind.DotToken && this.PeekToken(1).Kind == SyntaxKind.AsteriskToken) { importOnDemand = _syntaxFactory.JavaImportOnDemandSuffix(this.EatToken(SyntaxKind.DotToken), this.EatToken(SyntaxKind.AsteriskToken)); } semicolon = this.EatToken(SyntaxKind.SemicolonToken); } return(_syntaxFactory.JavaImportDeclaration(importKeywordToken, staticKeyword, name, importOnDemand, semicolon)); }
// Returns null if we can't parse anything (even partially). private MemberDeclarationSyntax ParseMemberDeclaration(SyntaxKind parentKind, string typeName = null) { CancellationToken.ThrowIfCancellationRequested(); // don't reuse members if they were previously declared under a different type keyword kind // don't reuse existing constructors & destructors because they have to match typename errors // don't reuse methods whose name matches the new type name (they now match as possible constructors) if (this.IsIncrementalAndFactoryContextMatches) { var member = this.CurrentNode as CSharp.Syntax.MemberDeclarationSyntax; if (CanReuseMemberDeclaration(member, typeName) || CanReuseTypeDeclaration(member)) { return((MemberDeclarationSyntax)this.EatNode()); } } var annotations = this._pool.Allocate <AnnotationSyntax>(); var modifiers = this._pool.Allocate(); var saveTermState = this._termState; try { this.ParseAnnotationDeclarations(annotations); // All modifiers that might start an expression are processed above. this.ParseModifiers(modifiers); TypeParameterListSyntax typeParameterListOpt = default(TypeParameterListSyntax); if (this.CurrentToken.Kind == SyntaxKind.LessThanToken) { typeParameterListOpt = this.ParseTypeParameterList(); } // Check for constructor form if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken) { // Script: // Constructor definitions are not allowed. We parse them as method calls with semicolon missing error: // // Script(...) { ... } // ^ // missing ';' if (this.CurrentToken.ValueText == typeName) { return(this.ParseConstructorDeclaration(typeName, annotations, modifiers, typeParameterListOpt)); } // Script: // Unless there modifiers or attributes are present this is more likely to be a method call than a method definition. var token = SyntaxFactory.MissingToken(SyntaxKind.VoidKeyword); token = this.AddError(token, ErrorCode.ERR_MemberNeedsType); var voidType = _syntaxFactory.PredefinedType(token); var identifier = this.EatToken(); return(this.ParseMethodDeclaration(annotations, modifiers, voidType, identifier: identifier, typeParameterList: typeParameterListOpt, isDtor: false)); } else if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken && annotations.Count == 0) { return(this.ParseJavaInitializerMethodDeclaration(modifiers)); } //// Check for destructor form //// TODO: better error messages for script //if (this.CurrentToken.Kind == SyntaxKind.TildeToken) //{ // return this.ParseDestructorDeclaration(typeName, annotations, modifiers); //} // Check for constant (prefers const field over const local variable decl) //if (this.CurrentToken.Kind == SyntaxKind.ConstKeyword) //{ // return this.ParseConstantFieldDeclaration(annotations, modifiers, parentKind); //} // It's valid to have a type declaration here -- check for those if (CanStartTypeDeclaration(this.CurrentToken.Kind)) { return(this.ParseTypeDeclaration(annotations, modifiers)); } // Everything that's left -- methods, fields, properties, // indexers, and non-conversion operators -- starts with a type // (possibly void). Parse one. var type = this.ParseReturnType(); // <UNDONE> UNDONE: should disallow non-methods with void type here</UNDONE> // Check for misplaced modifiers. if we see any, then consider this member // terminated and restart parsing. if (GetModifier(this.CurrentToken) != SyntaxModifier.None && IsComplete(type)) { var misplacedModifier = this.CurrentToken; type = this.AddError( type, type.FullWidth + misplacedModifier.GetLeadingTriviaWidth(), misplacedModifier.Width, ErrorCode.ERR_BadModifierLocation, misplacedModifier.Text); return(_syntaxFactory.IncompleteMember(annotations, typeParameterListOpt, modifiers.ToTokenList(), type)); } if (IsFieldDeclaration(isEvent: false)) { return(this.ParseNormalFieldDeclaration(annotations, modifiers, type, parentKind)); } // At this point we can either have indexers, methods, or // properties (or something unknown). Try to break apart // the following name and determine what to do from there. SyntaxToken identifierOrThisOpt; //this.ParseMemberName( out identifierOrThisOpt, out typeParameterListOpt); this.ParseMemberName(out identifierOrThisOpt); // First, check if we got absolutely nothing. If so, then // We need to consume a bad member and try again. if (identifierOrThisOpt == null) { if (annotations.Count == 0 && modifiers.Count == 0 && type.IsMissing) { // we haven't advanced, the caller needs to consume the tokens ahead return(null); } var incompleteMember = _syntaxFactory.IncompleteMember(annotations, typeParameterListOpt, modifiers.ToTokenList(), type.IsMissing ? null : type); if (incompleteMember.ContainsDiagnostics) { return(incompleteMember); } else if (parentKind == SyntaxKind.CompilationUnit) { return(this.AddErrorToLastToken(incompleteMember, ErrorCode.ERR_NamespaceUnexpected)); } else { //the error position should indicate CurrentToken return(this.AddError( incompleteMember, incompleteMember.FullWidth + this.CurrentToken.GetLeadingTriviaWidth(), this.CurrentToken.Width, ErrorCode.ERR_InvalidMemberDecl, this.CurrentToken.Text)); } } Debug.Assert(identifierOrThisOpt != null); var dtor = identifierOrThisOpt.ValueText == "finalize" && type is PredefinedTypeSyntax && ((PredefinedTypeSyntax)type).Keyword.Kind == SyntaxKind.VoidKeyword; // treat anything else as a method. return(this.ParseMethodDeclaration(annotations, modifiers, type, identifierOrThisOpt, typeParameterListOpt, isDtor: dtor)); } finally { this._pool.Free(modifiers); this._pool.Free(annotations); this._termState = saveTermState; } }
private ExpressionSyntax ParseArrayOrObjectCreationExpression() { SimpleNameSyntax name = this.CurrentToken.Kind == SyntaxKind.IdentifierToken ? this.ParseSimpleName(NameOptions.InExpression) : null; SyntaxToken @dot = (name != null) ? this.EatToken(SyntaxKind.DotToken) : null; SyntaxToken @new = this.EatToken(SyntaxKind.NewKeyword); bool isPossibleArrayCreation = this.IsPossibleArrayCreationExpression(); var type = this.ParseTypeCore(parentIsParameter: false, isInstanceOfOrAs: false, expectSizes: isPossibleArrayCreation, isArrayCreation: isPossibleArrayCreation); if (type.Kind == SyntaxKind.ArrayType) { // Check for an initializer. InitializerExpressionSyntax initializer = null; if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) { initializer = this.ParseArrayInitializer(); } else if (type.Kind == SyntaxKind.ArrayType) { var rankSpec = ((ArrayTypeSyntax)type).RankSpecifiers[0]; if (GetNumberOfNonOmittedArraySizes(rankSpec) == 0) { type = this.AddError(type, rankSpec, ErrorCode.ERR_MissingArraySize); } } return(_syntaxFactory.ArrayCreationExpression(@new, (ArrayTypeSyntax)type, initializer)); } else { ArgumentListSyntax argumentList = null; if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) { argumentList = this.ParseParenthesizedArgumentList(); } //处理双大括号初始化 匿名类 //List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}}; // List<Character> characters = new ArrayList<Character>() { // { // for (char c = 'A'; c <= 'E'; c++) add(c); // } // }; //JavaAnonymousClassDeclarationSyntax //InitializerExpressionSyntax initializer = null; //if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) //{ // initializer = this.ParseObjectOrCollectionInitializer(); //} JavaAnonymousClassInitializerExpressionSyntax initializer = null; if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) { initializer = this.ParseJavaAnonymousClassBody(); } // we need one or the other if (argumentList == null && initializer == null) { argumentList = _syntaxFactory.ArgumentList( this.AddError(SyntaxFactory.MissingToken(SyntaxKind.OpenParenToken), ErrorCode.ERR_BadNewExpr), default(SeparatedSyntaxList <ArgumentSyntax>), SyntaxFactory.MissingToken(SyntaxKind.CloseParenToken)); } return(_syntaxFactory.ObjectCreationExpression(name, @dot, @new, type, argumentList, initializer)); } }