Esempio n. 1
0
        public char NextCharOrUnicodeEscape(
            out char surrogateCharacter,
            out SyntaxDiagnosticInfo info
            )
        {
            var ch = this.PeekChar();

            Debug.Assert(
                ch != InvalidCharacter,
                "Precondition established by all callers; required for correctness of AdvanceChar() call."
                );
            if (ch == '\\')
            {
                var ch2 = this.PeekChar(1);
                if (ch2 == 'U' || ch2 == 'u')
                {
                    return(this.ScanUnicodeEscape(
                               peek: false,
                               surrogateCharacter: out surrogateCharacter,
                               info: out info
                               ));
                }
            }

            surrogateCharacter = InvalidCharacter;
            info = null;
            this.AdvanceChar();
            return(ch);
        }
Esempio n. 2
0
        protected SyntaxDiagnosticInfo[] GetErrors(int leadingTriviaWidth)
        {
            if (_errors != null)
            {
                if (leadingTriviaWidth > 0)
                {
                    var array = new SyntaxDiagnosticInfo[_errors.Count];
                    for (int i = 0; i < _errors.Count; i++)
                    {
                        // fixup error positioning to account for leading trivia
                        array[i] = _errors[i].WithOffset(_errors[i].Offset + leadingTriviaWidth);
                    }

                    return(array);
                }
                else
                {
                    return(_errors.ToArray());
                }
            }
            else
            {
                return(null);
            }
        }
Esempio n. 3
0
        private void ScanInterpolatedStringLiteral(bool isVerbatim, ref TokenInfo info)
        {
            // We have a string of the form
            //                $" ... "
            // or, if isVerbatim is true, of possible forms
            //                $@" ... "
            //                @$" ... "
            // Where the contents contains zero or more sequences
            //                { STUFF }
            // where these curly braces delimit STUFF in expression "holes".
            // In order to properly find the closing quote of the whole string,
            // we need to locate the closing brace of each hole, as strings
            // may appear in expressions in the holes. So we
            // need to match up any braces that appear between them.
            // But in order to do that, we also need to match up any
            // /**/ comments, ' characters quotes, () parens
            // [] brackets, and "" strings, including interpolated holes in the latter.

            SyntaxDiagnosticInfo error = null;
            bool closeQuoteMissing;

            ScanInterpolatedStringLiteralTop(
                null,
                isVerbatim,
                ref info,
                ref error,
                out closeQuoteMissing
                );
            this.AddError(error);
        }
Esempio n. 4
0
            internal void ScanInterpolatedStringLiteralTop(ArrayBuilder <Interpolation> interpolations, ref TokenInfo info, out bool closeQuoteMissing)
            {
                Debug.Assert(lexer.TextWindow.PeekChar() == '$');
                lexer.TextWindow.AdvanceChar(); // $
                if (isVerbatim)
                {
                    Debug.Assert(lexer.TextWindow.PeekChar() == '@');
                    lexer.TextWindow.AdvanceChar(); // @
                }

                Debug.Assert(lexer.TextWindow.PeekChar() == '"');
                lexer.TextWindow.AdvanceChar(); // "
                ScanInterpolatedStringLiteralContents(interpolations);
                if (lexer.TextWindow.PeekChar() != '"')
                {
                    Debug.Assert(IsAtEnd());
                    if (error == null)
                    {
                        int position = IsAtEnd(true) ? lexer.TextWindow.Position - 1 : lexer.TextWindow.Position;
                        error = lexer.MakeError(position, 1, isVerbatim ? ErrorCode.ERR_UnterminatedStringLit : ErrorCode.ERR_NewlineInConst);
                    }

                    closeQuoteMissing = true;
                }
                else
                {
                    // found the closing quote
                    lexer.TextWindow.AdvanceChar(); // "
                    closeQuoteMissing = false;
                }

                info.Kind = SyntaxKind.InterpolatedStringToken;
            }
Esempio n. 5
0
 private void ScanISLNestedVerbatimString(ref SyntaxDiagnosticInfo error)
 {
     Debug.Assert(TextWindow.PeekChar() == '@');
     TextWindow.AdvanceChar();
     Debug.Assert(TextWindow.PeekChar() == '\"');
     TextWindow.AdvanceChar(); // move past quote
     while (true)
     {
         if (IsAtEnd())
         {
             // we'll get an error in the enclosing construct
             return;
         }
         char ch = TextWindow.PeekChar();
         TextWindow.AdvanceChar();
         if (ch == '\"')
         {
             if (TextWindow.PeekChar(1) == '\"')
             {
                 TextWindow.AdvanceChar(); // move past escaped quote
             }
             else
             {
                 return;
             }
         }
     }
 }
Esempio n. 6
0
        private static TSyntax UpdateDiagnosticOffset <TSyntax>(
            TSyntax node,
            int diagnosticOffsetDelta
            ) where TSyntax : CSharpSyntaxNode
        {
            DiagnosticInfo[] oldDiagnostics = node.GetDiagnostics();
            if (oldDiagnostics == null || oldDiagnostics.Length == 0)
            {
                return(node);
            }

            var numDiagnostics = oldDiagnostics.Length;

            DiagnosticInfo[] newDiagnostics = new DiagnosticInfo[numDiagnostics];
            for (int i = 0; i < numDiagnostics; i++)
            {
                DiagnosticInfo       oldDiagnostic       = oldDiagnostics[i];
                SyntaxDiagnosticInfo oldSyntaxDiagnostic = oldDiagnostic as SyntaxDiagnosticInfo;
                newDiagnostics[i] =
                    oldSyntaxDiagnostic == null
                        ? oldDiagnostic
                        : new SyntaxDiagnosticInfo(
                        oldSyntaxDiagnostic.Offset + diagnosticOffsetDelta,
                        oldSyntaxDiagnostic.Width,
                        (ErrorCode)oldSyntaxDiagnostic.Code,
                        oldSyntaxDiagnostic.Arguments
                        );
            }
            return(node.WithDiagnosticsGreen(newDiagnostics));
        }
Esempio n. 7
0
        /// <remarks>
        /// NOTE: we are specifically diverging from dev11 to improve the user experience.
        /// Since treating the "async" keyword as an identifier in older language
        /// versions can never result in a correct program, we instead accept it as the a
        /// keyword regardless of the language version and produce an error if the version
        /// is insufficient.
        /// </remarks>
        protected TNode CheckFeatureAvailability <TNode>(TNode node, MessageID feature, bool forceWarning = false)
            where TNode : CSharpSyntaxNode
        {
            LanguageVersion availableVersion = this.Options.LanguageVersion;

            if (feature == MessageID.IDS_FeatureModuleAttrLoc)
            {
                // There's a special error code for this feature, so handle it separately.
                return(availableVersion >= LanguageVersion.CSharp2
                    ? node
                    : this.AddError(node, ErrorCode.WRN_NonECMAFeature, feature.Localize()));
            }

            LanguageVersion requiredVersion = feature.RequiredVersion();

            if (availableVersion >= requiredVersion)
            {
                return(node);
            }

            if (!forceWarning)
            {
                return(this.AddError(node, availableVersion.GetErrorCode(), feature.Localize(), (int)requiredVersion));
            }

            SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(availableVersion.GetErrorCode(), feature.Localize(), (int)requiredVersion);

            return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code));
        }
Esempio n. 8
0
        protected SyntaxDiagnosticInfo[] GetErrors(int leadingTriviaWidth)
        {
            if (_errors != null)
            {
                if (leadingTriviaWidth > 0)
                {
                    var array = new SyntaxDiagnosticInfo[_errors.Count];
                    for (int i = 0; i < _errors.Count; i++)
                    {
                        // fixup error positioning to account for leading trivia
                        array[i] = _errors[i].WithOffset(_errors[i].Offset + leadingTriviaWidth);
                    }

                    return array;
                }
                else
                {
                    return _errors.ToArray();
                }
            }
            else
            {
                return null;
            }
        }
Esempio n. 9
0
            private void TrySetUnrecoverableError(SyntaxDiagnosticInfo error)
            {
                // only need to record the first error we hit
                Error ??= error;

                // No matter what, ensure that we know we hit an error we can't recover from.
                EncounteredUnrecoverableError = true;
            }
Esempio n. 10
0
 public char NextUnicodeEscape(out char surrogateCharacter, out SyntaxDiagnosticInfo info)
 {
     return(ScanUnicodeEscape(
                peek: false,
                surrogateCharacter: out surrogateCharacter,
                info: out info
                ));
 }
Esempio n. 11
0
            private void TrySetRecoverableError(SyntaxDiagnosticInfo error)
            {
                // only need to record the first error we hit
                Error ??= error;

                // Do not touch 'EncounteredUnrecoverableError'.  If we already encountered something unrecoverable,
                // that doesn't change.  And if we haven't hit something unrecoverable then we stay in that mode as this
                // is a recoverable error.
            }
Esempio n. 12
0
        private void ScanISLContents(ArrayBuilder <Interpolation> interpolations, ref SyntaxDiagnosticInfo error)
        {
            while (true)
            {
                if (IsAtEnd())
                {
                    // error: end of line before end of string
                    return;
                }
                switch (TextWindow.PeekChar())
                {
                case '\"':
                    // found the end of the string
                    return;

                case '\\':
                    TextWindow.AdvanceChar();
                    if (IsAtEnd())
                    {
                        // the caller will complain about unclosed quote
                        return;
                    }
                    else if (TextWindow.PeekChar() == '{')
                    {
                        int interpolationStart = TextWindow.Position;
                        TextWindow.AdvanceChar();
                        ScanISLHoleBalancedText('}', true, ref error);
                        int end = TextWindow.Position;
                        if (TextWindow.PeekChar() == '}')
                        {
                            TextWindow.AdvanceChar();
                        }
                        else
                        {
                            if (error == null)
                            {
                                error = MakeError(interpolationStart - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
                            }
                        }
                        if (interpolations != null)
                        {
                            interpolations.Add(new Interpolation(interpolationStart, end));
                        }
                    }
                    else
                    {
                        TextWindow.AdvanceChar();     // skip past a single escaped character
                    }
                    continue;

                default:
                    // found some other character in the string portion
                    TextWindow.AdvanceChar();
                    continue;
                }
            }
        }
Esempio n. 13
0
        protected void AddError(SyntaxDiagnosticInfo error)
        {
            if (this.errors == null)
            {
                this.errors = new List <SyntaxDiagnosticInfo>(8);
            }

            this.errors.Add(error);
        }
Esempio n. 14
0
        private InternalSyntaxTrivia AddDiagnostic(InternalSyntaxTrivia token, int tokenIndex)
        {
            string errorMessage;

            if (this.Antlr4Errors.TryGetValue(tokenIndex, out errorMessage))
            {
                SyntaxDiagnosticInfo diagnosticInfo = this.MakeError(token.GetLeadingTriviaWidth(), token.Width, Antlr4RoslynErrorCode.ERR_SyntaxError, errorMessage);
                return((InternalSyntaxTrivia)token.WithDiagnostics(new DiagnosticInfo[] { diagnosticInfo }));
            }
            return(token);
        }
Esempio n. 15
0
        protected void AddError(SyntaxDiagnosticInfo error)
        {
            if (error != null)
            {
                if (_errors == null)
                {
                    _errors = new List <SyntaxDiagnosticInfo>(8);
                }

                _errors.Add(error);
            }
        }
Esempio n. 16
0
        protected void AddError(SyntaxDiagnosticInfo error)
        {
            if (error != null)
            {
                if (this.errors == null)
                {
                    this.errors = new List<SyntaxDiagnosticInfo>(8);
                }

                this.errors.Add(error);
            }
        }
Esempio n. 17
0
 void ScanISLHoleBracketed(char start, char end, ref SyntaxDiagnosticInfo error)
 {
     Debug.Assert(start == TextWindow.PeekChar());
     TextWindow.AdvanceChar();
     ScanISLHoleBalancedText(end, false, ref error);
     if (TextWindow.PeekChar() == end)
     {
         TextWindow.AdvanceChar();
     }
     else
     {
         // an error was given by the caller
     }
 }
Esempio n. 18
0
        private void ScanISLNestedString(char quote, ref SyntaxDiagnosticInfo error)
        {
            Debug.Assert(TextWindow.PeekChar() == quote);
            TextWindow.AdvanceChar(); // move past quote
            while (true)
            {
                if (IsAtEnd())
                {
                    // we'll get an error in the enclosing construct
                    return;
                }
                char ch = TextWindow.PeekChar();
                TextWindow.AdvanceChar();
                switch (ch)
                {
                case '\"':
                case '\'':
                    if (ch == quote)
                    {
                        return;
                    }
                    break;

                case '\\':
                    ch = TextWindow.PeekChar();
                    if (IsAtEnd())
                    {
                        return;
                    }
                    else if (ch == '{' && quote == '"')
                    {
                        TextWindow.AdvanceChar();     // move past {
                        ScanISLHoleBalancedText('}', true, ref error);
                        if (TextWindow.PeekChar() == '}')
                        {
                            TextWindow.AdvanceChar();
                        }
                    }
                    else
                    {
                        TextWindow.AdvanceChar();     // move past one escaped character
                    }
                    break;
                }
            }
        }
Esempio n. 19
0
        /// <remarks>
        /// NOTE: we are specifically diverging from dev11 to improve the user experience.
        /// Since treating the "async" keyword as an identifier in older language
        /// versions can never result in a correct program, we instead accept it as a
        /// keyword regardless of the language version and produce an error if the version
        /// is insufficient.
        /// </remarks>
        protected TNode CheckFeatureAvailability <TNode>(TNode node, MessageID feature, bool forceWarning = false)
            where TNode : GreenNode
        {
            LanguageVersion availableVersion = this.Options.LanguageVersion;

            if (feature == MessageID.IDS_FeatureModuleAttrLoc)
            {
                // There's a special error code for this feature, so handle it separately.
                return(availableVersion >= LanguageVersion.CSharp2
                    ? node
                    : this.AddError(node, ErrorCode.WRN_NonECMAFeature, feature.Localize()));
            }

            if (IsFeatureEnabled(feature))
            {
                return(node);
            }

            var featureName     = feature.Localize();
            var requiredFeature = feature.RequiredFeature();

            if (requiredFeature != null)
            {
                if (forceWarning)
                {
                    SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(ErrorCode.ERR_FeatureIsExperimental, featureName, requiredFeature);
                    return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code));
                }

                return(this.AddError(node, ErrorCode.ERR_FeatureIsExperimental, featureName, requiredFeature));
            }
            else
            {
                var requiredVersion = feature.RequiredVersion();

                if (forceWarning)
                {
                    SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(availableVersion.GetErrorCode(), featureName,
                                                                            new CSharpRequiredLanguageVersion(requiredVersion));
                    return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code));
                }

                return(this.AddError(node, availableVersion.GetErrorCode(), featureName, new CSharpRequiredLanguageVersion(requiredVersion)));
            }
        }
Esempio n. 20
0
        internal void ScanInterpolatedStringLiteralTop(
            ArrayBuilder <Interpolation> interpolations,
            bool isVerbatim,
            ref TokenInfo info,
            ref SyntaxDiagnosticInfo error,
            out bool closeQuoteMissing
            )
        {
            var subScanner = new InterpolatedStringScanner(this, isVerbatim);

            subScanner.ScanInterpolatedStringLiteralTop(
                interpolations,
                ref info,
                out closeQuoteMissing
                );
            error     = subScanner.error;
            info.Text = TextWindow.GetText(false);
        }
Esempio n. 21
0
        private void ScanInterpolatedStringLiteral(ref TokenInfo info)
        {
            // We have a string of the form
            //                " ... "
            // Where the contents contains one or more sequences
            //                \{ STUFF }
            // where these curly braces delimit STUFF in expression "holes".
            // In order to properly find the closing quote of the whole string,
            // we need to locate the closing brace of each hole, as strings
            // may appear in expressions in the holes. So we
            // need to match up any braces that appear between them.
            // But in order to do that, we also need to match up any
            // /**/ comments, ' characters quotes, () parens
            // [] brackets, and "" strings, including interpolated holes in the latter.

            SyntaxDiagnosticInfo error = null;

            ScanISLTop(null, ref info, ref error);
            this.AddError(error);
            info.Text = TextWindow.GetText(false);
        }
        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));
        }
Esempio n. 23
0
        private SkippedTokensTriviaSyntax ParserErrorsAsTrivia(List <ParseErrorData> parseErrors, IDictionary <string, SourceText> includes)
        {
            // create one syntax token per error
            // and one syntax token for the main file
            // these tokens will get as many errors as needed.
            // We are only includin 1 syntax error per file (1003) and one parse error (9002)
            var textNode = SyntaxFactory.BadToken(null, _text.ToString(), null);
            var builder  = new SyntaxListBuilder(parseErrors.Count + 1);

            if (!parseErrors.IsEmpty())
            {
                bool hasSyntaxError = false;
                bool hasParserError = false;
                foreach (var e in parseErrors)
                {
                    bool add = true;
                    if (e.Code == ErrorCode.ERR_SyntaxError)
                    {
                        add            = !hasSyntaxError;
                        hasSyntaxError = true;
                    }
                    else if (e.Code == ErrorCode.ERR_ParserError)
                    {
                        add            = !hasParserError;
                        hasParserError = true;
                    }
                    if (!add)
                    {
                        continue;
                    }
                    if (e.Node != null)
                    {
                        var node = e.Node;
                        var key  = node.SourceFileName;
                        int pos  = node.Position;
                        int len  = node.FullWidth;
                        if (node.SourceSymbol != null)
                        {
                            var sym = node.SourceSymbol as XSharpToken;
                            key = sym.SourceName;
                            pos = sym.Position;
                            len = sym.FullWidth;
                        }
                        if (len <= 0 || pos < 0)
                        {
                            if (e.Node.Parent != null)
                            {
                                var xNode = e.Node as IXParseTree;
                                pos = xNode.Position;
                                len = xNode.FullWidth;
                            }
                            if (pos < 0)
                            {
                                pos = 0;
                            }
                            if (len <= 0)
                            {
                                len = 1;
                            }
                        }
                        SourceText inc = null;
                        if (key != null && includes.ContainsKey(key))
                        {
                            inc = includes[key];
                            if (pos - 1 + len > inc.Length)
                            {
                                len = inc.Length - pos + 1;
                            }
                        }
                        var diag = new SyntaxDiagnosticInfo(pos, len, e.Code, e.Args);
                        if (inc != null)
                        {
                            var incNode = SyntaxFactory.BadToken(null, inc.ToString(), null);
                            incNode       = incNode.WithAdditionalDiagnostics(diag);
                            incNode.XNode = e.Node;
                            builder.Add(incNode);
                        }
                        else
                        {
                            textNode = textNode.WithAdditionalDiagnostics(diag);
                        }
                    }
                    else
                    {
                        textNode = textNode.WithAdditionalDiagnostics(new SyntaxDiagnosticInfo(e.Code, e.Args));
                    }
                }
            }
            else
            {
                if (_options.ParseLevel == ParseLevel.Complete)
                {
                    textNode = textNode.WithAdditionalDiagnostics(new SyntaxDiagnosticInfo(ErrorCode.ERR_ParserError, "Unknown error"));
                }
            }
            builder.Add(textNode);
            return(_syntaxFactory.SkippedTokensTrivia(builder.ToList <SyntaxToken>()));
        }
Esempio n. 24
0
        public char NextCharOrUnicodeEscape(out char surrogateCharacter, out SyntaxDiagnosticInfo info)
        {
            var ch = this.PeekChar();
            Debug.Assert(ch != InvalidCharacter, "Precondition established by all callers; required for correctness of AdvanceChar() call.");
            if (ch == '\\')
            {
                var ch2 = this.PeekChar(1);
                if (ch2 == 'U' || ch2 == 'u')
                {
                    return this.ScanUnicodeEscape(peek: false, surrogateCharacter: out surrogateCharacter, info: out info);
                }
            }

            surrogateCharacter = InvalidCharacter;
            info = null;
            this.AdvanceChar();
            return ch;
        }
Esempio n. 25
0
 private void ScanFormatSpecifier()
 {
     Debug.Assert(lexer.TextWindow.PeekChar() == ':');
     lexer.TextWindow.AdvanceChar();
     while (true)
     {
         char ch = lexer.TextWindow.PeekChar();
         if (ch == '\\' && !isVerbatim)
         {
             // normal string & char constants can have escapes
             var  pos = lexer.TextWindow.Position;
             char c2;
             ch = lexer.ScanEscapeSequence(out c2);
             if ((ch == '{' || ch == '}') && error == null)
             {
                 error = lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch);
             }
         }
         else if (ch == '"')
         {
             if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
             {
                 lexer.TextWindow.AdvanceChar();
                 lexer.TextWindow.AdvanceChar();
             }
             else
             {
                 return; // premature end of string! let caller complain about unclosed interpolation
             }
         }
         else if (ch == '{')
         {
             var pos = lexer.TextWindow.Position;
             lexer.TextWindow.AdvanceChar();
             // ensure any { characters are doubled up
             if (lexer.TextWindow.PeekChar() == '{')
             {
                 lexer.TextWindow.AdvanceChar(); // {
             }
             else if (error == null)
             {
                 error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "{");
             }
         }
         else if (ch == '}')
         {
             if (lexer.TextWindow.PeekChar(1) == '}')
             {
                 lexer.TextWindow.AdvanceChar();
                 lexer.TextWindow.AdvanceChar();
             }
             else
             {
                 return; // end of interpolation
             }
         }
         else if (IsAtEnd())
         {
             return; // premature end; let caller complain
         }
         else
         {
             lexer.TextWindow.AdvanceChar();
         }
     }
 }
Esempio n. 26
0
            /// <summary>
            /// Scan past the hole inside an interpolated string literal, leaving the current character on the '}' (if any)
            /// </summary>
            private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool isHole, ref int colonPosition)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // the caller will complain
                        return;
                    }

                    char ch = lexer.TextWindow.PeekChar();
                    switch (ch)
                    {
                    case '#':
                        // preprocessor directives not allowed.
                        if (error == null)
                        {
                            error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                        }

                        lexer.TextWindow.AdvanceChar();
                        continue;

                    case '$':
                        if (lexer.TextWindow.PeekChar(1) == '"' || lexer.TextWindow.PeekChar(1) == '@' && lexer.TextWindow.PeekChar(2) == '"')
                        {
                            bool isVerbatimSubstring = lexer.TextWindow.PeekChar(1) == '@';
                            var  interpolations      = default(ArrayBuilder <Interpolation>);
                            var  info             = default(TokenInfo);
                            bool wasVerbatim      = this.isVerbatim;
                            bool wasAllowNewlines = this.allowNewlines;
                            try
                            {
                                this.isVerbatim     = isVerbatimSubstring;
                                this.allowNewlines &= isVerbatim;
                                bool closeQuoteMissing;
                                ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
                            }
                            finally
                            {
                                this.isVerbatim    = wasVerbatim;
                                this.allowNewlines = wasAllowNewlines;
                            }
                            continue;
                        }

                        goto default;

                    case ':':
                        // the first colon not nested within matching delimiters is the start of the format string
                        if (isHole)
                        {
                            Debug.Assert(colonPosition == 0);
                            colonPosition = lexer.TextWindow.Position;
                            ScanFormatSpecifier();
                            return;
                        }

                        goto default;

                    case '}':
                    case ')':
                    case ']':
                        if (ch == endingChar)
                        {
                            return;
                        }

                        if (error == null)
                        {
                            error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                        }

                        goto default;

                    case '"':
                    case '\'':
                        // handle string or character literal inside an expression hole.
                        ScanInterpolatedStringLiteralNestedString();
                        continue;

                    case '@':
                        if (lexer.TextWindow.PeekChar(1) == '"')
                        {
                            // check for verbatim string inside an expression hole.
                            ScanInterpolatedStringLiteralNestedVerbatimString();
                            continue;
                        }

                        goto default;

                    case '/':
                        switch (lexer.TextWindow.PeekChar(1))
                        {
                        case '/':
                            if (isVerbatim && allowNewlines)
                            {
                                lexer.TextWindow.AdvanceChar();         // skip /
                                lexer.TextWindow.AdvanceChar();         // skip /
                                while (!IsAtEnd(false))
                                {
                                    lexer.TextWindow.AdvanceChar();         // skip // comment character
                                }
                            }
                            else
                            {
                                // error: single-line comment not allowed in an interpolated string
                                if (error == null)
                                {
                                    error = lexer.MakeError(lexer.TextWindow.Position, 2, ErrorCode.ERR_SingleLineCommentInExpressionHole);
                                }

                                lexer.TextWindow.AdvanceChar();
                                lexer.TextWindow.AdvanceChar();
                            }
                            continue;

                        case '*':
                            // check for and scan /* comment */
                            ScanInterpolatedStringLiteralNestedComment();
                            continue;

                        default:
                            lexer.TextWindow.AdvanceChar();
                            continue;
                        }

                    case '{':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('{', '}');
                        continue;

                    case '(':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('(', ')');
                        continue;

                    case '[':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('[', ']');
                        continue;

                    default:
                        // part of code in the expression hole
                        lexer.TextWindow.AdvanceChar();
                        continue;
                    }
                }
            }
Esempio n. 27
0
        private char ScanUnicodeEscape(bool peek, out char surrogateCharacter, out SyntaxDiagnosticInfo info)
        {
            surrogateCharacter = InvalidCharacter;
            info = null;

            int  start     = this.Position;
            char character = this.PeekChar();

            Debug.Assert(character == '\\');
            this.AdvanceChar();

            character = this.PeekChar();
            if (character == 'U')
            {
                uint uintChar = 0;

                this.AdvanceChar();
                if (!SyntaxFacts.IsHexDigit(this.PeekChar()))
                {
                    if (!peek)
                    {
                        info = CreateIllegalEscapeDiagnostic(start);
                    }
                }
                else
                {
                    for (int i = 0; i < 8; i++)
                    {
                        character = this.PeekChar();
                        if (!SyntaxFacts.IsHexDigit(character))
                        {
                            if (!peek)
                            {
                                info = CreateIllegalEscapeDiagnostic(start);
                            }

                            break;
                        }

                        uintChar = (uint)((uintChar << 4) + SyntaxFacts.HexValue(character));
                        this.AdvanceChar();
                    }

                    if (uintChar > 0x0010FFFF)
                    {
                        if (!peek)
                        {
                            info = CreateIllegalEscapeDiagnostic(start);
                        }
                    }
                    else
                    {
                        character = GetCharsFromUtf32(uintChar, out surrogateCharacter);
                    }
                }
            }
            else
            {
                Debug.Assert(character == 'u' || character == 'x');

                int intChar = 0;
                this.AdvanceChar();
                if (!SyntaxFacts.IsHexDigit(this.PeekChar()))
                {
                    if (!peek)
                    {
                        info = CreateIllegalEscapeDiagnostic(start);
                    }
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        char ch2 = this.PeekChar();
                        if (!SyntaxFacts.IsHexDigit(ch2))
                        {
                            if (character == 'u')
                            {
                                if (!peek)
                                {
                                    info = CreateIllegalEscapeDiagnostic(start);
                                }
                            }

                            break;
                        }

                        intChar = (intChar << 4) + SyntaxFacts.HexValue(ch2);
                        this.AdvanceChar();
                    }

                    character = (char)intChar;
                }
            }

            return(character);
        }
Esempio n. 28
0
            internal void ScanInterpolatedStringLiteralTop(ArrayBuilder<Interpolation> interpolations, ref TokenInfo info, out bool closeQuoteMissing)
            {
                Debug.Assert(lexer.TextWindow.PeekChar() == '$');
                lexer.TextWindow.AdvanceChar(); // $
                if (isVerbatim)
                {
                    Debug.Assert(lexer.TextWindow.PeekChar() == '@');
                    lexer.TextWindow.AdvanceChar(); // @
                }

                Debug.Assert(lexer.TextWindow.PeekChar() == '"');
                lexer.TextWindow.AdvanceChar(); // "
                ScanInterpolatedStringLiteralContents(interpolations);
                if (lexer.TextWindow.PeekChar() != '"')
                {
                    Debug.Assert(IsAtEnd());
                    if (error == null)
                    {
                        int position = IsAtEnd(true) ? lexer.TextWindow.Position - 1 : lexer.TextWindow.Position;
                        error = lexer.MakeError(position, 1, isVerbatim ? ErrorCode.ERR_UnterminatedStringLit : ErrorCode.ERR_NewlineInConst);
                    }

                    closeQuoteMissing = true;
                }
                else
                {
                    // found the closing quote
                    lexer.TextWindow.AdvanceChar(); // "
                    closeQuoteMissing = false;
                }

                info.Kind = SyntaxKind.InterpolatedStringToken;
            }
Esempio n. 29
0
 public char NextUnicodeEscape(out char surrogateCharacter, out SyntaxDiagnosticInfo info)
 {
     return ScanUnicodeEscape(peek: false, surrogateCharacter: out surrogateCharacter, info: out info);
 }
Esempio n. 30
0
        private SyntaxToken Create(ref TokenInfo info, SyntaxListBuilder leading, SyntaxListBuilder trailing, SyntaxDiagnosticInfo[] errors)
        {
            Debug.Assert(info.Kind != SyntaxKind.IdentifierToken || info.StringValue != null);

            var leadingNode = SyntaxList.List(leading);
            var trailingNode = SyntaxList.List(trailing);

            SyntaxToken token;
            if (info.RequiresTextForXmlEntity)
            {
                token = SyntaxFactory.Token(leadingNode, info.Kind, info.Text, info.StringValue, trailingNode);
            }
            else
            {
                switch (info.Kind)
                {
                    case SyntaxKind.IdentifierToken:
                        token = SyntaxFactory.Identifier(info.ContextualKind, leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.NumericLiteralToken:
                        switch (info.ValueKind)
                        {
                            case SpecialType.System_Int32:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.IntValue, trailingNode);
                                break;
                            case SpecialType.System_UInt32:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.UintValue, trailingNode);
                                break;
                            case SpecialType.System_Int64:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.LongValue, trailingNode);
                                break;
                            case SpecialType.System_UInt64:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.UlongValue, trailingNode);
                                break;
                            case SpecialType.System_Single:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.FloatValue, trailingNode);
                                break;
                            case SpecialType.System_Double:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.DoubleValue, trailingNode);
                                break;
                            case SpecialType.System_Decimal:
                                token = SyntaxFactory.Literal(leadingNode, info.Text, info.DecimalValue, trailingNode);
                                break;
                            default:
                                throw ExceptionUtilities.UnexpectedValue(info.ValueKind);
                        }

                        break;
                    case SyntaxKind.InterpolatedStringToken:
                        // we do not record a separate "value" for an interpolated string token, as it must be rescanned during parsing.
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.Text, trailingNode);
                        break;
                    case SyntaxKind.StringLiteralToken:
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.CharacterLiteralToken:
                        token = SyntaxFactory.Literal(leadingNode, info.Text, info.CharValue, trailingNode);
                        break;
                    case SyntaxKind.XmlTextLiteralNewLineToken:
                        token = SyntaxFactory.XmlTextNewLine(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.XmlTextLiteralToken:
                        token = SyntaxFactory.XmlTextLiteral(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.XmlEntityLiteralToken:
                        token = SyntaxFactory.XmlEntity(leadingNode, info.Text, info.StringValue, trailingNode);
                        break;
                    case SyntaxKind.EndOfDocumentationCommentToken:
                    case SyntaxKind.EndOfFileToken:
                        token = SyntaxFactory.Token(leadingNode, info.Kind, trailingNode);
                        break;
                    case SyntaxKind.None:
                        token = SyntaxFactory.BadToken(leadingNode, info.Text, trailingNode);
                        break;

                    default:
                        Debug.Assert(SyntaxFacts.IsPunctuationOrKeyword(info.Kind));
                        token = SyntaxFactory.Token(leadingNode, info.Kind, trailingNode);
                        break;
                }
            }

            if (errors != null && (_options.DocumentationMode >= DocumentationMode.Diagnose || !InDocumentationComment))
            {
                token = token.WithDiagnosticsGreen(errors);
            }

            return token;
        }
        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 interpolated string nonterminal node).
            //
            // (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.
            //
            // Take special not of the handling of trivia. With one exception, what happens in a hole stays
            // in the hole. That means that the first token in a hole can have leading trivia, even though
            // it is not the first thing on a line. The single exception occurs when the hole is completely
            // empty of tokens, but contains some trivia. In that case we move the trivia (from the fake EOF
            // token inside the hole) to be leading trivia of the following literal part so that it doesn't
            // get dropped on the floor.
            //

            var originalToken = this.EatToken();

            Debug.Assert(originalToken.Kind == SyntaxKind.InterpolatedStringToken);
            var originalText   = originalToken.ValueText;
            var interpolations = ArrayBuilder <Lexer.Interpolation> .GetInstance();

            SyntaxDiagnosticInfo error = null;

            using (var tempLexer = new Lexer(Text.SourceText.From(originalText), this.Options))
            {
                // compute the positions of the interpolations in the original string literal
                var info = default(Lexer.TokenInfo);
                tempLexer.ScanISLTop(interpolations, ref info, ref error);
            }

            Debug.Assert(interpolations.Count != 0);
            var builder = this.pool.AllocateSeparated <InterpolatedStringInsertSyntax>();

            try
            {
                SyntaxToken stringStart = null;
                SyntaxToken stringEnd   = null;

                for (int i = 0; i < interpolations.Count; i++)
                {
                    var interpolation = interpolations[i];
                    var first         = i == 0;
                    var last          = i == (interpolations.Count - 1);

                    if (first)
                    {
                        // compute stringStart
                        var startText = originalText.Substring(0, interpolation.Start + 1);
                        stringStart = MakeStringToken(startText, SyntaxKind.InterpolatedStringStartToken).WithLeadingTrivia(originalToken.GetLeadingTrivia());
                        Debug.Assert(stringStart.Kind == SyntaxKind.InterpolatedStringStartToken);
                    }

                    CSharpSyntaxNode additionalTrivia;
                    var interpText = originalText.Substring(interpolation.Start + 1, interpolation.End - interpolation.Start - 1);
                    using (var tempLexer = new Lexer(Text.SourceText.From(interpText), this.Options))
                    {
                        using (var tempParser = new LanguageParser(tempLexer, null, null))
                        {
                            var insert = tempParser.ParseInterpolatedStringInsert();
                            insert = tempParser.ConsumeUnexpectedTokens(insert);
                            // In case the insert is empty, move the leading trivia from its EOF token to the following literal part.
                            additionalTrivia = tempParser.CurrentToken.GetLeadingTrivia();
                            builder.Add(insert);
                        }
                    }

                    if (last)
                    {
                        // compute stringEnd
                        var endText = originalText.Substring(interpolation.End);
                        stringEnd = MakeStringToken(endText, SyntaxKind.InterpolatedStringEndToken).WithLeadingTrivia(additionalTrivia).WithTrailingTrivia(originalToken.GetTrailingTrivia());
                        Debug.Assert(stringEnd.Kind == SyntaxKind.InterpolatedStringEndToken);
                    }
                    else
                    {
                        // add an interpolated string mid token for the following }...{ part
                        var midText   = originalText.Substring(interpolation.End, interpolations[i + 1].Start - interpolation.End + 1);
                        var stringMid = MakeStringToken(midText, SyntaxKind.InterpolatedStringMidToken).WithLeadingTrivia(additionalTrivia);
                        Debug.Assert(stringMid.Kind == SyntaxKind.InterpolatedStringMidToken);
                        builder.AddSeparator(stringMid);
                    }
                }

                interpolations.Free();
                var result = SyntaxFactory.InterpolatedString(stringStart, builder.ToList(), stringEnd);
                if (error != null)
                {
                    result = result.WithDiagnosticsGreen(new[] { error });
                }
                return(result);
            }
            finally
            {
                this.pool.Free(builder);
            }
        }
Esempio n. 32
0
        private char ScanUnicodeEscape(bool peek, out char surrogateCharacter, out SyntaxDiagnosticInfo info)
        {
            surrogateCharacter = InvalidCharacter;
            info = null;

            int start = this.Position;
            char character = this.PeekChar();
            Debug.Assert(character == '\\');
            this.AdvanceChar();

            character = this.PeekChar();
            if (character == 'U')
            {
                uint uintChar = 0;

                this.AdvanceChar();
                if (!SyntaxFacts.IsHexDigit(this.PeekChar()))
                {
                    if (!peek)
                    {
                        info = CreateIllegalEscapeDiagnostic(start);
                    }
                }
                else
                {
                    for (int i = 0; i < 8; i++)
                    {
                        character = this.PeekChar();
                        if (!SyntaxFacts.IsHexDigit(character))
                        {
                            if (!peek)
                            {
                                info = CreateIllegalEscapeDiagnostic(start);
                            }

                            break;
                        }

                        uintChar = (uint)((uintChar << 4) + SyntaxFacts.HexValue(character));
                        this.AdvanceChar();
                    }

                    if (uintChar > 0x0010FFFF)
                    {
                        if (!peek)
                        {
                            info = CreateIllegalEscapeDiagnostic(start);
                        }
                    }
                    else
                    {
                        character = GetCharsFromUtf32(uintChar, out surrogateCharacter);
                    }
                }
            }
            else
            {
                Debug.Assert(character == 'u' || character == 'x');

                int intChar = 0;
                this.AdvanceChar();
                if (!SyntaxFacts.IsHexDigit(this.PeekChar()))
                {
                    if (!peek)
                    {
                        info = CreateIllegalEscapeDiagnostic(start);
                    }
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        char ch2 = this.PeekChar();
                        if (!SyntaxFacts.IsHexDigit(ch2))
                        {
                            if (character == 'u')
                            {
                                if (!peek)
                                {
                                    info = CreateIllegalEscapeDiagnostic(start);
                                }
                            }

                            break;
                        }

                        intChar = (intChar << 4) + SyntaxFacts.HexValue(ch2);
                        this.AdvanceChar();
                    }

                    character = (char)intChar;
                }
            }

            return character;
        }
Esempio n. 33
0
 private void TrySetUnrecoverableError(SyntaxDiagnosticInfo error)
 {
     // only need to record the first error we hit
     Error ??= error;
 }
Esempio n. 34
0
        /// <summary>
        /// Converts skippedSyntax node into tokens and adds these as trivia on the target token.
        /// Also adds the first error (in depth-first preorder) found in the skipped syntax tree to the target token.
        /// </summary>
        internal SyntaxToken AddSkippedSyntax(SyntaxToken target, CSharpSyntaxNode skippedSyntax, bool trailing)
        {
            var builder = new SyntaxListBuilder(4);

            // the error in we'll attach to the node
            SyntaxDiagnosticInfo diagnostic = null;

            // the position of the error within the skipedSyntax node full tree
            int diagnosticOffset = 0;

            int currentOffset = 0;

            foreach (var node in skippedSyntax.EnumerateNodes())
            {
                SyntaxToken token = node as SyntaxToken;
                if (token != null)
                {
                    builder.Add(token.GetLeadingTrivia());

                    if (token.Width > 0)
                    {
                        // separate trivia from the tokens
                        SyntaxToken tk = token.WithLeadingTrivia(null).WithTrailingTrivia(null);

                        // adjust relative offsets of diagnostics attached to the token:
                        int leadingWidth = token.GetLeadingTriviaWidth();
                        if (leadingWidth > 0)
                        {
                            var tokenDiagnostics = tk.GetDiagnostics();
                            for (int i = 0; i < tokenDiagnostics.Length; i++)
                            {
                                var d = (SyntaxDiagnosticInfo)tokenDiagnostics[i];
                                tokenDiagnostics[i] = new SyntaxDiagnosticInfo(d.Offset - leadingWidth, d.Width, (ErrorCode)d.Code, d.Arguments);
                            }
                        }

                        builder.Add(SyntaxFactory.SkippedTokensTrivia(tk));
                    }
                    else
                    {
                        // do not create zero-width structured trivia, GetStructure doesn't work well for them
                        var existing = (SyntaxDiagnosticInfo)token.GetDiagnostics().FirstOrDefault();
                        if (existing != null)
                        {
                            diagnostic       = existing;
                            diagnosticOffset = currentOffset;
                        }
                    }
                    builder.Add(token.GetTrailingTrivia());

                    currentOffset += token.FullWidth;
                }
                else if (node.ContainsDiagnostics && diagnostic == null)
                {
                    // only propagate the first error to reduce noise:
                    var existing = (SyntaxDiagnosticInfo)node.GetDiagnostics().FirstOrDefault();
                    if (existing != null)
                    {
                        diagnostic       = existing;
                        diagnosticOffset = currentOffset;
                    }
                }
            }

            int triviaWidth = currentOffset;
            var trivia      = builder.ToListNode();

            // total width of everything preceding the added trivia
            int triviaOffset;

            if (trailing)
            {
                var trailingTrivia = target.GetTrailingTrivia();
                triviaOffset = target.FullWidth; //added trivia is full width (before addition)
                target       = target.WithTrailingTrivia(SyntaxList.Concat(trailingTrivia, trivia));
            }
            else
            {
                // Since we're adding triviaWidth before the token, we have to add that much to
                // the offset of each of its diagnostics.
                if (triviaWidth > 0)
                {
                    var targetDiagnostics = target.GetDiagnostics();
                    for (int i = 0; i < targetDiagnostics.Length; i++)
                    {
                        var d = (SyntaxDiagnosticInfo)targetDiagnostics[i];
                        targetDiagnostics[i] = new SyntaxDiagnosticInfo(d.Offset + triviaWidth, d.Width, (ErrorCode)d.Code, d.Arguments);
                    }
                }

                var leadingTrivia = target.GetLeadingTrivia();
                target       = target.WithLeadingTrivia(SyntaxList.Concat(trivia, leadingTrivia));
                triviaOffset = 0; //added trivia is first, so offset is zero
            }

            if (diagnostic != null)
            {
                int newOffset = triviaOffset + diagnosticOffset + diagnostic.Offset;

                target = WithAdditionalDiagnostics(target,
                                                   new SyntaxDiagnosticInfo(newOffset, diagnostic.Width, (ErrorCode)diagnostic.Code, diagnostic.Arguments)
                                                   );
            }

            return(target);
        }
Esempio n. 35
0
            private void ScanInterpolatedStringLiteralContents(ArrayBuilder <Interpolation> interpolations)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // error: end of line before end of string
                        return;
                    }

                    switch (lexer.TextWindow.PeekChar())
                    {
                    case '"':
                        if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
                        {
                            lexer.TextWindow.AdvanceChar();     // "
                            lexer.TextWindow.AdvanceChar();     // "
                            continue;
                        }
                        // found the end of the string
                        return;

                    case '}':
                        var pos = lexer.TextWindow.Position;
                        lexer.TextWindow.AdvanceChar();     // }
                        // ensure any } characters are doubled up
                        if (lexer.TextWindow.PeekChar() == '}')
                        {
                            lexer.TextWindow.AdvanceChar();     // }
                        }
                        else if (error == null)
                        {
                            error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}");
                        }
                        continue;

                    case '{':
                        if (lexer.TextWindow.PeekChar(1) == '{')
                        {
                            lexer.TextWindow.AdvanceChar();
                            lexer.TextWindow.AdvanceChar();
                        }
                        else
                        {
                            int openBracePosition = lexer.TextWindow.Position;
                            lexer.TextWindow.AdvanceChar();
                            int colonPosition = 0;
                            ScanInterpolatedStringLiteralHoleBalancedText('}', true, ref colonPosition);
                            int  closeBracePosition = lexer.TextWindow.Position;
                            bool closeBraceMissing  = false;
                            if (lexer.TextWindow.PeekChar() == '}')
                            {
                                lexer.TextWindow.AdvanceChar();
                            }
                            else
                            {
                                closeBraceMissing = true;
                                if (error == null)
                                {
                                    error = lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
                                }
                            }

                            interpolations?.Add(new Interpolation(openBracePosition, colonPosition, closeBracePosition, closeBraceMissing));
                        }
                        continue;

                    case '\\':
                        if (isVerbatim)
                        {
                            goto default;
                        }

                        var  escapeStart = lexer.TextWindow.Position;
                        char c2;
                        char ch = lexer.ScanEscapeSequence(out c2);
                        if ((ch == '{' || ch == '}') && error == null)
                        {
                            error = lexer.MakeError(escapeStart, lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch);
                        }

                        continue;

                    default:
                        // found some other character in the string portion
                        lexer.TextWindow.AdvanceChar();
                        continue;
                    }
                }
            }
Esempio n. 36
0
 internal void ScanInterpolatedStringLiteralTop(ArrayBuilder<Interpolation> interpolations, bool isVerbatim, ref TokenInfo info, ref SyntaxDiagnosticInfo error, out bool closeQuoteMissing)
 {
     var subScanner = new InterpolatedStringScanner(this, isVerbatim);
     subScanner.ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
     error = subScanner.error;
     info.Text = TextWindow.GetText(false);
 }
Esempio n. 37
0
 private void ScanFormatSpecifier()
 {
     Debug.Assert(lexer.TextWindow.PeekChar() == ':');
     lexer.TextWindow.AdvanceChar();
     while (true)
     {
         char ch = lexer.TextWindow.PeekChar();
         if (ch == '\\' && !isVerbatim)
         {
             // normal string & char constants can have escapes
             var pos = lexer.TextWindow.Position;
             char c2;
             ch = lexer.ScanEscapeSequence(out c2);
             if ((ch == '{' || ch == '}') && error == null)
             {
                 error = lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch);
             }
         }
         else if (ch == '"')
         {
             if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
             {
                 lexer.TextWindow.AdvanceChar();
                 lexer.TextWindow.AdvanceChar();
             }
             else
             {
                 return; // premature end of string! let caller complain about unclosed interpolation
             }
         }
         else if (ch == '{')
         {
             var pos = lexer.TextWindow.Position;
             lexer.TextWindow.AdvanceChar();
             // ensure any { characters are doubled up
             if (lexer.TextWindow.PeekChar() == '{')
             {
                 lexer.TextWindow.AdvanceChar(); // {
             }
             else if (error == null)
             {
                 error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "{");
             }
         }
         else if (ch == '}')
         {
             if (lexer.TextWindow.PeekChar(1) == '}')
             {
                 lexer.TextWindow.AdvanceChar();
                 lexer.TextWindow.AdvanceChar();
             }
             else
             {
                 return; // end of interpolation
             }
         }
         else if (IsAtEnd())
         {
             return; // premature end; let caller complain
         }
         else
         {
             lexer.TextWindow.AdvanceChar();
         }
     }
 }
Esempio n. 38
0
            private void ScanInterpolatedStringLiteralContents(ArrayBuilder<Interpolation> interpolations)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // error: end of line before end of string
                        return;
                    }

                    switch (lexer.TextWindow.PeekChar())
                    {
                        case '"':
                            if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
                            {
                                lexer.TextWindow.AdvanceChar(); // "
                                lexer.TextWindow.AdvanceChar(); // "
                                continue;
                            }
                            // found the end of the string
                            return;
                        case '}':
                            var pos = lexer.TextWindow.Position;
                            lexer.TextWindow.AdvanceChar(); // }
                            // ensure any } characters are doubled up
                            if (lexer.TextWindow.PeekChar() == '}')
                            {
                                lexer.TextWindow.AdvanceChar(); // }
                            }
                            else if (error == null)
                            {
                                error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}");
                            }
                            continue;
                        case '{':
                            if (lexer.TextWindow.PeekChar(1) == '{')
                            {
                                lexer.TextWindow.AdvanceChar();
                                lexer.TextWindow.AdvanceChar();
                            }
                            else
                            {
                                int openBracePosition = lexer.TextWindow.Position;
                                lexer.TextWindow.AdvanceChar();
                                int colonPosition = 0;
                                ScanInterpolatedStringLiteralHoleBalancedText('}', true, ref colonPosition);
                                int closeBracePosition = lexer.TextWindow.Position;
                                bool closeBraceMissing = false;
                                if (lexer.TextWindow.PeekChar() == '}')
                                {
                                    lexer.TextWindow.AdvanceChar();
                                }
                                else
                                {
                                    closeBraceMissing = true;
                                    if (error == null)
                                    {
                                        error = lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
                                    }
                                }

                                interpolations?.Add(new Interpolation(openBracePosition, colonPosition, closeBracePosition, closeBraceMissing));
                            }
                            continue;
                        case '\\':
                            if (isVerbatim)
                            {
                                goto default;
                            }

                            var escapeStart = lexer.TextWindow.Position;
                            char c2;
                            char ch = lexer.ScanEscapeSequence(out c2);
                            if ((ch == '{' || ch == '}') && error == null)
                            {
                                error = lexer.MakeError(escapeStart, lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch);
                            }

                            continue;
                        default:
                            // found some other character in the string portion
                            lexer.TextWindow.AdvanceChar();
                            continue;
                    }
                }
            }
Esempio n. 39
0
            private void ScanInterpolatedStringLiteralContents(ArrayBuilder <Interpolation> interpolations)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // error: end of line before end of string
                        return;
                    }

                    switch (lexer.TextWindow.PeekChar())
                    {
                    case '"' when RecoveringFromRunawayLexing():
                        // When recovering from mismatched delimiters, we consume the next
                        // quote character as the close quote for the interpolated string. In
                        // practice this gets us out of trouble in scenarios we've encountered.
                        // See, for example, https://github.com/dotnet/roslyn/issues/44789
                        return;

                    case '"':
                        if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
                        {
                            lexer.TextWindow.AdvanceChar();     // "
                            lexer.TextWindow.AdvanceChar();     // "
                            continue;
                        }
                        // found the end of the string
                        return;

                    case '}':
                        var pos = lexer.TextWindow.Position;
                        lexer.TextWindow.AdvanceChar();     // }
                        // ensure any } characters are doubled up
                        if (lexer.TextWindow.PeekChar() == '}')
                        {
                            lexer.TextWindow.AdvanceChar();     // }
                        }
                        else if (error == null)
                        {
                            error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}");
                        }
                        continue;

                    case '{':
                        if (lexer.TextWindow.PeekChar(1) == '{')
                        {
                            lexer.TextWindow.AdvanceChar();
                            lexer.TextWindow.AdvanceChar();
                        }
                        else
                        {
                            int openBracePosition = lexer.TextWindow.Position;
                            lexer.TextWindow.AdvanceChar();
                            int colonPosition = 0;
                            ScanInterpolatedStringLiteralHoleBalancedText('}', true, ref colonPosition);
                            int  closeBracePosition = lexer.TextWindow.Position;
                            bool closeBraceMissing  = false;
                            if (lexer.TextWindow.PeekChar() == '}')
                            {
                                lexer.TextWindow.AdvanceChar();
                            }
                            else
                            {
                                closeBraceMissing = true;
                                if (error == null)
                                {
                                    error = lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
                                }
                            }

                            interpolations?.Add(new Interpolation(openBracePosition, colonPosition, closeBracePosition, closeBraceMissing));
                        }
                        continue;

                    case '\\':
                        if (isVerbatim)
                        {
                            goto default;
                        }

                        var  escapeStart = lexer.TextWindow.Position;
                        char c2;
                        char ch = lexer.ScanEscapeSequence(out c2);
                        if ((ch == '{' || ch == '}') && error == null)
                        {
                            error = lexer.MakeError(escapeStart, lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch);
                        }

                        continue;

                    default:
                        // found some other character in the string portion
                        lexer.TextWindow.AdvanceChar();
                        continue;
                    }
                }
            }
Esempio n. 40
0
            /// <summary>
            /// Scan past the hole inside an interpolated string literal, leaving the current character on the '}' (if any)
            /// </summary>
            private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool isHole, ref int colonPosition)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // the caller will complain
                        return;
                    }

                    char ch = lexer.TextWindow.PeekChar();
                    switch (ch)
                    {
                        case '#':
                            // preprocessor directives not allowed.
                            if (error == null)
                            {
                                error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                            }

                            lexer.TextWindow.AdvanceChar();
                            continue;
                        case '$':
                            if (lexer.TextWindow.PeekChar(1) == '"' || lexer.TextWindow.PeekChar(1) == '@' && lexer.TextWindow.PeekChar(2) == '"')
                            {
                                bool isVerbatimSubstring = lexer.TextWindow.PeekChar(1) == '@';
                                var interpolations = default(ArrayBuilder<Interpolation>);
                                var info = default(TokenInfo);
                                bool wasVerbatim = this.isVerbatim;
                                bool wasAllowNewlines = this.allowNewlines;
                                try
                                {
                                    this.isVerbatim = isVerbatimSubstring;
                                    this.allowNewlines &= isVerbatim;
                                    bool closeQuoteMissing;
                                    ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
                                }
                                finally
                                {
                                    this.isVerbatim = wasVerbatim;
                                    this.allowNewlines = wasAllowNewlines;
                                }
                                continue;
                            }

                            goto default;
                        case ':':
                            // the first colon not nested within matching delimiters is the start of the format string
                            if (isHole)
                            {
                                Debug.Assert(colonPosition == 0);
                                colonPosition = lexer.TextWindow.Position;
                                ScanFormatSpecifier();
                                return;
                            }

                            goto default;
                        case '}':
                        case ')':
                        case ']':
                            if (ch == endingChar)
                            {
                                return;
                            }

                            if (error == null)
                            {
                                error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                            }

                            goto default;
                        case '"':
                        case '\'':
                            // handle string or character literal inside an expression hole.
                            ScanInterpolatedStringLiteralNestedString(ch);
                            continue;
                        case '@':
                            if (lexer.TextWindow.PeekChar(1) == '"')
                            {
                                // check for verbatim string inside an expression hole.
                                ScanInterpolatedStringLiteralNestedVerbatimString();
                                continue;
                            }

                            goto default;
                        case '/':
                            switch (lexer.TextWindow.PeekChar(1))
                            {
                                case '/':
                                    if (isVerbatim && allowNewlines)
                                    {
                                        lexer.TextWindow.AdvanceChar(); // skip /
                                        lexer.TextWindow.AdvanceChar(); // skip /
                                        while (!IsAtEnd(false))
                                        {
                                            lexer.TextWindow.AdvanceChar(); // skip // comment character
                                        }
                                    }
                                    else
                                    {
                                        // error: single-line comment not allowed in an interpolated string
                                        if (error == null)
                                        {
                                            error = lexer.MakeError(lexer.TextWindow.Position, 2, ErrorCode.ERR_SingleLineCommentInExpressionHole);
                                        }

                                        lexer.TextWindow.AdvanceChar();
                                        lexer.TextWindow.AdvanceChar();
                                    }
                                    continue;
                                case '*':
                                    // check for and scan /* comment */
                                    ScanInterpolatedStringLiteralNestedComment();
                                    continue;
                                default:
                                    lexer.TextWindow.AdvanceChar();
                                    continue;
                            }
                        case '{':
                            // TODO: after the colon this has no special meaning.
                            ScanInterpolatedStringLiteralHoleBracketed('{', '}');
                            continue;
                        case '(':
                            // TODO: after the colon this has no special meaning.
                            ScanInterpolatedStringLiteralHoleBracketed('(', ')');
                            continue;
                        case '[':
                            // TODO: after the colon this has no special meaning.
                            ScanInterpolatedStringLiteralHoleBracketed('[', ']');
                            continue;
                        default:
                            // part of code in the expression hole
                            lexer.TextWindow.AdvanceChar();
                            continue;
                    }
                }
            }
Esempio n. 41
0
            private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool isHole, ref int colonPosition)
            {
                while (true)
                {
                    if (IsAtEnd())
                    {
                        // the caller will complain
                        return;
                    }

                    char ch = lexer.TextWindow.PeekChar();
                    switch (ch)
                    {
                    case '#':
                        // preprocessor directives not allowed.
                        if (error == null)
                        {
                            error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                        }

                        lexer.TextWindow.AdvanceChar();
                        continue;

                    case '$':
                        if (lexer.TextWindow.PeekChar(1) == '"' || lexer.TextWindow.PeekChar(1) == '@' && lexer.TextWindow.PeekChar(2) == '"')
                        {
                            bool isVerbatimSubstring = lexer.TextWindow.PeekChar(1) == '@';
                            var  interpolations      = (ArrayBuilder <Interpolation>)null;
                            var  info             = default(TokenInfo);
                            bool wasVerbatim      = this.isVerbatim;
                            bool wasAllowNewlines = this.allowNewlines;
                            try
                            {
                                this.isVerbatim     = isVerbatimSubstring;
                                this.allowNewlines &= isVerbatim;
                                bool closeQuoteMissing;
                                ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
                            }
                            finally
                            {
                                this.isVerbatim    = wasVerbatim;
                                this.allowNewlines = wasAllowNewlines;
                            }
                            continue;
                        }

                        goto default;

                    case ':':
                        // the first colon not nested within matching delimiters is the start of the format string
                        if (isHole)
                        {
                            Debug.Assert(colonPosition == 0);
                            colonPosition = lexer.TextWindow.Position;
                            ScanFormatSpecifier();
                            return;
                        }

                        goto default;

                    case '}':
                    case ')':
                    case ']':
                        if (ch == endingChar)
                        {
                            return;
                        }

                        if (error == null)
                        {
                            error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
                        }

                        goto default;

                    case '"' when RecoveringFromRunawayLexing():
                        // When recovering from mismatched delimiters, we consume the next
                        // quote character as the close quote for the interpolated string. In
                        // practice this gets us out of trouble in scenarios we've encountered.
                        // See, for example, https://github.com/dotnet/roslyn/issues/44789
                        return;

                    case '"':
                    case '\'':
                        // handle string or character literal inside an expression hole.
                        ScanInterpolatedStringLiteralNestedString();
                        continue;

                    case '@':
                        if (lexer.TextWindow.PeekChar(1) == '"' && !RecoveringFromRunawayLexing())
                        {
                            // check for verbatim string inside an expression hole.
                            ScanInterpolatedStringLiteralNestedVerbatimString();
                            continue;
                        }
                        else if (lexer.TextWindow.PeekChar(1) == '$' && lexer.TextWindow.PeekChar(2) == '"')
                        {
                            lexer.CheckFeatureAvailability(MessageID.IDS_FeatureAltInterpolatedVerbatimStrings);
                            var  interpolations   = (ArrayBuilder <Interpolation>)null;
                            var  info             = default(TokenInfo);
                            bool wasVerbatim      = this.isVerbatim;
                            bool wasAllowNewlines = this.allowNewlines;
                            try
                            {
                                this.isVerbatim    = true;
                                this.allowNewlines = true;
                                bool closeQuoteMissing;
                                ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
                            }
                            finally
                            {
                                this.isVerbatim    = wasVerbatim;
                                this.allowNewlines = wasAllowNewlines;
                            }
                            continue;
                        }

                        goto default;

                    case '/':
                        switch (lexer.TextWindow.PeekChar(1))
                        {
                        case '/':
                            if (isVerbatim && allowNewlines)
                            {
                                lexer.TextWindow.AdvanceChar();         // skip /
                                lexer.TextWindow.AdvanceChar();         // skip /
                                while (!IsAtEnd(false))
                                {
                                    lexer.TextWindow.AdvanceChar();         // skip // comment character
                                }
                            }
                            else
                            {
                                // error: single-line comment not allowed in an interpolated string
                                if (error == null)
                                {
                                    error = lexer.MakeError(lexer.TextWindow.Position, 2, ErrorCode.ERR_SingleLineCommentInExpressionHole);
                                }

                                lexer.TextWindow.AdvanceChar();
                                lexer.TextWindow.AdvanceChar();
                            }
                            continue;

                        case '*':
                            // check for and scan /* comment */
                            ScanInterpolatedStringLiteralNestedComment();
                            continue;

                        default:
                            lexer.TextWindow.AdvanceChar();
                            continue;
                        }

                    case '{':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('{', '}');
                        continue;

                    case '(':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('(', ')');
                        continue;

                    case '[':
                        // TODO: after the colon this has no special meaning.
                        ScanInterpolatedStringLiteralHoleBracketed('[', ']');
                        continue;

                    default:
                        // part of code in the expression hole
                        lexer.TextWindow.AdvanceChar();
                        continue;
                    }
                }
            }