Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#247 Implement pragma once directive. #267

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,66 @@ public void TestPragma()
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive, Text = @"something custom" });
}

[Fact]
public void TestPragmaOnce()
{
const string fooText = @"
#pragma once
#define FOO
float foo = 1.0f;
";
const string barText = @"
#define BAR
#include <foo.hlsl>
#include ""foo.hlsl""
float bar = 2.0f;
#pragma once 1
#pragma once : s
#pragma once()
#pragma once
";
const string text = @"
#include <foo.hlsl>
#include ""foo.hlsl""
#include ""bar.hlsl""
#include <foo.hlsl>
#include ""foo.hlsl""
#include ""bar.hlsl""
float rawr = 3.0f;
#define RAWR
";
var node = Parse(
text,
new HlslParseOptions
{
AdditionalIncludeDirectories = { "test" }
},
new InMemoryFileSystem(new Dictionary<string, string>
{
{ Path.Combine("test", "foo.hlsl"), fooText },
{ Path.Combine("test2", "bar.hlsl"), barText }
}), Path.Combine("test2", "__Root__.hlsl"));

TestRoundTripping(node, text);
VerifyDirectivesSpecial(node,
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.ObjectLikeDefineDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.ObjectLikeDefineDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.PragmaDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.IncludeDirectiveTrivia, Status = NodeStatus.IsActive },
new DirectiveInfo { Kind = SyntaxKind.ObjectLikeDefineDirectiveTrivia, Status = NodeStatus.IsActive });
}

[Fact]
public void HandlesVirtualDirectoryMapping_IncludeIsInRootOfVirtualDirectory_IncludeHandledSuccessfully()
{
Expand Down Expand Up @@ -1174,9 +1234,9 @@ private static IReadOnlyList<SyntaxToken> LexAllTokens(string text)
return SyntaxFactory.ParseAllTokens(new SourceFile(SourceText.From(text)));
}

private static CompilationUnitSyntax Parse(string text, HlslParseOptions options = null, IIncludeFileSystem fileSystem = null)
private static CompilationUnitSyntax Parse(string text, HlslParseOptions options = null, IIncludeFileSystem fileSystem = null, string filePath = "__Root__.hlsl")
{
return SyntaxFactory.ParseCompilationUnit(new SourceFile(SourceText.From(text), "__Root__.hlsl"), options, fileSystem);
return SyntaxFactory.ParseCompilationUnit(new SourceFile(SourceText.From(text), filePath), options, fileSystem);
}

private static void TestRoundTripping(CompilationUnitSyntax node, string text, bool disallowErrors = true)
Expand Down
3 changes: 3 additions & 0 deletions src/ShaderTools.CodeAnalysis.Hlsl/Parser/DirectiveParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ private PragmaDirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, Synta

var eod = ParseEndOfDirective(false);

if (body.Count > 0 && body.First().ContextualKind == SyntaxKind.OnceKeyword)
_lexer.ApplyPragmaOnceDirective();

return new PragmaDirectiveTriviaSyntax(hash, keyword, body, eod, isActive);
}

Expand Down
5 changes: 4 additions & 1 deletion src/ShaderTools.CodeAnalysis.Hlsl/Parser/HlslLexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ namespace ShaderTools.CodeAnalysis.Hlsl.Parser
public sealed partial class HlslLexer : ILexer
{
private readonly IIncludeFileResolver _includeFileResolver;
private readonly HashSet<string> _includeOnceList = new HashSet<string>();
private readonly List<SyntaxNode> _leadingTrivia = new List<SyntaxNode>();
private readonly List<SyntaxNode> _trailingTrivia = new List<SyntaxNode>();
private readonly List<Diagnostic> _diagnostics = new List<Diagnostic>();

private LexerMode _mode;
public bool ExpandMacros { get; set; }
public void ApplyPragmaOnceDirective() { _includeOnceList.Add(File.FilePath); }

private List<SyntaxToken> _expandedMacroTokens;
private int _expandedMacroIndex;
Expand Down Expand Up @@ -338,7 +340,8 @@ private bool LexDirectiveAndExcludedTrivia(
if (include != null)
{
triviaList.Add(includeDirective);
PushIncludeContext(include);
if (!_includeOnceList.Contains(include.FilePath))
PushIncludeContext(include);
return false;
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/ShaderTools.CodeAnalysis.Hlsl/Syntax/SyntaxFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ public static string GetText(this SyntaxKind kind)
return "min16int";
case SyntaxKind.Min16UintKeyword:
return "min16uint";
case SyntaxKind.OnceKeyword:
return "once";
case SyntaxKind.OutKeyword:
return "out";
case SyntaxKind.PackMatrixKeyword:
Expand Down Expand Up @@ -2854,6 +2856,8 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
return SyntaxKind.PackMatrixKeyword;
case "warning":
return SyntaxKind.WarningKeyword;
case "once":
return SyntaxKind.OnceKeyword;
default:
return SyntaxKind.IdentifierToken;
}
Expand All @@ -2880,6 +2884,7 @@ public static bool IsPreprocessorKeyword(this SyntaxKind kind)
case SyntaxKind.MessageKeyword:
case SyntaxKind.PackMatrixKeyword:
case SyntaxKind.WarningKeyword:
case SyntaxKind.OnceKeyword:
return true;

default:
Expand Down
9 changes: 5 additions & 4 deletions src/ShaderTools.CodeAnalysis.Hlsl/Syntax/SyntaxKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ public enum SyntaxKind
NointerpolationKeyword,
NoperspectiveKeyword,
NullKeyword,
OnceKeyword,
OutKeyword,
OutputPatchKeyword,
PackMatrixKeyword,
Expand Down Expand Up @@ -415,8 +416,8 @@ public enum SyntaxKind
Uint4x2Keyword,
Uint4x3Keyword,
Uint4x4Keyword,
Uint64_tKeyword,
Uint64_t1Keyword,
Uint64_tKeyword,
Uint64_t1Keyword,
Uint64_t2Keyword,
Uint64_t3Keyword,
Uint64_t4Keyword,
Expand All @@ -436,8 +437,8 @@ public enum SyntaxKind
Uint64_t4x2Keyword,
Uint64_t4x3Keyword,
Uint64_t4x4Keyword,
Uint16_tKeyword,
Uint16_t1Keyword,
Uint16_tKeyword,
Uint16_t1Keyword,
Uint16_t2Keyword,
Uint16_t3Keyword,
Uint16_t4Keyword,
Expand Down