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);
        }
Example #2
0
        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);
        }
Example #3
0
        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));
        }
Example #5
0
 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));
        }
Example #7
0
        // 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));
            }
        }