提交 6c5767b2 编写于 作者: K Kevin Halverson

Implement parsing for #load directive...

上级 e48b532e
......@@ -5362,6 +5362,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to #load is only allowed in scripts.
/// </summary>
internal static string ERR_LoadDirectiveOnlyAllowedInScripts {
get {
return ResourceManager.GetString("ERR_LoadDirectiveOnlyAllowedInScripts", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Local &apos;{0}&apos; or its members cannot have their address taken and be used inside an anonymous method or lambda expression.
/// </summary>
......@@ -7027,6 +7036,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use #load after first token in file.
/// </summary>
internal static string ERR_PPLoadFollowsToken {
get {
return ResourceManager.GetString("ERR_PPLoadFollowsToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use #r after first token in file.
/// </summary>
......
......@@ -4641,4 +4641,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_DebugEntryPointNotSourceMethodDefinition" xml:space="preserve">
<value>Debug entry point must be a definition of a method declared in the current compilation.</value>
</data>
<data name="ERR_LoadDirectiveOnlyAllowedInScripts" xml:space="preserve">
<value>#load is only allowed in scripts</value>
</data>
<data name="ERR_PPLoadFollowsToken" xml:space="preserve">
<value>Cannot use #load after first token in file</value>
</data>
</root>
\ No newline at end of file
......@@ -1312,5 +1312,7 @@ internal enum ErrorCode
WRN_AlignmentMagnitude = 8094,
ERR_ConstantStringTooLong = 8095,
ERR_DebugEntryPointNotSourceMethodDefinition = 8096,
ERR_LoadDirectiveOnlyAllowedInScripts = 8097,
ERR_PPLoadFollowsToken = 8098,
}
}
......@@ -37,8 +37,8 @@ internal DirectiveParser(Lexer lexer, DirectiveStack context)
// 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 is new, but it does not require nesting behavior, so we'll ignore its
// diagnostics (as in (1) above).
// #reference, #load and #! are new, but they do not require nesting behavior, so we'll
// ignore their diagnostics (as in (1) above).
SyntaxKind contextualKind = this.CurrentToken.ContextualKind;
switch (contextualKind)
......@@ -89,6 +89,10 @@ internal DirectiveParser(Lexer lexer, DirectiveStack context)
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:
var id = this.EatToken(SyntaxKind.IdentifierToken, false);
var end = this.ParseEndOfDirective(ignoreErrors: true);
......@@ -359,13 +363,32 @@ private DirectiveTriviaSyntax ParseReferenceDirective(SyntaxToken hash, SyntaxTo
}
}
SyntaxToken file = this.EatToken(SyntaxKind.StringLiteralToken, ErrorCode.ERR_ExpectedPPFile, reportError: isActive);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive, afterPragma: false, afterLineNumber: false, afterReference: true);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive);
return SyntaxFactory.ReferenceDirectiveTrivia(hash, keyword, file, end, isActive);
}
private DirectiveTriviaSyntax ParseLoadDirective(SyntaxToken hash, SyntaxToken keyword, bool isActive, bool isFollowingToken)
{
if (isActive)
{
if (Options.Kind == SourceCodeKind.Regular)
{
keyword = this.AddError(keyword, ErrorCode.ERR_LoadDirectiveOnlyAllowedInScripts);
}
else if (isFollowingToken)
{
keyword = this.AddError(keyword, ErrorCode.ERR_PPLoadFollowsToken);
}
}
SyntaxToken file = this.EatToken(SyntaxKind.StringLiteralToken, ErrorCode.ERR_ExpectedPPFile, reportError: isActive);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive);
return SyntaxFactory.LoadDirectiveTrivia(hash, keyword, file, end, isActive);
}
private DirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, SyntaxToken pragma, bool isActive)
{
pragma = CheckFeatureAvailability(pragma, MessageID.IDS_FeaturePragma);
......@@ -512,7 +535,7 @@ private SyntaxToken ParseEndOfDirectiveWithOptionalPreprocessingMessage()
return endOfDirective;
}
private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = false, bool afterLineNumber = false, bool afterReference = false)
private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = false, bool afterLineNumber = false)
{
var skippedTokens = new SyntaxListBuilder<SyntaxToken>();
......@@ -524,7 +547,7 @@ private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = fa
if (!ignoreErrors)
{
ErrorCode errorCode = ErrorCode.ERR_EndOfPPLineExpected;
var errorCode = ErrorCode.ERR_EndOfPPLineExpected;
if (afterPragma)
{
errorCode = ErrorCode.WRN_EndOfPPLineExpected;
......@@ -533,10 +556,6 @@ private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = fa
{
errorCode = ErrorCode.ERR_MissingPPFile;
}
else if (afterReference)
{
errorCode = ErrorCode.ERR_ExpectedPPFile;
}
skippedTokens.Add(this.AddError(this.EatToken().WithoutDiagnosticsGreen(), errorCode));
}
......
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.WithKind(Microsoft.CodeAnalysis.SourceCodeKind kind) -> Microsoft.CodeAnalysis.CSharp.CSharpParseOptions
Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax.GetLoadDirectives() -> System.Collections.Generic.IList<Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax>
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.LoadKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken loadKeyword, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithLoadKeyword(Microsoft.CodeAnalysis.SyntaxToken loadKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadDirectiveTrivia = 8923 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadKeyword = 8485 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.ShebangCommentTrivia = 8922 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
override Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.CommonWithKind(Microsoft.CodeAnalysis.SourceCodeKind kind) -> Microsoft.CodeAnalysis.ParseOptions
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.IsActive.get -> bool
static Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser.Interactive.get -> Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser
static Microsoft.CodeAnalysis.CSharp.CSharpCompilation.CreateSubmission(string assemblyName, Microsoft.CodeAnalysis.SyntaxTree syntaxTree = null, System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.MetadataReference> references = null, Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions options = null, Microsoft.CodeAnalysis.Compilation previousSubmission = null, System.Type returnType = null, System.Type hostObjectType = null) -> Microsoft.CodeAnalysis.CSharp.CSharpCompilation
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation, bool elasticTrivia) -> Microsoft.CodeAnalysis.SyntaxToken
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation, bool elasticTrivia) -> Microsoft.CodeAnalysis.SyntaxTriviaList
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LoadDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LoadDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken loadKeyword, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> TResult
\ No newline at end of file
......@@ -25,6 +25,16 @@ internal IList<ReferenceDirectiveTriviaSyntax> GetReferenceDirectives(Func<Refer
return firstToken.GetDirectives<ReferenceDirectiveTriviaSyntax>(filter);
}
/// <summary>
/// Returns #r directives specified in the compilation.
/// </summary>
public IList<LoadDirectiveTriviaSyntax> GetLoadDirectives()
{
// #load directives are always on the first token of the compilation unit.
var firstToken = (SyntaxNodeOrToken)this.GetFirstToken(includeZeroWidth: true);
return firstToken.GetDirectives<LoadDirectiveTriviaSyntax>(filter: null);
}
internal Syntax.InternalSyntax.DirectiveStack GetConditionalDirectivesStack()
{
IEnumerable<DirectiveTriviaSyntax> directives = this.GetDirectives(filter: IsActiveConditionalDirective);
......
......@@ -3979,4 +3979,20 @@
</Field>
<Field Name="IsActive" Type="bool" Override="true"/>
</Node>
<Node Name="LoadDirectiveTriviaSyntax" Base="DirectiveTriviaSyntax">
<Kind Name="LoadDirectiveTrivia"/>
<Field Name="HashToken" Type="SyntaxToken" Override="true">
<Kind Name="HashToken"/>
</Field>
<Field Name="LoadKeyword" Type="SyntaxToken">
<Kind Name="LoadKeyword"/>
</Field>
<Field Name="File" Type="SyntaxToken">
<Kind Name="StringLiteralToken"/>
</Field>
<Field Name="EndOfDirectiveToken" Type="SyntaxToken" Override="true">
<Kind Name="EndOfDirectiveToken"/>
</Field>
<Field Name="IsActive" Type="bool" Override="true"/>
</Node>
</Tree>
......@@ -209,6 +209,7 @@ public enum SyntaxKind : ushort
DisableKeyword = 8479,
RestoreKeyword = 8480,
ReferenceKeyword = 8481,
LoadKeyword = 8485,
InterpolatedStringStartToken = 8482, // $"
InterpolatedStringEndToken = 8483, // "
......@@ -530,5 +531,6 @@ public enum SyntaxKind : ushort
InterpolationFormatClause = 8921,
ShebangCommentTrivia = 8922,
LoadDirectiveTrivia = 8923,
}
}
......@@ -87,6 +87,7 @@ public static bool IsPreprocessorKeyword(SyntaxKind kind)
case SyntaxKind.DisableKeyword:
case SyntaxKind.RestoreKeyword:
case SyntaxKind.ReferenceKeyword:
case SyntaxKind.LoadKeyword:
return true;
default:
return false;
......@@ -193,6 +194,7 @@ public static bool IsAnyToken(SyntaxKind kind)
case SyntaxKind.InterpolatedVerbatimStringStartToken:
case SyntaxKind.InterpolatedStringTextToken:
case SyntaxKind.InterpolatedStringEndToken:
case SyntaxKind.LoadKeyword:
return true;
default:
return false;
......@@ -1020,6 +1022,8 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
return SyntaxKind.RestoreKeyword;
case "r":
return SyntaxKind.ReferenceKeyword;
case "load":
return SyntaxKind.LoadKeyword;
default:
return SyntaxKind.None;
}
......@@ -1496,6 +1500,8 @@ public static string GetText(SyntaxKind kind)
return "restore";
case SyntaxKind.ReferenceKeyword:
return "r";
case SyntaxKind.LoadKeyword:
return "load";
// contextual keywords
case SyntaxKind.YieldKeyword:
......
......@@ -9,8 +9,6 @@
using Roslyn.Test.Utilities;
using Xunit;
//test
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
#region Local types for verification
......@@ -3810,5 +3808,67 @@ public void TestReferenceWithVariousFileNameFormats()
}
#endregion
#region #load
[Fact]
public void TestLoad()
{
var text = "#load \"bogus\"";
var node = Parse(text, SourceCodeKind.Script);
TestRoundTripping(node, text);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = "bogus"
});
}
[Fact]
public void TestLoadWithoutFile()
{
var text = "#load";
var node = Parse(text, SourceCodeKind.Interactive);
TestRoundTripping(node, text, disallowErrors: false);
VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
});
Assert.True(node.GetLoadDirectives().Single().File.IsMissing);
}
[Fact]
public void TestLoadWithSemicolon()
{
var text = "#load \"\";";
var node = Parse(text, SourceCodeKind.Interactive);
TestRoundTripping(node, text, disallowErrors: false);
VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = ""
});
}
[Fact]
public void TestLoadWithComment()
{
var text = "#load \"bogus\" // comment";
var node = Parse(text, SourceCodeKind.Script);
TestRoundTripping(node, text);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = "bogus"
});
}
#endregion
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册