diff --git a/Cesium.Ast/Cesium.Ast.csproj b/Cesium.Ast/Cesium.Ast.csproj index 54c67da7..444a7901 100644 --- a/Cesium.Ast/Cesium.Ast.csproj +++ b/Cesium.Ast/Cesium.Ast.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj b/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj index 997ce591..1f0ee832 100644 --- a/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj +++ b/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj @@ -8,15 +8,15 @@ - - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Cesium.CodeGen/Cesium.CodeGen.csproj b/Cesium.CodeGen/Cesium.CodeGen.csproj index d992d2ba..f1c067c7 100644 --- a/Cesium.CodeGen/Cesium.CodeGen.csproj +++ b/Cesium.CodeGen/Cesium.CodeGen.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/Cesium.Compiler.Tests/Cesium.Compiler.Tests.csproj b/Cesium.Compiler.Tests/Cesium.Compiler.Tests.csproj index aa500239..297bb799 100644 --- a/Cesium.Compiler.Tests/Cesium.Compiler.Tests.csproj +++ b/Cesium.Compiler.Tests/Cesium.Compiler.Tests.csproj @@ -9,13 +9,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Cesium.Compiler/Cesium.Compiler.csproj b/Cesium.Compiler/Cesium.Compiler.csproj index e4e6560d..9b78d196 100644 --- a/Cesium.Compiler/Cesium.Compiler.csproj +++ b/Cesium.Compiler/Cesium.Compiler.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/Cesium.Compiler/Compilation.cs b/Cesium.Compiler/Compilation.cs index 865db0a5..fb1084d8 100644 --- a/Cesium.Compiler/Compilation.cs +++ b/Cesium.Compiler/Compilation.cs @@ -63,7 +63,7 @@ private static Task Preprocess(string compilationSourcePath, string comp .Concat(compilationOptions.AdditionalIncludeDirectories) .ToImmutableArray(); var includeContext = new FileSystemIncludeContext(stdLibDirectory, includeDirectories); - var preprocessorLexer = new CPreprocessorLexer(reader); + var preprocessorLexer = new CPreprocessorLexer(new Yoakke.SynKit.Text.SourceFile(compilationSourcePath, reader)); var definesContext = new InMemoryDefinesContext(); var outOfFileRange = new Yoakke.SynKit.Text.Range(); foreach (var define in compilationOptions.DefineConstants) @@ -73,7 +73,7 @@ private static Task Preprocess(string compilationSourcePath, string comp macroDefinition: new ObjectMacroDefinition(define), replacement: new IToken[] { - new Token(outOfFileRange, "1", CPreprocessorTokenType.PreprocessingToken) + new Token(outOfFileRange, new(), "1", CPreprocessorTokenType.PreprocessingToken) }); } diff --git a/Cesium.Core/Cesium.Core.csproj b/Cesium.Core/Cesium.Core.csproj index c59f7450..254a972e 100644 --- a/Cesium.Core/Cesium.Core.csproj +++ b/Cesium.Core/Cesium.Core.csproj @@ -7,7 +7,7 @@ - + diff --git a/Cesium.IntegrationTests/Cesium.IntegrationTests.csproj b/Cesium.IntegrationTests/Cesium.IntegrationTests.csproj index 3f9fdf69..cc15ccec 100644 --- a/Cesium.IntegrationTests/Cesium.IntegrationTests.csproj +++ b/Cesium.IntegrationTests/Cesium.IntegrationTests.csproj @@ -12,13 +12,13 @@ - - - - - - - + + + + + + + diff --git a/Cesium.IntegrationTests/preprocessor.c b/Cesium.IntegrationTests/preprocessor.c index 81e262a1..f6de527e 100644 --- a/Cesium.IntegrationTests/preprocessor.c +++ b/Cesium.IntegrationTests/preprocessor.c @@ -2,6 +2,9 @@ #define Y #define Z 0 +#define SINGLE_HASH_(x) # x +#define SINGLE_HASH(x) SINGLE_HASH_(x) + int main(void) { printf("__TEST_DEFINE %i", __TEST_DEFINE); @@ -12,5 +15,8 @@ int main(void) printf("This does exists"); #endif + printf(SINGLE_HASH(x)); + printf("line: %d file: %s ", __LINE__, __FILE__); + return 42; } diff --git a/Cesium.Parser.Tests/Cesium.Parser.Tests.csproj b/Cesium.Parser.Tests/Cesium.Parser.Tests.csproj index e9500537..2f9e2903 100644 --- a/Cesium.Parser.Tests/Cesium.Parser.Tests.csproj +++ b/Cesium.Parser.Tests/Cesium.Parser.Tests.csproj @@ -8,14 +8,14 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Cesium.Parser.Tests/ParserTests/TokenExtensionsTests.cs b/Cesium.Parser.Tests/ParserTests/TokenExtensionsTests.cs index bc8ff061..59049bed 100644 --- a/Cesium.Parser.Tests/ParserTests/TokenExtensionsTests.cs +++ b/Cesium.Parser.Tests/ParserTests/TokenExtensionsTests.cs @@ -17,7 +17,7 @@ public class TokenExtensionsTests [InlineData("\"\\x\"", "\\x")] public void Test(string tokenText, string expected) { - var token = new Token(new Yoakke.SynKit.Text.Range(), tokenText, CTokenType.StringLiteral); + var token = new Token(new Yoakke.SynKit.Text.Range(), new Yoakke.SynKit.Text.Location(), tokenText, CTokenType.StringLiteral); var actual = token.UnwrapStringLiteral(); diff --git a/Cesium.Parser.Tests/PreprocessorTests/PreprocessorTests.cs b/Cesium.Parser.Tests/PreprocessorTests/PreprocessorTests.cs index a8a712ed..59ea86a4 100644 --- a/Cesium.Parser.Tests/PreprocessorTests/PreprocessorTests.cs +++ b/Cesium.Parser.Tests/PreprocessorTests/PreprocessorTests.cs @@ -15,10 +15,11 @@ private static async Task DoTest(string source, Dictionary? stan private static async Task DoPreprocess(string source, Dictionary? standardHeaders = null, Dictionary>>? defines = null) { - var lexer = new CPreprocessorLexer(source); + var filePath = "c:\\a\\b\\c.c"; + var lexer = new CPreprocessorLexer(filePath, source); var includeContext = new IncludeContextMock(standardHeaders ?? new Dictionary()); var definesContext = new InMemoryDefinesContext(defines ?? new Dictionary>>()); - var preprocessor = new CPreprocessor(source, lexer, includeContext, definesContext); + var preprocessor = new CPreprocessor(filePath, lexer, includeContext, definesContext); var result = await preprocessor.ProcessSource(); return result; } @@ -417,5 +418,26 @@ public Task UnrollNestedDefines() => DoTest( #define nested_foo foo #define _(code) nested_foo(code) _(""test"") +"); + + [Fact] + public Task DoubleHashOperator() => DoTest( +@" +#define HASHME(x) L ## x +#define NOHASHME(x) L x +HASHME(""test"") +NOHASHME(""test"") +"); + + [Fact] + public Task LineDefine() => DoTest( +@" +int x = __LINE__; +"); + + [Fact] + public Task FileDefine() => DoTest( +@" +char* x = __FILE__; "); } diff --git a/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.DoubleHashOperator.verified.txt b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.DoubleHashOperator.verified.txt new file mode 100644 index 00000000..9f4cc70e --- /dev/null +++ b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.DoubleHashOperator.verified.txt @@ -0,0 +1,3 @@ + +L"test" +L "test" diff --git a/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.FileDefine.verified.txt b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.FileDefine.verified.txt new file mode 100644 index 00000000..e8a7e610 --- /dev/null +++ b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.FileDefine.verified.txt @@ -0,0 +1,2 @@ + +char* x = "c:\\a\\b\\c.c"; diff --git a/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.LineDefine.verified.txt b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.LineDefine.verified.txt new file mode 100644 index 00000000..8f56463c --- /dev/null +++ b/Cesium.Parser.Tests/PreprocessorTests/verified/PreprocessorTests.LineDefine.verified.txt @@ -0,0 +1,2 @@ + +int x = 2; diff --git a/Cesium.Parser/CParser.cs b/Cesium.Parser/CParser.cs index e484fab3..f4c492a7 100644 --- a/Cesium.Parser/CParser.cs +++ b/Cesium.Parser/CParser.cs @@ -1031,5 +1031,5 @@ private static ImmutableArray MakeDeclarationList( } private static ICToken MergeTokens(ICToken token1, ICToken token2) => - new Token(new Range(token1.Range, token2.Range), token1.Text + token2.Text, token2.Kind); + new Token(new Range(token1.Range, token2.Range), token1.Location, token1.Text + token2.Text, token2.Kind); } diff --git a/Cesium.Parser/Cesium.Parser.csproj b/Cesium.Parser/Cesium.Parser.csproj index 54a1419c..cade06f2 100644 --- a/Cesium.Parser/Cesium.Parser.csproj +++ b/Cesium.Parser/Cesium.Parser.csproj @@ -6,10 +6,10 @@ - - - - + + + + diff --git a/Cesium.Preprocessor/CPreprocessor.cs b/Cesium.Preprocessor/CPreprocessor.cs index 47c2dfd9..f6f1efec 100644 --- a/Cesium.Preprocessor/CPreprocessor.cs +++ b/Cesium.Preprocessor/CPreprocessor.cs @@ -1,9 +1,11 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using Cesium.Core; using Yoakke.Streams; using Yoakke.SynKit.Lexer; +using Yoakke.SynKit.Text; using static Cesium.Preprocessor.CPreprocessorTokenType; using Range = Yoakke.SynKit.Text.Range; @@ -180,7 +182,7 @@ private IEnumerable> ReplaceMacro(IToken(token.Range, ",", CPreprocessorTokenType.Separator)); + va_args.Add(new Token(token.Range, token.Location, ",", CPreprocessorTokenType.Separator)); } } else @@ -242,9 +244,29 @@ private IEnumerable> ReplaceMacro(IToken(token.Range, token.Location, "\"" + token.Location.File?.Path.Replace("\\", "\\\\") + "\"", PreprocessingToken); + yield break; + } + if (token.Text == "__LINE__") + { + var line = token.Location.Range.Start.Line + 1; + yield return new Token( + token.Range, + token.Location, + line.ToString(), + PreprocessingToken); + yield break; + } + } bool performStringReplace = false; + bool includeNextVerbatim = false; var nestedStream = new EnumerableStream>(tokenReplacement); + var pendingWhitespaces = new List>(); while (!nestedStream.IsEnd) { var subToken = nestedStream.Consume(); @@ -254,40 +276,78 @@ private IEnumerable> ReplaceMacro(IToken(token.Range, token.Location, parameterToken.Text, parameterToken.Kind); + } + } + else if (performStringReplace) { var stringValue = string.Join(string.Empty, parameterTokens.Select(t => t.Text)); var escapedStringValue = stringValue.Replace("\\", "\\\\") .Replace("\"", "\\\"") ; escapedStringValue = $"\"{escapedStringValue}\""; - yield return new Token(token.Range, escapedStringValue, token.Kind); + yield return new Token(token.Range, token.Location, escapedStringValue, token.Kind); performStringReplace = false; } else { foreach (var parameterToken in parameterTokens) { - yield return new Token(token.Range, parameterToken.Text, parameterToken.Kind); + yield return new Token(token.Range, token.Location, parameterToken.Text, parameterToken.Kind); } } } else { - foreach (var nestedT in ReplaceMacro(subToken, nestedStream)) + if (includeNextVerbatim) { - yield return nestedT; - + yield return subToken; } + else + { + foreach (var nestedT in ReplaceMacro(subToken, nestedStream)) + { + yield return nestedT; + } + } + } + + includeNextVerbatim = false; + } + else if (subToken is { Kind: WhiteSpace }) + { + if (!includeNextVerbatim) + { + pendingWhitespaces.Add(new Token(token.Range, token.Location, subToken.Text, subToken.Kind)); } } else { - yield return new Token(token.Range, subToken.Text, subToken.Kind); + yield return new Token(token.Range, token.Location, subToken.Text, subToken.Kind); } } } @@ -521,7 +581,7 @@ IEnumerable> ConsumeLineAll() private bool EvaluateExpression(IList> expressionTokens) { var stream = new EnumerableStream>( - expressionTokens.Union(new[] { new Token(new Range(), "", End) })).ToBuffered(); + expressionTokens.Union(new[] { new Token(new Range(), new Yoakke.SynKit.Text.Location(), "", End) })).ToBuffered(); var p = new CPreprocessorExpressionParser(stream); var expression = p.ParseExpression(); if (expression.IsError) @@ -537,7 +597,7 @@ private bool EvaluateExpression(IList> expression private static (MacroDefinition, List>) EvaluateMacroDefinition(IEnumerable> expressionTokens) { var stream = new EnumerableStream>( - expressionTokens.Union(new[] { new Token(new Range(), "", End) })).ToBuffered(); + expressionTokens.Union(new[] { new Token(new Range(), new Yoakke.SynKit.Text.Location(), "", End) })).ToBuffered(); var p = new CPreprocessorMacroDefinitionParser(stream); var macroDefinition = p.ParseMacro(); var macroReplacement = new List>(); @@ -567,13 +627,13 @@ private static (MacroDefinition, List>) EvaluateM private async IAsyncEnumerable> ProcessInclude(string compilationUnitPath, TextReader fileReader) { - var lexer = new CPreprocessorLexer(fileReader); + var lexer = new CPreprocessorLexer(new SourceFile(compilationUnitPath, fileReader)); var subProcessor = new CPreprocessor(compilationUnitPath, lexer, IncludeContext, MacroContext); await foreach (var item in subProcessor.GetPreprocessingResults()) { yield return item; } - yield return new Token(new Range(), "\n", NewLine); + yield return new Token(new Range(), new Yoakke.SynKit.Text.Location(), "\n", NewLine); } } diff --git a/Cesium.Preprocessor/Cesium.Preprocessor.csproj b/Cesium.Preprocessor/Cesium.Preprocessor.csproj index 33e1ceff..3365ce43 100644 --- a/Cesium.Preprocessor/Cesium.Preprocessor.csproj +++ b/Cesium.Preprocessor/Cesium.Preprocessor.csproj @@ -6,10 +6,10 @@ - - - - + + + + diff --git a/Cesium.Preprocessor/InMemoryDefinesContext.cs b/Cesium.Preprocessor/InMemoryDefinesContext.cs index e5d77798..35abc6a0 100644 --- a/Cesium.Preprocessor/InMemoryDefinesContext.cs +++ b/Cesium.Preprocessor/InMemoryDefinesContext.cs @@ -13,7 +13,17 @@ public InMemoryDefinesContext(IReadOnlyDictionary>>() : new Dictionary>>(initialDefines); - _defineMacros = new(); + _defineMacros = new(); + + this.DefineMacro( + "__LINE__", + macroDefinition: new ObjectMacroDefinition("__LINE__"), + replacement: new IToken[0]); + + this.DefineMacro( + "__FILE__", + macroDefinition: new ObjectMacroDefinition("__FILE__"), + replacement: new IToken[0]); } public void DefineMacro(string macro, MacroDefinition macroDefinition, IList> replacement) diff --git a/Cesium.Runtime.Tests/Cesium.Runtime.Tests.csproj b/Cesium.Runtime.Tests/Cesium.Runtime.Tests.csproj index 53dd9ac5..17108c41 100644 --- a/Cesium.Runtime.Tests/Cesium.Runtime.Tests.csproj +++ b/Cesium.Runtime.Tests/Cesium.Runtime.Tests.csproj @@ -10,13 +10,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Cesium.TestFramework.Tests/Cesium.TestFramework.Tests.csproj b/Cesium.TestFramework.Tests/Cesium.TestFramework.Tests.csproj index 9a17f158..33440b6f 100644 --- a/Cesium.TestFramework.Tests/Cesium.TestFramework.Tests.csproj +++ b/Cesium.TestFramework.Tests/Cesium.TestFramework.Tests.csproj @@ -10,13 +10,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Cesium.TestFramework/Cesium.TestFramework.csproj b/Cesium.TestFramework/Cesium.TestFramework.csproj index 1d34a677..316c9bc2 100644 --- a/Cesium.TestFramework/Cesium.TestFramework.csproj +++ b/Cesium.TestFramework/Cesium.TestFramework.csproj @@ -6,11 +6,11 @@ - - - - - + + + + + diff --git a/Cesium.sln b/Cesium.sln index 59817627..aabd2baf 100644 --- a/Cesium.sln +++ b/Cesium.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution after.Cesium.sln.targets = after.Cesium.sln.targets CONTRIBUTING.md = CONTRIBUTING.md Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props README.md = README.md EndProjectSection EndProject diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 00000000..847c9879 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,24 @@ + + + true + + + + + + + + + + + + + + + + + + + + +