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)); } } }
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 )); } }
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 )); } }
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 )); } }
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); }