예제 #1
0
        private DirectiveTriviaSyntax ParseElifDirective(SyntaxToken hash, SyntaxToken keyword, bool isActive, bool endIsActive)
        {
            var expr = this.ParseExpression();
            var eod  = this.ParseEndOfDirective(ignoreErrors: false);

            if (_context.HasPreviousIfOrElif())
            {
                var isTrue      = this.EvaluateBool(expr);
                var branchTaken = endIsActive && isTrue && !_context.PreviousBranchTaken();
                return(SyntaxFactory.ElifDirectiveTrivia(hash, keyword, expr, eod, endIsActive, branchTaken, isTrue));
            }
            else
            {
                eod = eod.TokenWithLeadingTrivia(SyntaxList.Concat(SyntaxFactory.DisabledText(expr.ToFullString()), eod.GetLeadingTrivia()));
                if (_context.HasUnfinishedRegion())
                {
                    return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_EndRegionDirectiveExpected));
                }
                else if (_context.HasUnfinishedIf())
                {
                    return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_EndifDirectiveExpected));
                }
                else
                {
                    return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_UnexpectedDirective));
                }
            }
        }
예제 #2
0
        private DirectiveTriviaSyntax ParseEndIfDirective(
            SyntaxToken hash,
            SyntaxToken keyword,
            bool isActive,
            bool endIsActive
            )
        {
            var eod = this.ParseEndOfDirective(ignoreErrors: false);

            if (_context.HasUnfinishedIf())
            {
                return(SyntaxFactory.EndIfDirectiveTrivia(hash, keyword, eod, endIsActive));
            }
            else if (_context.HasUnfinishedRegion())
            {
                // CONSIDER: dev10 actually pops the region off the directive stack here.
                // See if (tok == PPT_ENDIF) in CSourceData::CPreprocessor::ScanPreprocessorIfSection.
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_EndRegionDirectiveExpected
                           ));
            }
            else
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_UnexpectedDirective
                           ));
            }
        }
예제 #3
0
        private DirectiveTriviaSyntax ParseEndRegionDirective(
            SyntaxToken hash,
            SyntaxToken keyword,
            bool isActive
            )
        {
            var eod = this.ParseEndOfDirectiveWithOptionalPreprocessingMessage();

            if (_context.HasUnfinishedRegion())
            {
                return(SyntaxFactory.EndRegionDirectiveTrivia(hash, keyword, eod, isActive));
            }
            else if (_context.HasUnfinishedIf())
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_EndifDirectiveExpected
                           ));
            }
            else
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_UnexpectedDirective
                           ));
            }
        }
예제 #4
0
        private DirectiveTriviaSyntax ParseElseDirective(
            SyntaxToken hash,
            SyntaxToken keyword,
            bool isActive,
            bool endIsActive
            )
        {
            var eod = this.ParseEndOfDirective(ignoreErrors: false);

            if (_context.HasPreviousIfOrElif())
            {
                var branchTaken = endIsActive && !_context.PreviousBranchTaken();
                return(SyntaxFactory.ElseDirectiveTrivia(
                           hash,
                           keyword,
                           eod,
                           endIsActive,
                           branchTaken
                           ));
            }
            else if (_context.HasUnfinishedRegion())
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_EndRegionDirectiveExpected
                           ));
            }
            else if (_context.HasUnfinishedIf())
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_EndifDirectiveExpected
                           ));
            }
            else
            {
                return(this.AddError(
                           SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive),
                           ErrorCode.ERR_UnexpectedDirective
                           ));
            }
        }
예제 #5
0
        public CSharpSyntaxNode ParseDirective(
            bool isActive,
            bool endIsActive,
            bool isAfterFirstTokenInFile,
            bool isAfterNonWhitespaceOnLine)
        {
            var hashPosition = lexer.TextWindow.Position;
            var hash         = this.EatToken(SyntaxKind.HashToken, false);

            if (isAfterNonWhitespaceOnLine)
            {
                hash = this.AddError(hash, ErrorCode.ERR_BadDirectivePlacement);
            }

            // The behavior of these directives when isActive is false is somewhat complicated.
            // The key functions in the native compiler are ScanPreprocessorIfSection and
            // ScanAndIgnoreDirective in CSourceData::CPreprocessor.
            // Key points:
            //   1) #error, #warning, #line, and #pragma have no effect and produce no diagnostics.
            //   2) #if, #else, #elif, #endif, #region, and #endregion must still nest correctly.
            //   3) #define and #undef produce diagnostics but have no effect.
            // #reference, #load and #! are new, but they do not require nesting behavior, so we'll
            // ignore their diagnostics (as in (1) above).

            CSharpSyntaxNode result;
            SyntaxKind       contextualKind = this.CurrentToken.ContextualKind;

            switch (contextualKind)
            {
            case SyntaxKind.IfKeyword:
                result = this.ParseIfDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.ElifKeyword:
                result = this.ParseElifDirective(hash, this.EatContextualToken(contextualKind), isActive, endIsActive);
                break;

            case SyntaxKind.ElseKeyword:
                result = this.ParseElseDirective(hash, this.EatContextualToken(contextualKind), isActive, endIsActive);
                break;

            case SyntaxKind.EndIfKeyword:
                result = this.ParseEndIfDirective(hash, this.EatContextualToken(contextualKind), isActive, endIsActive);
                break;

            case SyntaxKind.RegionKeyword:
                result = this.ParseRegionDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.EndRegionKeyword:
                result = this.ParseEndRegionDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.DefineKeyword:
            case SyntaxKind.UndefKeyword:
                result = this.ParseDefineOrUndefDirective(hash, this.EatContextualToken(contextualKind), isActive, isAfterFirstTokenInFile && !isAfterNonWhitespaceOnLine);
                break;

            case SyntaxKind.ErrorKeyword:
            case SyntaxKind.WarningKeyword:
                result = this.ParseErrorOrWarningDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.LineKeyword:
                result = this.ParseLineDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.PragmaKeyword:
                result = this.ParsePragmaDirective(hash, this.EatContextualToken(contextualKind), isActive);
                break;

            case SyntaxKind.ReferenceKeyword:
                result = this.ParseReferenceDirective(hash, this.EatContextualToken(contextualKind), isActive, isAfterFirstTokenInFile && !isAfterNonWhitespaceOnLine);
                break;

            case SyntaxKind.LoadKeyword:
                result = this.ParseLoadDirective(hash, this.EatContextualToken(contextualKind), isActive, isAfterFirstTokenInFile && !isAfterNonWhitespaceOnLine);
                break;

            default:
                if (lexer.Options.Kind == SourceCodeKind.Script && contextualKind == SyntaxKind.ExclamationToken && hashPosition == 0 && !hash.HasTrailingTrivia)
                {
                    result = this.ParseShebangDirective(hash, this.EatToken(SyntaxKind.ExclamationToken), isActive);
                }
                else
                {
                    var id  = this.EatToken(SyntaxKind.IdentifierToken, false);
                    var end = this.ParseEndOfDirective(ignoreErrors: true);
                    if (!isAfterNonWhitespaceOnLine)
                    {
                        if (!id.IsMissing)
                        {
                            id = this.AddError(id, ErrorCode.ERR_PPDirectiveExpected);
                        }
                        else
                        {
                            hash = this.AddError(hash, ErrorCode.ERR_PPDirectiveExpected);
                        }
                    }

                    result = SyntaxFactory.BadDirectiveTrivia(hash, id, end, isActive);
                }

                break;
            }

            return(result);
        }