From cbda8733619058f64c625902b59988b5a2d57cda Mon Sep 17 00:00:00 2001 From: slangbot <186143334+slangbot@users.noreply.github.com> Date: Thu, 17 Apr 2025 00:15:58 +0000 Subject: [PATCH] format code --- tools/CMakeLists.txt | 6 +- .../slang-fiddle-diagnostic-defs.h | 20 +- .../slang-fiddle/slang-fiddle-diagnostics.cpp | 4 +- tools/slang-fiddle/slang-fiddle-diagnostics.h | 10 +- tools/slang-fiddle/slang-fiddle-lua.cpp | 1 - tools/slang-fiddle/slang-fiddle-main.cpp | 660 +++-- tools/slang-fiddle/slang-fiddle-options.cpp | 1 - tools/slang-fiddle/slang-fiddle-options.h | 87 +- tools/slang-fiddle/slang-fiddle-scrape.cpp | 2282 ++++++++--------- tools/slang-fiddle/slang-fiddle-scrape.h | 524 ++-- tools/slang-fiddle/slang-fiddle-script.cpp | 258 +- tools/slang-fiddle/slang-fiddle-script.h | 23 +- tools/slang-fiddle/slang-fiddle-template.cpp | 866 +++---- tools/slang-fiddle/slang-fiddle-template.h | 151 +- 14 files changed, 2387 insertions(+), 2506 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f9a65bac0c0..efcc71060f9 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -45,11 +45,7 @@ function(generator dir) endif() endfunction() -generator( - slang-fiddle - LINK_WITH_PRIVATE - compiler-core -) +generator(slang-fiddle LINK_WITH_PRIVATE compiler-core) generator( slang-cpp-extractor USE_FEWER_WARNINGS diff --git a/tools/slang-fiddle/slang-fiddle-diagnostic-defs.h b/tools/slang-fiddle/slang-fiddle-diagnostic-defs.h index 8dcd487b0aa..204185b1c5e 100644 --- a/tools/slang-fiddle/slang-fiddle-diagnostic-defs.h +++ b/tools/slang-fiddle/slang-fiddle-diagnostic-defs.h @@ -37,23 +37,35 @@ DIAGNOSTIC(200002, Error, couldNotWriteOutputFile, "could not write output file // Template Parsing -DIAGNOSTIC(300001, Error, expectedOutputStartMarker, "start line for template not followed by a line marking output with '$0'") +DIAGNOSTIC( + 300001, + Error, + expectedOutputStartMarker, + "start line for template not followed by a line marking output with '$0'") DIAGNOSTIC(300002, Error, expectedEndMarker, "expected a template end line ('$0')") // Scraper: Parsing DIAGNOSTIC(500001, Error, unexpected, "unexpected $0, expected $1") -DIAGNOSTIC(501001, Error, expectedFiddleEllipsisInvocation, "expected 'FIDDLE(...)' at start of body of '$0'") +DIAGNOSTIC( + 501001, + Error, + expectedFiddleEllipsisInvocation, + "expected 'FIDDLE(...)' at start of body of '$0'") -DIAGNOSTIC(502001, Error, expectedIncludeOfOutputHeader, "expected a '#include' of generated output file '$0' in file containing 'FIDDLE(...)' invocations") +DIAGNOSTIC( + 502001, + Error, + expectedIncludeOfOutputHeader, + "expected a '#include' of generated output file '$0' in file containing 'FIDDLE(...)' " + "invocations") // Scraper: Semantic Checking DIAGNOSTIC(600001, Error, undefinedIdentifier, "undefined identifier '$0'") - DIAGNOSTIC(999999, Fatal, internalError, "internal error in 'fiddle' tool") #undef DIAGNOSTIC diff --git a/tools/slang-fiddle/slang-fiddle-diagnostics.cpp b/tools/slang-fiddle/slang-fiddle-diagnostics.cpp index e5ce53c1ab4..7b59224c6d1 100644 --- a/tools/slang-fiddle/slang-fiddle-diagnostics.cpp +++ b/tools/slang-fiddle/slang-fiddle-diagnostics.cpp @@ -10,5 +10,5 @@ using namespace Slang; #define DIAGNOSTIC(id, severity, name, messageFormat) \ const DiagnosticInfo name = {id, Severity::severity, #name, messageFormat}; #include "slang-fiddle-diagnostic-defs.h" -} -} +} // namespace Diagnostics +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-diagnostics.h b/tools/slang-fiddle/slang-fiddle-diagnostics.h index 8126b1c688a..6dac91f9567 100644 --- a/tools/slang-fiddle/slang-fiddle-diagnostics.h +++ b/tools/slang-fiddle/slang-fiddle-diagnostics.h @@ -7,12 +7,12 @@ namespace fiddle { - using namespace Slang; +using namespace Slang; - namespace Diagnostics - { +namespace Diagnostics +{ #define DIAGNOSTIC(id, severity, name, messageFormat) extern const DiagnosticInfo name; #include "slang-fiddle-diagnostic-defs.h" - } -} +} // namespace Diagnostics +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-lua.cpp b/tools/slang-fiddle/slang-fiddle-lua.cpp index e9b8c936cd8..f6ba36357ad 100644 --- a/tools/slang-fiddle/slang-fiddle-lua.cpp +++ b/tools/slang-fiddle/slang-fiddle-lua.cpp @@ -3,4 +3,3 @@ #define MAKE_LIB 1 #include "../external/lua/onelua.c" - diff --git a/tools/slang-fiddle/slang-fiddle-main.cpp b/tools/slang-fiddle/slang-fiddle-main.cpp index 168f34c68d0..455ee0960d6 100644 --- a/tools/slang-fiddle/slang-fiddle-main.cpp +++ b/tools/slang-fiddle/slang-fiddle-main.cpp @@ -1,12 +1,11 @@ // slang-fiddle-main.cpp +#include "core/slang-io.h" #include "slang-fiddle-diagnostics.h" #include "slang-fiddle-options.h" #include "slang-fiddle-scrape.h" #include "slang-fiddle-template.h" -#include "core/slang-io.h" - #if 0 #include "compiler-core/slang-doc-extractor.h" #include "compiler-core/slang-name-convention-util.h" @@ -29,380 +28,373 @@ namespace fiddle { - using namespace Slang; +using namespace Slang; - class InputFile : public RefObject - { - public: - String inputFileName; +class InputFile : public RefObject +{ +public: + String inputFileName; - RefPtr scrapedSourceUnit; - RefPtr textTemplateFile; - }; + RefPtr scrapedSourceUnit; + RefPtr textTemplateFile; +}; - struct App +struct App +{ +public: + App(SourceManager& sourceManager, DiagnosticSink& sink, RootNamePool rootNamePool) + : sourceManager(sourceManager), sink(sink), rootNamePool(rootNamePool) { - public: - App( - SourceManager& sourceManager, - DiagnosticSink& sink, - RootNamePool rootNamePool) - : sourceManager(sourceManager) - , sink(sink) - , rootNamePool(rootNamePool) - {} - - RootNamePool& rootNamePool; - SourceManager& sourceManager; - DiagnosticSink& sink; - - Options options; - - List> inputFiles; - RefPtr logicalModule; - - RefPtr parseSourceUnit( - SourceView* inputSourceView, - String outputFileName) - { - return fiddle::parseSourceUnit( - inputSourceView, - logicalModule, - &rootNamePool, - &sink, - &sourceManager, - outputFileName); - } - - RefPtr parseTextTemplate(SourceView* inputSourceView) - { - return fiddle::parseTextTemplateFile(inputSourceView, &sink); - } - - String getOutputFileName(String inputFileName) - { - return inputFileName + ".fiddle"; - } - - void processInputFile(String const& inputFileName) - { - // The full path to the input and output is determined by the prefixes that - // were specified via command-line arguments. - // - String inputPath = options.inputPathPrefix + inputFileName; - - // We read the fill text of the file into memory as a single string, - // so that we can easily parse it without need for I/O operations - // along the way. - // - String inputText; - if (SLANG_FAILED(File::readAllText(inputPath, inputText))) - { - sink.diagnose(SourceLoc(), fiddle::Diagnostics::couldNotReadInputFile, inputPath); - return; - } + } - // Registering the input file with the `sourceManager` allows us - // to get proper source locations for offsets within it. - // - PathInfo inputPathInfo = PathInfo::makeFromString(inputPath); - SourceFile* inputSourceFile = sourceManager.createSourceFileWithString(inputPathInfo, inputText); - SourceView* inputSourceView = sourceManager.createSourceView(inputSourceFile, nullptr, SourceLoc()); + RootNamePool& rootNamePool; + SourceManager& sourceManager; + DiagnosticSink& sink; - auto inputFile = RefPtr(new InputFile()); - inputFile->inputFileName = inputFileName; + Options options; - // We are going to process the same input file in two different ways: - // - // - We will read the file using the C++-friendly `Lexer` type - // from the Slang `compiler-core` library, in order to scrape - // specially marked C++ declarations and process their contents. - // - // - We will also read the file as plain text, in order to find - // ranges that represent templates to be processed with our - // ad hoc Lua-based template engine. + List> inputFiles; + RefPtr logicalModule; - // We'll do the token-based parsing step first, and allow it - // to return a `SourceUnit` that we can use to keep track - // of the file. - // - auto sourceUnit = parseSourceUnit( - inputSourceView, - getOutputFileName(inputFileName)); - - // Then we'll read the same file again looking for template - // lines, and collect that information onto the same - // object, so that we can emit the file back out again, - // potentially with some of its content replaced. - // - auto textTemplateFile = parseTextTemplate(inputSourceView); + RefPtr parseSourceUnit(SourceView* inputSourceView, String outputFileName) + { + return fiddle::parseSourceUnit( + inputSourceView, + logicalModule, + &rootNamePool, + &sink, + &sourceManager, + outputFileName); + } - inputFile->scrapedSourceUnit = sourceUnit; - inputFile->textTemplateFile = textTemplateFile; + RefPtr parseTextTemplate(SourceView* inputSourceView) + { + return fiddle::parseTextTemplateFile(inputSourceView, &sink); + } - inputFiles.add(inputFile); - } + String getOutputFileName(String inputFileName) { return inputFileName + ".fiddle"; } - /// Generate a slug version of the given string. - /// - /// A *slug* is a version of a string that has - /// a visible and obvious dependency on the input - /// text, but that is massaged to conform to the - /// constraints of names for some purpose. - /// - /// In our case, the constraints are to have an - /// identifier that is suitable for use as a - /// preprocessor macro. - /// - String generateSlug(String const& inputText) + void processInputFile(String const& inputFileName) + { + // The full path to the input and output is determined by the prefixes that + // were specified via command-line arguments. + // + String inputPath = options.inputPathPrefix + inputFileName; + + // We read the fill text of the file into memory as a single string, + // so that we can easily parse it without need for I/O operations + // along the way. + // + String inputText; + if (SLANG_FAILED(File::readAllText(inputPath, inputText))) { - StringBuilder builder; - int prev = -1; - for (auto c : inputText) - { - // Ordinary alphabetic characters go - // through as-is, but converted to - // upper-case. - // - if (('A' <= c) && (c <= 'Z')) - { - builder.appendChar(c); - } - else if (('a' <= c) && (c <= 'z')) - { - builder.appendChar((c - 'a') + 'A'); - } - else if (('0' <= c) && (c <= '9')) - { - // A digit can be passed through as-is, - // except that we need to account for - // the case where (somehow) the very - // first character is a digit. - if (prev == -1) - builder.appendChar('_'); - builder.appendChar(c); - } - else - { - // We replace any other character with - // an underscore (`_`), but we make - // sure to collapse any sequence of - // consecutive underscores, and to - // ignore characters at the start of - // the string that would turn into - // underscores. - // - if (prev == -1) - continue; - if (prev == '_') - continue; - - c = '_'; - builder.appendChar(c); - } - - prev = c; - } - return builder.produceString(); + sink.diagnose(SourceLoc(), fiddle::Diagnostics::couldNotReadInputFile, inputPath); + return; } - void generateAndEmitFilesForInputFile(InputFile* inputFile) - { - // The output file wil name will be the input file - // name, but with the suffix `.fiddle` appended to it. - // - auto inputFileName = inputFile->inputFileName; - String outputFileName = getOutputFileName(inputFileName); - String outputFilePath = options.outputPathPrefix + outputFileName; - - String inputFileSlug = generateSlug(inputFileName); - - // We start the generated file with a header to warn - // people against editing it by hand (not that doing - // so will prevent by-hand edits, but its one of the - // few things we can do). - // - StringBuilder builder; - builder.append("// GENERATED CODE; DO NOT EDIT\n"); - builder.append("//\n"); - - builder.append("// input file: "); - builder.append(inputFile->inputFileName); - builder.append("\n"); - - // There are currently two kinds of generated code - // we need to handle here: - // - // - The code that the scraping tool wants to inject - // at each of the `FIDDLE(...)` macro invocation - // sites. - // - // - The code that is generated from each of the - // `FIDDLE TEMPLATE` constructs. - // - // We will emit both kinds of output to the same - // file, to keep things easy-ish for the client. + // Registering the input file with the `sourceManager` allows us + // to get proper source locations for offsets within it. + // + PathInfo inputPathInfo = PathInfo::makeFromString(inputPath); + SourceFile* inputSourceFile = + sourceManager.createSourceFileWithString(inputPathInfo, inputText); + SourceView* inputSourceView = + sourceManager.createSourceView(inputSourceFile, nullptr, SourceLoc()); + + auto inputFile = RefPtr(new InputFile()); + inputFile->inputFileName = inputFileName; + + // We are going to process the same input file in two different ways: + // + // - We will read the file using the C++-friendly `Lexer` type + // from the Slang `compiler-core` library, in order to scrape + // specially marked C++ declarations and process their contents. + // + // - We will also read the file as plain text, in order to find + // ranges that represent templates to be processed with our + // ad hoc Lua-based template engine. + + // We'll do the token-based parsing step first, and allow it + // to return a `SourceUnit` that we can use to keep track + // of the file. + // + auto sourceUnit = parseSourceUnit(inputSourceView, getOutputFileName(inputFileName)); + + // Then we'll read the same file again looking for template + // lines, and collect that information onto the same + // object, so that we can emit the file back out again, + // potentially with some of its content replaced. + // + auto textTemplateFile = parseTextTemplate(inputSourceView); + + inputFile->scrapedSourceUnit = sourceUnit; + inputFile->textTemplateFile = textTemplateFile; + + inputFiles.add(inputFile); + } - // The first kind of output is the content for - // any `FIDDLE(...)` macro invocations. + /// Generate a slug version of the given string. + /// + /// A *slug* is a version of a string that has + /// a visible and obvious dependency on the input + /// text, but that is massaged to conform to the + /// constraints of names for some purpose. + /// + /// In our case, the constraints are to have an + /// identifier that is suitable for use as a + /// preprocessor macro. + /// + String generateSlug(String const& inputText) + { + StringBuilder builder; + int prev = -1; + for (auto c : inputText) + { + // Ordinary alphabetic characters go + // through as-is, but converted to + // upper-case. // - if (hasAnyFiddleInvocations(inputFile->scrapedSourceUnit)) + if (('A' <= c) && (c <= 'Z')) { - - builder.append("\n// BEGIN FIDDLE SCRAPER OUTPUT\n"); - builder.append("#ifndef "); - builder.append(inputFileSlug); - builder.append("_INCLUDED\n"); - builder.append("#define "); - builder.append(inputFileSlug); - builder.append("_INCLUDED 1\n"); - builder.append("#ifdef FIDDLE\n"); - builder.append("#undef FIDDLE\n"); - builder.append("#undef FIDDLEX\n"); - builder.append("#undef FIDDLEY\n"); - builder.append("#endif\n"); - builder.append("#define FIDDLEY(ARG) FIDDLE_##ARG\n"); - builder.append("#define FIDDLEX(ARG) FIDDLEY(ARG)\n"); - builder.append("#define FIDDLE FIDDLEX(__LINE__)\n"); - - emitSourceUnitMacros( - inputFile->scrapedSourceUnit, - builder, - &sink, - &sourceManager, - logicalModule); - - builder.append("\n#endif\n"); - builder.append("// END FIDDLE SCRAPER OUTPUT\n"); - + builder.appendChar(c); } - - if (inputFile->textTemplateFile->textTemplates.getCount() != 0) + else if (('a' <= c) && (c <= 'z')) { - builder.append("\n// BEGIN FIDDLE TEMPLATE OUTPUT:\n"); - builder.append("#ifdef FIDDLE_GENERATED_OUTPUT_ID\n"); - - generateTextTemplateOutputs( - options.inputPathPrefix + inputFileName, - inputFile->textTemplateFile, - builder, - &sink); - - builder.append("#undef FIDDLE_GENERATED_OUTPUT_ID\n"); - builder.append("#endif\n"); - builder.append("// END FIDDLE TEMPLATE OUTPUT\n"); + builder.appendChar((c - 'a') + 'A'); } - - builder.append("\n// END OF FIDDLE-GENERATED FILE\n"); - - + else if (('0' <= c) && (c <= '9')) { - String outputFileContent = builder.produceString(); - - if (SLANG_FAILED(File::writeAllTextIfChanged( - outputFilePath, outputFileContent.getUnownedSlice()))) - { - sink.diagnose(SourceLoc(), - fiddle::Diagnostics::couldNotWriteOutputFile, outputFilePath); - return; - } + // A digit can be passed through as-is, + // except that we need to account for + // the case where (somehow) the very + // first character is a digit. + if (prev == -1) + builder.appendChar('_'); + builder.appendChar(c); } - - // If we successfully wrote the output file and all of - // its content, it is time to write out new text for - // the *input* file, based on the template file. - // + else { - String newInputFileContent = generateModifiedInputFileForTextTemplates( - outputFileName, - inputFile->textTemplateFile, - &sink); - - String inputFilePath = options.inputPathPrefix + inputFileName; - if (SLANG_FAILED(File::writeAllTextIfChanged( - inputFilePath, newInputFileContent.getUnownedSlice()))) - { - sink.diagnose(SourceLoc(), - fiddle::Diagnostics::couldNotOverwriteInputFile, inputFilePath); - return; - } + // We replace any other character with + // an underscore (`_`), but we make + // sure to collapse any sequence of + // consecutive underscores, and to + // ignore characters at the start of + // the string that would turn into + // underscores. + // + if (prev == -1) + continue; + if (prev == '_') + continue; + + c = '_'; + builder.appendChar(c); } + + prev = c; } + return builder.produceString(); + } - void generateAndEmitFiles() + void generateAndEmitFilesForInputFile(InputFile* inputFile) + { + // The output file wil name will be the input file + // name, but with the suffix `.fiddle` appended to it. + // + auto inputFileName = inputFile->inputFileName; + String outputFileName = getOutputFileName(inputFileName); + String outputFilePath = options.outputPathPrefix + outputFileName; + + String inputFileSlug = generateSlug(inputFileName); + + // We start the generated file with a header to warn + // people against editing it by hand (not that doing + // so will prevent by-hand edits, but its one of the + // few things we can do). + // + StringBuilder builder; + builder.append("// GENERATED CODE; DO NOT EDIT\n"); + builder.append("//\n"); + + builder.append("// input file: "); + builder.append(inputFile->inputFileName); + builder.append("\n"); + + // There are currently two kinds of generated code + // we need to handle here: + // + // - The code that the scraping tool wants to inject + // at each of the `FIDDLE(...)` macro invocation + // sites. + // + // - The code that is generated from each of the + // `FIDDLE TEMPLATE` constructs. + // + // We will emit both kinds of output to the same + // file, to keep things easy-ish for the client. + + // The first kind of output is the content for + // any `FIDDLE(...)` macro invocations. + // + if (hasAnyFiddleInvocations(inputFile->scrapedSourceUnit)) { - for (auto inputFile : inputFiles) - generateAndEmitFilesForInputFile(inputFile); + + builder.append("\n// BEGIN FIDDLE SCRAPER OUTPUT\n"); + builder.append("#ifndef "); + builder.append(inputFileSlug); + builder.append("_INCLUDED\n"); + builder.append("#define "); + builder.append(inputFileSlug); + builder.append("_INCLUDED 1\n"); + builder.append("#ifdef FIDDLE\n"); + builder.append("#undef FIDDLE\n"); + builder.append("#undef FIDDLEX\n"); + builder.append("#undef FIDDLEY\n"); + builder.append("#endif\n"); + builder.append("#define FIDDLEY(ARG) FIDDLE_##ARG\n"); + builder.append("#define FIDDLEX(ARG) FIDDLEY(ARG)\n"); + builder.append("#define FIDDLE FIDDLEX(__LINE__)\n"); + + emitSourceUnitMacros( + inputFile->scrapedSourceUnit, + builder, + &sink, + &sourceManager, + logicalModule); + + builder.append("\n#endif\n"); + builder.append("// END FIDDLE SCRAPER OUTPUT\n"); } - void checkModule() + if (inputFile->textTemplateFile->textTemplates.getCount() != 0) { - fiddle::checkModule(this->logicalModule, &sink); + builder.append("\n// BEGIN FIDDLE TEMPLATE OUTPUT:\n"); + builder.append("#ifdef FIDDLE_GENERATED_OUTPUT_ID\n"); + + generateTextTemplateOutputs( + options.inputPathPrefix + inputFileName, + inputFile->textTemplateFile, + builder, + &sink); + + builder.append("#undef FIDDLE_GENERATED_OUTPUT_ID\n"); + builder.append("#endif\n"); + builder.append("// END FIDDLE TEMPLATE OUTPUT\n"); } - void execute(int argc, char const* const* argv) - { - // We start by parsing any command-line options - // that were specified. - // - options.parse(sink, argc, argv); - if (sink.getErrorCount()) - return; + builder.append("\n// END OF FIDDLE-GENERATED FILE\n"); - // All of the code that get scraped will be - // organized into a single logical module, - // with no regard for what file each - // declaration came from. - // - logicalModule = new LogicalModule(); - // We iterate over the input paths specified on - // the command line, to read each in and process - // its text. - // - // This step both scans for declarations that - // are to be scraped, and also reads the any - // template spans. - // - for (auto inputPath : options.inputPaths) + { + String outputFileContent = builder.produceString(); + + if (SLANG_FAILED(File::writeAllTextIfChanged( + outputFilePath, + outputFileContent.getUnownedSlice()))) { - processInputFile(inputPath); - } - if (sink.getErrorCount()) + sink.diagnose( + SourceLoc(), + fiddle::Diagnostics::couldNotWriteOutputFile, + outputFilePath); return; + } + } - // In order to build up the data model of the - // scraped declarations (such as what inherits - // from what), we need to perform a minimal - // amount of semantic checking here. - // - checkModule(); - if (sink.getErrorCount()) + // If we successfully wrote the output file and all of + // its content, it is time to write out new text for + // the *input* file, based on the template file. + // + { + String newInputFileContent = generateModifiedInputFileForTextTemplates( + outputFileName, + inputFile->textTemplateFile, + &sink); + + String inputFilePath = options.inputPathPrefix + inputFileName; + if (SLANG_FAILED(File::writeAllTextIfChanged( + inputFilePath, + newInputFileContent.getUnownedSlice()))) + { + sink.diagnose( + SourceLoc(), + fiddle::Diagnostics::couldNotOverwriteInputFile, + inputFilePath); return; + } + } + } + void generateAndEmitFiles() + { + for (auto inputFile : inputFiles) + generateAndEmitFilesForInputFile(inputFile); + } - // Before we go actually running any of the scripts - // that make up the template files, we need to - // put things into the environment that will allow - // those scripts to find the things we've scraped... - // - registerScrapedStuffWithScript(logicalModule); - if (sink.getErrorCount()) - return; - + void checkModule() { fiddle::checkModule(this->logicalModule, &sink); } - // Once we've processed the data model, we - // can generate the code that goes into - // the corresponding output file, as well - // as process any templates in the input - // files. - // - generateAndEmitFiles(); - if (sink.getErrorCount()) - return; + void execute(int argc, char const* const* argv) + { + // We start by parsing any command-line options + // that were specified. + // + options.parse(sink, argc, argv); + if (sink.getErrorCount()) + return; + + // All of the code that get scraped will be + // organized into a single logical module, + // with no regard for what file each + // declaration came from. + // + logicalModule = new LogicalModule(); + + // We iterate over the input paths specified on + // the command line, to read each in and process + // its text. + // + // This step both scans for declarations that + // are to be scraped, and also reads the any + // template spans. + // + for (auto inputPath : options.inputPaths) + { + processInputFile(inputPath); } - }; -} + if (sink.getErrorCount()) + return; + + // In order to build up the data model of the + // scraped declarations (such as what inherits + // from what), we need to perform a minimal + // amount of semantic checking here. + // + checkModule(); + if (sink.getErrorCount()) + return; + + + // Before we go actually running any of the scripts + // that make up the template files, we need to + // put things into the environment that will allow + // those scripts to find the things we've scraped... + // + registerScrapedStuffWithScript(logicalModule); + if (sink.getErrorCount()) + return; + + + // Once we've processed the data model, we + // can generate the code that goes into + // the corresponding output file, as well + // as process any templates in the input + // files. + // + generateAndEmitFiles(); + if (sink.getErrorCount()) + return; + } +}; +} // namespace fiddle #define DEBUG_FIDDLE_COMMAND_LINE 0 diff --git a/tools/slang-fiddle/slang-fiddle-options.cpp b/tools/slang-fiddle/slang-fiddle-options.cpp index e5c622b506d..3291dfa63d0 100644 --- a/tools/slang-fiddle/slang-fiddle-options.cpp +++ b/tools/slang-fiddle/slang-fiddle-options.cpp @@ -1,3 +1,2 @@ // slang-fiddle-options.cpp #include "slang-fiddle-options.h" - diff --git a/tools/slang-fiddle/slang-fiddle-options.h b/tools/slang-fiddle/slang-fiddle-options.h index 20ea22d92e0..ae6412ca09c 100644 --- a/tools/slang-fiddle/slang-fiddle-options.h +++ b/tools/slang-fiddle/slang-fiddle-options.h @@ -5,62 +5,57 @@ namespace fiddle { - using namespace Slang; +using namespace Slang; - // +// - struct Options +struct Options +{ +public: + static const char* expectArg(char const* const*& cursor, char const* const* end) + { + if (cursor != end) + return *cursor++; + return nullptr; + } + + void parse(DiagnosticSink& sink, int argc, char const* const* argv) { - public: - static const char* expectArg( - char const* const*& cursor, - char const* const* end) + auto argCursor = argv++; + auto argEnd = argCursor + argc; + + if (argCursor != argEnd) { - if (cursor != end) - return *cursor++; - return nullptr; + appName = *argCursor++; } - void parse( - DiagnosticSink& sink, - int argc, - char const* const* argv) + while (argCursor != argEnd) { - auto argCursor = argv++; - auto argEnd = argCursor + argc; - - if (argCursor != argEnd) + UnownedTerminatedStringSlice arg = *argCursor++; + if (arg[0] != '-') { - appName = *argCursor++; + inputPaths.add(String(arg)); + continue; } - while (argCursor != argEnd) + if (arg == UnownedTerminatedStringSlice("-i")) { - UnownedTerminatedStringSlice arg = *argCursor++; - if (arg[0] != '-') - { - inputPaths.add(String(arg)); - continue; - } - - if (arg == UnownedTerminatedStringSlice("-i")) - { - inputPathPrefix = expectArg(argCursor, argEnd); - } - else if (arg == UnownedTerminatedStringSlice("-o")) - { - outputPathPrefix = expectArg(argCursor, argEnd); - } - else - { - sink.diagnose(SourceLoc(), Diagnostics::unknownOption, arg); - } + inputPathPrefix = expectArg(argCursor, argEnd); + } + else if (arg == UnownedTerminatedStringSlice("-o")) + { + outputPathPrefix = expectArg(argCursor, argEnd); + } + else + { + sink.diagnose(SourceLoc(), Diagnostics::unknownOption, arg); } } - - String appName = "slang-fiddle"; - String inputPathPrefix = ""; - String outputPathPrefix = ""; - List inputPaths; - }; -} + } + + String appName = "slang-fiddle"; + String inputPathPrefix = ""; + String outputPathPrefix = ""; + List inputPaths; +}; +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-scrape.cpp b/tools/slang-fiddle/slang-fiddle-scrape.cpp index ebc65fb769f..c351583813f 100644 --- a/tools/slang-fiddle/slang-fiddle-scrape.cpp +++ b/tools/slang-fiddle/slang-fiddle-scrape.cpp @@ -6,170 +6,151 @@ namespace fiddle { - // Parser +// Parser - struct Parser - { - private: - DiagnosticSink& _sink; - List _tokens; +struct Parser +{ +private: + DiagnosticSink& _sink; + List _tokens; - TokenWithTrivia const* _cursor = nullptr; - TokenWithTrivia const* _end = nullptr; + TokenWithTrivia const* _cursor = nullptr; + TokenWithTrivia const* _end = nullptr; - LogicalModule* _module = nullptr; + LogicalModule* _module = nullptr; - ContainerDecl* _currentParentDecl = nullptr; + ContainerDecl* _currentParentDecl = nullptr; - struct WithParentDecl + struct WithParentDecl + { + public: + WithParentDecl(Parser* outer, ContainerDecl* decl) { - public: - WithParentDecl( - Parser* outer, - ContainerDecl* decl) - { - _outer = outer; - _saved = outer->_currentParentDecl; + _outer = outer; + _saved = outer->_currentParentDecl; - outer->_currentParentDecl = decl; - } + outer->_currentParentDecl = decl; + } - ~WithParentDecl() - { - _outer->_currentParentDecl = _saved; - } + ~WithParentDecl() { _outer->_currentParentDecl = _saved; } - private: - Parser* _outer; - ContainerDecl* _saved; - }; + private: + Parser* _outer; + ContainerDecl* _saved; + }; - public: - Parser( - DiagnosticSink& sink, - List const& tokens, - LogicalModule* module) - : _sink(sink) - , _tokens(tokens) - , _module(module) - { - _cursor = tokens.begin(); - _end = tokens.end() - 1; - } +public: + Parser(DiagnosticSink& sink, List const& tokens, LogicalModule* module) + : _sink(sink), _tokens(tokens), _module(module) + { + _cursor = tokens.begin(); + _end = tokens.end() - 1; + } - bool _isRecovering = false; + bool _isRecovering = false; - TokenWithTrivia const& peek() - { + TokenWithTrivia const& peek() { return *_cursor; } + + SourceLoc const& peekLoc() { return peek().getLoc(); } + + TokenType peekType() { return peek().getType(); } + + TokenWithTrivia read() + { + _isRecovering = false; + if (peekType() != TokenType::EndOfFile) + return *_cursor++; + else return *_cursor; - } + } - SourceLoc const& peekLoc() + TokenWithTrivia expect(TokenType expected) + { + if (peekType() == expected) { - return peek().getLoc(); + return read(); } - TokenType peekType() + if (!_isRecovering) { - return peek().getType(); + _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), expected); } - - TokenWithTrivia read() + else { - _isRecovering = false; - if (peekType() != TokenType::EndOfFile) - return *_cursor++; - else - return *_cursor; + // TODO: need to skip until we see what we expected... + _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); } - TokenWithTrivia expect(TokenType expected) + return TokenWithTrivia(); + } + + TokenWithTrivia expect(const char* expected) + { + if (peekType() == TokenType::Identifier) { - if (peekType() == expected) + if (peek().getContent() == expected) { return read(); } - - if (!_isRecovering) - { - _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), expected); - } - else - { - // TODO: need to skip until we see what we expected... - _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); - } - - return TokenWithTrivia(); } - TokenWithTrivia expect(const char* expected) + if (!_isRecovering) { - if (peekType() == TokenType::Identifier) - { - if (peek().getContent() == expected) - { - return read(); - } - } + _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), expected); + } + else + { + // TODO: need to skip until we see what we expected... + _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); + } - if (!_isRecovering) - { - _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), expected); - } - else - { - // TODO: need to skip until we see what we expected... - _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); - } + return TokenWithTrivia(); + } - return TokenWithTrivia(); + bool advanceIf(TokenType type) + { + if (peekType() == type) + { + read(); + return true; } - bool advanceIf(TokenType type) + return false; + } + + bool advanceIf(char const* name) + { + if (peekType() == TokenType::Identifier) { - if (peekType() == type) + if (peek().getContent() == name) { read(); return true; } - - return false; } - bool advanceIf(char const* name) - { - if (peekType() == TokenType::Identifier) - { - if (peek().getContent() == name) - { - read(); - return true; - } - } - - return false; - } + return false; + } - RefPtr parseCppSimpleExpr() + RefPtr parseCppSimpleExpr() + { + switch (peekType()) { - switch (peekType()) - { - case TokenType::Identifier: + case TokenType::Identifier: { auto nameToken = expect(TokenType::Identifier); return new NameExpr(nameToken); } break; - case TokenType::IntegerLiteral: + case TokenType::IntegerLiteral: { auto token = read(); return new LiteralExpr(token); } break; - case TokenType::LParent: + case TokenType::LParent: { expect(TokenType::LParent); auto inner = parseCppExpr(); @@ -181,11 +162,11 @@ namespace fiddle { case TokenType::Identifier: case TokenType::LParent: - { - auto arg = parseCppExpr(); - return inner; - } - break; + { + auto arg = parseCppExpr(); + return inner; + } + break; default: return inner; @@ -193,23 +174,23 @@ namespace fiddle } break; - default: - expect(TokenType::Identifier); - _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); - } + default: + expect(TokenType::Identifier); + _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); } + } - RefPtr parseCppExpr() + RefPtr parseCppExpr() + { + auto base = parseCppSimpleExpr(); + for (;;) { - auto base = parseCppSimpleExpr(); - for (;;) + switch (peekType()) { - switch (peekType()) - { - default: - return base; + default: + return base; - case TokenType::OpMul: + case TokenType::OpMul: { expect(TokenType::OpMul); switch (peekType()) @@ -221,21 +202,21 @@ namespace fiddle } break; - case TokenType::Scope: + case TokenType::Scope: { expect(TokenType::Scope); auto memberName = expect(TokenType::Identifier); base = new StaticMemberRef(base, memberName); } break; - case TokenType::LParent: + case TokenType::LParent: { // TODO: actually parse this! readBalanced(); } break; - case TokenType::OpLess: + case TokenType::OpLess: { auto specialize = RefPtr(new SpecializeExpr()); specialize->base = base; @@ -248,88 +229,86 @@ namespace fiddle base = specialize; } break; - - } } } + } - RefPtr parseCppSimpleTypeSpecififer() - { + RefPtr parseCppSimpleTypeSpecififer() + { - switch (peekType()) - { - case TokenType::Identifier: + switch (peekType()) + { + case TokenType::Identifier: { auto nameToken = expect(TokenType::Identifier); return new NameExpr(nameToken); } break; - default: - expect(TokenType::Identifier); - _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); - } + default: + expect(TokenType::Identifier); + _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); } + } - List> parseCppTemplateArgs() + List> parseCppTemplateArgs() + { + List> args; + for (;;) { - List> args; - for (;;) + switch (peekType()) { - switch (peekType()) - { - case TokenType::OpGeq: - case TokenType::OpGreater: - case TokenType::OpRsh: - case TokenType::EndOfFile: - return args; - } + case TokenType::OpGeq: + case TokenType::OpGreater: + case TokenType::OpRsh: + case TokenType::EndOfFile: + return args; + } - auto arg = parseCppExpr(); - if (arg) - args.add(arg); + auto arg = parseCppExpr(); + if (arg) + args.add(arg); - if (!advanceIf(TokenType::Comma)) - return args; - } + if (!advanceIf(TokenType::Comma)) + return args; } + } - void parseGenericCloser() - { - if (advanceIf(TokenType::OpGreater)) - return; - - if (peekType() == TokenType::OpRsh) - { - peek().setType(TokenType::OpGreater); + void parseGenericCloser() + { + if (advanceIf(TokenType::OpGreater)) + return; - return; - } + if (peekType() == TokenType::OpRsh) + { + peek().setType(TokenType::OpGreater); - expect(TokenType::OpGreater); + return; } - RefPtr parseCppTypeSpecifier() + expect(TokenType::OpGreater); + } + + RefPtr parseCppTypeSpecifier() + { + auto result = parseCppSimpleTypeSpecififer(); + for (;;) { - auto result = parseCppSimpleTypeSpecififer(); - for (;;) + switch (peekType()) { - switch (peekType()) - { - default: - return result; + default: + return result; - case TokenType::Scope: + case TokenType::Scope: { expect(TokenType::Scope); auto memberName = expect(TokenType::Identifier); auto memberRef = RefPtr(new StaticMemberRef(result, memberName)); result = memberRef; - } break; - case TokenType::OpLess: + case TokenType::OpLess: { auto specialize = RefPtr(new SpecializeExpr()); specialize->base = result; @@ -342,269 +321,267 @@ namespace fiddle result = specialize; } break; - } } } + } - struct UnwrappedDeclarator - { - RefPtr type; - TokenWithTrivia nameToken; - }; + struct UnwrappedDeclarator + { + RefPtr type; + TokenWithTrivia nameToken; + }; - UnwrappedDeclarator unwrapDeclarator(RefPtr declarator, RefPtr type) + UnwrappedDeclarator unwrapDeclarator(RefPtr declarator, RefPtr type) + { + if (!declarator) { - if (!declarator) - { - UnwrappedDeclarator result; - result.type = type; - return result; - } - - if (auto ptrDeclarator = as(declarator)) - { - return unwrapDeclarator(ptrDeclarator->base, new PtrType(type)); - } - else if (auto nameDeclarator = as(declarator)) - { - UnwrappedDeclarator result; - result.type = type; - result.nameToken = nameDeclarator->nameToken; - return result; - } - else - { - _sink.diagnose(SourceLoc(), Diagnostics::unexpected, "declarator type", "known"); - } - + UnwrappedDeclarator result; + result.type = type; + return result; } - RefPtr parseCppType() + if (auto ptrDeclarator = as(declarator)) { - auto typeSpecifier = parseCppTypeSpecifier(); - auto declarator = parseCppDeclarator(); - return unwrapDeclarator(declarator, typeSpecifier).type; + return unwrapDeclarator(ptrDeclarator->base, new PtrType(type)); } - - RefPtr parseCppBase() + else if (auto nameDeclarator = as(declarator)) { - // TODO: allow `private` and `protected` - // TODO: insert a default `public` keyword, if one is missing... - advanceIf("public"); - return parseCppType(); + UnwrappedDeclarator result; + result.type = type; + result.nameToken = nameDeclarator->nameToken; + return result; } - - void parseCppAggTypeDecl( - RefPtr decl) + else { - decl->mode = Mode::Cpp; + _sink.diagnose(SourceLoc(), Diagnostics::unexpected, "declarator type", "known"); + } + } - // read the type name - decl->nameToken = expect(TokenType::Identifier); + RefPtr parseCppType() + { + auto typeSpecifier = parseCppTypeSpecifier(); + auto declarator = parseCppDeclarator(); + return unwrapDeclarator(declarator, typeSpecifier).type; + } - // Read the bases clause. - // - // TODO: handle multiple bases... - // - if (advanceIf(TokenType::Colon)) - { - decl->directBaseType = parseCppBase(); - } + RefPtr parseCppBase() + { + // TODO: allow `private` and `protected` + // TODO: insert a default `public` keyword, if one is missing... + advanceIf("public"); + return parseCppType(); + } - expect(TokenType::LBrace); - addDecl(decl); - WithParentDecl withParent(this, decl); + void parseCppAggTypeDecl(RefPtr decl) + { + decl->mode = Mode::Cpp; - // We expect any `FIDDLE()`-marked aggregate type - // declaration to start with a `FIDDLE(...)` invocation, - // so that there is a suitable insertion point for - // the expansion step. - // - { - auto saved = _cursor; - bool found = peekFiddleEllipsisInvocation(); - _cursor = saved; - if (!found) - { - _sink.diagnose(peekLoc(), fiddle::Diagnostics::expectedFiddleEllipsisInvocation, decl->nameToken.getContent()); - } - } + // read the type name + decl->nameToken = expect(TokenType::Identifier); - parseCppDecls(decl); - expect(TokenType::RBrace); + // Read the bases clause. + // + // TODO: handle multiple bases... + // + if (advanceIf(TokenType::Colon)) + { + decl->directBaseType = parseCppBase(); } - bool peekFiddleEllipsisInvocation() + expect(TokenType::LBrace); + addDecl(decl); + WithParentDecl withParent(this, decl); + + // We expect any `FIDDLE()`-marked aggregate type + // declaration to start with a `FIDDLE(...)` invocation, + // so that there is a suitable insertion point for + // the expansion step. + // { - if (!advanceIf("FIDDLE")) - return false; + auto saved = _cursor; + bool found = peekFiddleEllipsisInvocation(); + _cursor = saved; + if (!found) + { + _sink.diagnose( + peekLoc(), + fiddle::Diagnostics::expectedFiddleEllipsisInvocation, + decl->nameToken.getContent()); + } + } + + parseCppDecls(decl); + expect(TokenType::RBrace); + } + + bool peekFiddleEllipsisInvocation() + { + if (!advanceIf("FIDDLE")) + return false; - if (!advanceIf(TokenType::LParent)) - return false; + if (!advanceIf(TokenType::LParent)) + return false; - if (!advanceIf(TokenType::Ellipsis)) - return false; + if (!advanceIf(TokenType::Ellipsis)) + return false; - return true; - } + return true; + } - RefPtr parseCppSimpleDeclarator() + RefPtr parseCppSimpleDeclarator() + { + switch (peekType()) { - switch (peekType()) - { - case TokenType::Identifier: + case TokenType::Identifier: { auto nameToken = expect(TokenType::Identifier); return RefPtr(new NameDeclarator(nameToken)); } - default: - return nullptr; - } + default: + return nullptr; } + } - RefPtr parseCppPostfixDeclarator() + RefPtr parseCppPostfixDeclarator() + { + auto result = parseCppSimpleDeclarator(); + for (;;) { - auto result = parseCppSimpleDeclarator(); - for (;;) + switch (peekType()) { - switch (peekType()) - { - default: - return result; + default: + return result; - case TokenType::LBracket: - readBalanced(); - return result; - } + case TokenType::LBracket: + readBalanced(); + return result; } - return result; } + return result; + } - RefPtr parseCppDeclarator() - { - advanceIf("const"); + RefPtr parseCppDeclarator() + { + advanceIf("const"); - if (advanceIf(TokenType::OpMul)) - { - auto base = parseCppDeclarator(); - return RefPtr(new PtrDeclarator(base)); - } - else - { - return parseCppPostfixDeclarator(); - } + if (advanceIf(TokenType::OpMul)) + { + auto base = parseCppDeclarator(); + return RefPtr(new PtrDeclarator(base)); } - - void parseCppDeclaratorBasedDecl( - List> const& fiddleModifiers) + else { - auto typeSpecifier = parseCppTypeSpecifier(); - auto declarator = parseCppDeclarator(); + return parseCppPostfixDeclarator(); + } + } - auto unwrapped = unwrapDeclarator(declarator, typeSpecifier); + void parseCppDeclaratorBasedDecl(List> const& fiddleModifiers) + { + auto typeSpecifier = parseCppTypeSpecifier(); + auto declarator = parseCppDeclarator(); - auto varDecl = RefPtr(new VarDecl()); - varDecl->nameToken = unwrapped.nameToken; - varDecl->type = unwrapped.type; - addDecl(varDecl); + auto unwrapped = unwrapDeclarator(declarator, typeSpecifier); - if (advanceIf(TokenType::OpAssign)) - { - varDecl->initExpr = parseCppExpr(); - } - expect(TokenType::Semicolon); + auto varDecl = RefPtr(new VarDecl()); + varDecl->nameToken = unwrapped.nameToken; + varDecl->type = unwrapped.type; + addDecl(varDecl); + if (advanceIf(TokenType::OpAssign)) + { + varDecl->initExpr = parseCppExpr(); } + expect(TokenType::Semicolon); + } - void parseNativeDeclaration( - List> const& fiddleModifiers) + void parseNativeDeclaration(List> const& fiddleModifiers) + { + auto keyword = peek(); + if (advanceIf("namespace")) { - auto keyword = peek(); - if (advanceIf("namespace")) - { - RefPtr namespaceDecl = new PhysicalNamespaceDecl(); - namespaceDecl->modifiers = fiddleModifiers; + RefPtr namespaceDecl = new PhysicalNamespaceDecl(); + namespaceDecl->modifiers = fiddleModifiers; - // read the namespace name - namespaceDecl->nameToken = expect(TokenType::Identifier); + // read the namespace name + namespaceDecl->nameToken = expect(TokenType::Identifier); - expect(TokenType::LBrace); + expect(TokenType::LBrace); - addDecl(namespaceDecl); - WithParentDecl withNamespace(this, namespaceDecl); + addDecl(namespaceDecl); + WithParentDecl withNamespace(this, namespaceDecl); - parseCppDecls(namespaceDecl); + parseCppDecls(namespaceDecl); - expect(TokenType::RBrace); - } - else if (advanceIf("class")) - { - auto decl = RefPtr(new ClassDecl()); - decl->modifiers = fiddleModifiers; - parseCppAggTypeDecl(decl); - } - else if (advanceIf("struct")) - { - auto decl = RefPtr(new StructDecl()); - decl->modifiers = fiddleModifiers; - parseCppAggTypeDecl(decl); - } - else if (peekType() == TokenType::Identifier) - { - // try to parse a declarator-based declaration - // (which for now is probably a field); - // - parseCppDeclaratorBasedDecl(fiddleModifiers); - } - else - { - _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), "OTHER"); - _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); - } + expect(TokenType::RBrace); } - - List> parseFiddleModifiers() + else if (advanceIf("class")) + { + auto decl = RefPtr(new ClassDecl()); + decl->modifiers = fiddleModifiers; + parseCppAggTypeDecl(decl); + } + else if (advanceIf("struct")) { - List> modifiers; + auto decl = RefPtr(new StructDecl()); + decl->modifiers = fiddleModifiers; + parseCppAggTypeDecl(decl); + } + else if (peekType() == TokenType::Identifier) + { + // try to parse a declarator-based declaration + // (which for now is probably a field); + // + parseCppDeclaratorBasedDecl(fiddleModifiers); + } + else + { + _sink.diagnose(peekLoc(), fiddle::Diagnostics::unexpected, peekType(), "OTHER"); + _sink.diagnose(SourceLoc(), fiddle::Diagnostics::internalError); + } + } - for (;;) - { - switch (peekType()) - { - default: - return modifiers; + List> parseFiddleModifiers() + { + List> modifiers; - case TokenType::Identifier: - break; - } + for (;;) + { + switch (peekType()) + { + default: + return modifiers; - if (advanceIf("abstract")) - { - modifiers.add(new AbstractModifier()); - } - else if (advanceIf("hidden")) - { - modifiers.add(new HiddenModifier()); - } - else - { - return modifiers; - } + case TokenType::Identifier: + break; } - return modifiers; + if (advanceIf("abstract")) + { + modifiers.add(new AbstractModifier()); + } + else if (advanceIf("hidden")) + { + modifiers.add(new HiddenModifier()); + } + else + { + return modifiers; + } } - RefPtr parseFiddlePrimaryExpr() + return modifiers; + } + + RefPtr parseFiddlePrimaryExpr() + { + switch (peekType()) { - switch (peekType()) - { - case TokenType::Identifier: - return new NameExpr(read()); + case TokenType::Identifier: + return new NameExpr(read()); - case TokenType::LParent: + case TokenType::LParent: { expect(TokenType::LParent); auto expr = parseFiddleExpr(); @@ -612,49 +589,49 @@ namespace fiddle return expr; } - default: - expect(TokenType::Identifier); - return nullptr; - } + default: + expect(TokenType::Identifier); + return nullptr; } + } - List> parseFiddleArgs() + List> parseFiddleArgs() + { + List> args; + for (;;) { - List> args; - for (;;) + switch (peekType()) { - switch (peekType()) - { - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - case TokenType::EndOfFile: - return args; + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + case TokenType::EndOfFile: + return args; - default: - break; - } + default: + break; + } - auto arg = parseFiddleExpr(); - args.add(arg); + auto arg = parseFiddleExpr(); + args.add(arg); - if (!advanceIf(TokenType::Comma)) - return args; - } + if (!advanceIf(TokenType::Comma)) + return args; } + } - RefPtr parseFiddlePostifxExpr() - { - auto result = parseFiddlePrimaryExpr(); + RefPtr parseFiddlePostifxExpr() + { + auto result = parseFiddlePrimaryExpr(); - for (;;) + for (;;) + { + switch (peekType()) { - switch (peekType()) - { - default: - return result; + default: + return result; - case TokenType::Dot: + case TokenType::Dot: { expect(TokenType::Dot); auto memberName = expect(TokenType::Identifier); @@ -663,7 +640,7 @@ namespace fiddle } break; - case TokenType::LParent: + case TokenType::LParent: { expect(TokenType::LParent); auto args = parseFiddleArgs(); @@ -672,573 +649,552 @@ namespace fiddle result = new CallExpr(result, args); } break; - } - } } - RefPtr parseFiddleExpr() - { - return parseFiddlePostifxExpr(); - } + } + RefPtr parseFiddleExpr() { return parseFiddlePostifxExpr(); } - RefPtr parseFiddleTypeExpr() - { - return parseFiddleExpr(); - } + RefPtr parseFiddleTypeExpr() { return parseFiddleExpr(); } - void parseFiddleAggTypeDecl(RefPtr decl) - { - decl->mode = Mode::Fiddle; + void parseFiddleAggTypeDecl(RefPtr decl) + { + decl->mode = Mode::Fiddle; - // read the type name - decl->nameToken = expect(TokenType::Identifier); + // read the type name + decl->nameToken = expect(TokenType::Identifier); - // Read the bases clause. - if (advanceIf(TokenType::Colon)) - { - decl->directBaseType = parseFiddleTypeExpr(); - } + // Read the bases clause. + if (advanceIf(TokenType::Colon)) + { + decl->directBaseType = parseFiddleTypeExpr(); + } - addDecl(decl); - WithParentDecl withParent(this, decl); + addDecl(decl); + WithParentDecl withParent(this, decl); - if (advanceIf(TokenType::LBrace)) - { - parseOptionalFiddleModeDecls(); + if (advanceIf(TokenType::LBrace)) + { + parseOptionalFiddleModeDecls(); - expect(TokenType::RBrace); - } - else - { - expect(TokenType::Semicolon); - } + expect(TokenType::RBrace); } - - void parseFiddleModeDecl(List> modifiers) + else { - if (advanceIf("class")) - { - auto decl = RefPtr(new ClassDecl()); - decl->modifiers = modifiers; - parseFiddleAggTypeDecl(decl); - } - else - { - _sink.diagnose(peekLoc(), Diagnostics::unexpected, peekType(), "fiddle-mode declaration"); - } + expect(TokenType::Semicolon); } + } - void parseFiddleModeDecl() + void parseFiddleModeDecl(List> modifiers) + { + if (advanceIf("class")) + { + auto decl = RefPtr(new ClassDecl()); + decl->modifiers = modifiers; + parseFiddleAggTypeDecl(decl); + } + else { - auto modifiers = parseFiddleModifiers(); - parseFiddleModeDecl(modifiers); + _sink.diagnose( + peekLoc(), + Diagnostics::unexpected, + peekType(), + "fiddle-mode declaration"); } + } - void parseOptionalFiddleModeDecls() + void parseFiddleModeDecl() + { + auto modifiers = parseFiddleModifiers(); + parseFiddleModeDecl(modifiers); + } + + void parseOptionalFiddleModeDecls() + { + for (;;) { - for (;;) + switch (peekType()) { - switch (peekType()) - { - case TokenType::RParent: - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::EndOfFile: - return; - } - - parseFiddleModeDecl(); + case TokenType::RParent: + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::EndOfFile: + return; } - } - void parseFiddleModeDecls(List> modifiers) - { - parseFiddleModeDecl(modifiers); - parseOptionalFiddleModeDecls(); + parseFiddleModeDecl(); } + } - void parseFiddleNode() - { - auto fiddleToken = expect("FIDDLE"); - - // We will capture the token at this invocation site, - // because later on we will generate a macro that - // this invocation will expand into. - // - auto fiddleMacroInvocation = RefPtr(new FiddleMacroInvocation()); - fiddleMacroInvocation->fiddleToken = fiddleToken; - addDecl(fiddleMacroInvocation); - - // The `FIDDLE` keyword can be followed by parentheses around a bunch of - // fiddle-mode modifiers. - List> fiddleModifiers; - if (advanceIf(TokenType::LParent)) - { - if (advanceIf(TokenType::Ellipsis)) - { - // A `FIDDLE(...)` invocation is a hook for - // our expansion step to insert the generated - // declarations that go into the body of - // the parent declaration. + void parseFiddleModeDecls(List> modifiers) + { + parseFiddleModeDecl(modifiers); + parseOptionalFiddleModeDecls(); + } - fiddleMacroInvocation->node = _currentParentDecl; + void parseFiddleNode() + { + auto fiddleToken = expect("FIDDLE"); - expect(TokenType::RParent); - return; - } + // We will capture the token at this invocation site, + // because later on we will generate a macro that + // this invocation will expand into. + // + auto fiddleMacroInvocation = RefPtr(new FiddleMacroInvocation()); + fiddleMacroInvocation->fiddleToken = fiddleToken; + addDecl(fiddleMacroInvocation); + // The `FIDDLE` keyword can be followed by parentheses around a bunch of + // fiddle-mode modifiers. + List> fiddleModifiers; + if (advanceIf(TokenType::LParent)) + { + if (advanceIf(TokenType::Ellipsis)) + { + // A `FIDDLE(...)` invocation is a hook for + // our expansion step to insert the generated + // declarations that go into the body of + // the parent declaration. - // We start off by parsing optional modifiers - fiddleModifiers = parseFiddleModifiers(); + fiddleMacroInvocation->node = _currentParentDecl; - if (peekType() != TokenType::RParent) - { - // In this case we are expecting a fiddle-mode declaration - // to appear, in which case we will allow any number of full - // fiddle-mode declarations, but won't expect a C++-mode - // declaration to follow. - - // TODO: We should associate these declarations - // as children of the `FiddleMacroInvocation`, - // so that they can be emitted as part of its - // expansion (if we decide to make more use - // of the `FIDDLE()` approach...). - - parseFiddleModeDecls(fiddleModifiers); - expect(TokenType::RParent); - return; - } expect(TokenType::RParent); + return; } - else + + + // We start off by parsing optional modifiers + fiddleModifiers = parseFiddleModifiers(); + + if (peekType() != TokenType::RParent) { - // TODO: diagnose this! - } + // In this case we are expecting a fiddle-mode declaration + // to appear, in which case we will allow any number of full + // fiddle-mode declarations, but won't expect a C++-mode + // declaration to follow. - // Any tokens from here on are expected to be in C++-mode + // TODO: We should associate these declarations + // as children of the `FiddleMacroInvocation`, + // so that they can be emitted as part of its + // expansion (if we decide to make more use + // of the `FIDDLE()` approach...). - parseNativeDeclaration(fiddleModifiers); + parseFiddleModeDecls(fiddleModifiers); + expect(TokenType::RParent); + return; + } + expect(TokenType::RParent); } - - void addDecl(ContainerDecl* parentDecl, Decl* memberDecl) + else { - if (!memberDecl) - return; + // TODO: diagnose this! + } - parentDecl->members.add(memberDecl); + // Any tokens from here on are expected to be in C++-mode - auto physicalParent = as(parentDecl); - if (!physicalParent) - return; + parseNativeDeclaration(fiddleModifiers); + } - auto logicalParent = physicalParent->logicalVersion; - if (!logicalParent) - return; + void addDecl(ContainerDecl* parentDecl, Decl* memberDecl) + { + if (!memberDecl) + return; - if (auto physicalNamespace = as(memberDecl)) - { - auto namespaceName = physicalNamespace->nameToken.getContent(); - auto logicalNamespace = findDecl(logicalParent, namespaceName); - if (!logicalNamespace) - { - logicalNamespace = new LogicalNamespace(); + parentDecl->members.add(memberDecl); - logicalNamespace->nameToken = physicalNamespace->nameToken; + auto physicalParent = as(parentDecl); + if (!physicalParent) + return; - logicalParent->members.add(logicalNamespace); - logicalParent->mapNameToMember.add(namespaceName, logicalNamespace); - } - physicalNamespace->logicalVersion = logicalNamespace; - } - else + auto logicalParent = physicalParent->logicalVersion; + if (!logicalParent) + return; + + if (auto physicalNamespace = as(memberDecl)) + { + auto namespaceName = physicalNamespace->nameToken.getContent(); + auto logicalNamespace = findDecl(logicalParent, namespaceName); + if (!logicalNamespace) { - logicalParent->members.add(memberDecl); + logicalNamespace = new LogicalNamespace(); + + logicalNamespace->nameToken = physicalNamespace->nameToken; + + logicalParent->members.add(logicalNamespace); + logicalParent->mapNameToMember.add(namespaceName, logicalNamespace); } + physicalNamespace->logicalVersion = logicalNamespace; } - - void addDecl(RefPtr decl) + else { - addDecl(_currentParentDecl, decl); + logicalParent->members.add(memberDecl); } + } - void parseCppDecls(RefPtr parentDecl) + void addDecl(RefPtr decl) { addDecl(_currentParentDecl, decl); } + + void parseCppDecls(RefPtr parentDecl) + { + for (;;) { - for (;;) + switch (peekType()) { - switch (peekType()) - { - case TokenType::EndOfFile: - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - return; - - default: - break; - } + case TokenType::EndOfFile: + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + return; - parseCppDecl(); + default: + break; } - } - void readBalanced() - { - Count skipCount = read().getSkipCount(); - _cursor = _cursor + skipCount; + parseCppDecl(); } + } - void parseCppDecl() + void readBalanced() + { + Count skipCount = read().getSkipCount(); + _cursor = _cursor + skipCount; + } + + void parseCppDecl() + { + // We consume raw tokens until we see something + // that ought to start a reflected/extracted declaration. + // + for (;;) { - // We consume raw tokens until we see something - // that ought to start a reflected/extracted declaration. - // - for (;;) + switch (peekType()) { - switch (peekType()) - { - default: + default: { readBalanced(); continue; } - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - case TokenType::EndOfFile: - return; + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + case TokenType::EndOfFile: + return; - case TokenType::Identifier: - break; + case TokenType::Identifier: + break; - case TokenType::Pound: - // a `#` means we have run into a preprocessor directive - // (or, somehow, we are already *inside* one...). - // - // We don't want to try to intercept anything to do with - // these lines, so we will read until the next end-of-line. - // + case TokenType::Pound: + // a `#` means we have run into a preprocessor directive + // (or, somehow, we are already *inside* one...). + // + // We don't want to try to intercept anything to do with + // these lines, so we will read until the next end-of-line. + // + read(); + while (!(peek().getToken().flags & TokenFlag::AtStartOfLine)) + { + if (peekType() == TokenType::EndOfFile) + break; read(); - while (!(peek().getToken().flags & TokenFlag::AtStartOfLine)) - { - if (peekType() == TokenType::EndOfFile) - break; - read(); - } - continue; } + continue; + } - // Okay, we have an identifier, but is its name - // one that we want to pay attention to? + // Okay, we have an identifier, but is its name + // one that we want to pay attention to? + // + // + auto name = peek().getContent(); + if (name == "FIDDLE") + { + // If the `FIDDLE` is the first token we are seeing, then we will + // start parsing a construct in fiddle-mode: // + parseFiddleNode(); + } + else + { + // If the name isn't one we recognize, then + // we are just reading raw tokens as usual. // - auto name = peek().getContent(); - if (name == "FIDDLE") - { - // If the `FIDDLE` is the first token we are seeing, then we will - // start parsing a construct in fiddle-mode: - // - parseFiddleNode(); - } - else - { - // If the name isn't one we recognize, then - // we are just reading raw tokens as usual. - // - readBalanced(); - continue; - } + readBalanced(); + continue; } } + } + + RefPtr parseSourceUnit() + { + RefPtr sourceUnit = new SourceUnit(); + sourceUnit->logicalVersion = _module; - RefPtr parseSourceUnit() + WithParentDecl withSourceUnit(this, sourceUnit); + while (_cursor != _end) { - RefPtr sourceUnit = new SourceUnit(); - sourceUnit->logicalVersion = _module; + parseCppDecl(); - WithParentDecl withSourceUnit(this, sourceUnit); - while (_cursor != _end) + switch (peekType()) { - parseCppDecl(); - - switch (peekType()) - { - default: - break; + default: + break; - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - case TokenType::EndOfFile: - read(); - break; - } + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + case TokenType::EndOfFile: + read(); + break; } - read(); - - return sourceUnit; } + read(); - }; + return sourceUnit; + } +}; +// Check - // Check +struct CheckContext +{ +private: + DiagnosticSink& sink; - struct CheckContext +public: + CheckContext(DiagnosticSink& sink) + : sink(sink) { - private: - DiagnosticSink& sink; + } - public: - CheckContext(DiagnosticSink& sink) - : sink(sink) - {} + void checkModule(LogicalModule* module) { checkMemberDecls(module); } - void checkModule(LogicalModule* module) +private: + struct Scope + { + public: + Scope(ContainerDecl* containerDecl, Scope* outer) + : containerDecl(containerDecl), outer(outer) { - checkMemberDecls(module); } - private: - struct Scope - { - public: - Scope(ContainerDecl* containerDecl, Scope* outer) - : containerDecl(containerDecl) - , outer(outer) - {} - - ContainerDecl* containerDecl = nullptr; - Scope* outer = nullptr; - }; - Scope* currentScope = nullptr; + ContainerDecl* containerDecl = nullptr; + Scope* outer = nullptr; + }; + Scope* currentScope = nullptr; - struct WithScope : Scope + struct WithScope : Scope + { + WithScope(CheckContext* context, ContainerDecl* containerDecl) + : Scope(containerDecl, context->currentScope) + , _context(context) + , _saved(context->currentScope) { - WithScope(CheckContext* context, ContainerDecl* containerDecl) - : Scope(containerDecl, context->currentScope) - , _context(context) - , _saved(context->currentScope) - { - context->currentScope = this; - } + context->currentScope = this; + } - ~WithScope() - { - _context->currentScope = _saved; - } + ~WithScope() { _context->currentScope = _saved; } - private: - CheckContext* _context = nullptr; - Scope* _saved = nullptr; - }; + private: + CheckContext* _context = nullptr; + Scope* _saved = nullptr; + }; - // - void checkDecl(Decl* decl) + // + void checkDecl(Decl* decl) + { + if (auto aggTypeDecl = as(decl)) { - if (auto aggTypeDecl = as(decl)) - { - checkTypeExprInPlace(aggTypeDecl->directBaseType); + checkTypeExprInPlace(aggTypeDecl->directBaseType); - if (auto baseType = aggTypeDecl->directBaseType) + if (auto baseType = aggTypeDecl->directBaseType) + { + if (auto baseDeclRef = as(baseType)) { - if (auto baseDeclRef = as(baseType)) + auto baseDecl = baseDeclRef->decl; + if (auto baseAggTypeDecl = as(baseDecl)) { - auto baseDecl = baseDeclRef->decl; - if (auto baseAggTypeDecl = as(baseDecl)) - { - baseAggTypeDecl->directSubTypeDecls.add(aggTypeDecl); - } + baseAggTypeDecl->directSubTypeDecls.add(aggTypeDecl); } } - - checkMemberDecls(aggTypeDecl); - } - else if (auto namespaceDecl = as(decl)) - { - checkMemberDecls(namespaceDecl); - } - else if (auto varDecl = as(decl)) - { - // Note: for now we aren't trying to check the type - // or the initial-value expression of a field. - } - else if (as(decl)) - { } - else - { - sink.diagnose(SourceLoc(), Diagnostics::unexpected, "case in checkDecl", "known type"); - } - } - void checkMemberDecls(ContainerDecl* containerDecl) + checkMemberDecls(aggTypeDecl); + } + else if (auto namespaceDecl = as(decl)) { - WithScope moduleScope(this, containerDecl); - for (auto memberDecl : containerDecl->members) - { - checkDecl(memberDecl); - } + checkMemberDecls(namespaceDecl); } - - void checkTypeExprInPlace(RefPtr& ioTypeExpr) + else if (auto varDecl = as(decl)) { - if (!ioTypeExpr) - return; - ioTypeExpr = checkTypeExpr(ioTypeExpr); + // Note: for now we aren't trying to check the type + // or the initial-value expression of a field. } + else if (as(decl)) + { + } + else + { + sink.diagnose(SourceLoc(), Diagnostics::unexpected, "case in checkDecl", "known type"); + } + } - RefPtr checkTypeExpr(Expr* expr) + void checkMemberDecls(ContainerDecl* containerDecl) + { + WithScope moduleScope(this, containerDecl); + for (auto memberDecl : containerDecl->members) { - return checkExpr(expr); + checkDecl(memberDecl); } + } + + void checkTypeExprInPlace(RefPtr& ioTypeExpr) + { + if (!ioTypeExpr) + return; + ioTypeExpr = checkTypeExpr(ioTypeExpr); + } - RefPtr checkExpr(Expr* expr) + RefPtr checkTypeExpr(Expr* expr) { return checkExpr(expr); } + + RefPtr checkExpr(Expr* expr) + { + if (auto nameExpr = as(expr)) { - if (auto nameExpr = as(expr)) - { - return lookUp(nameExpr->nameToken.getContent()); - } - else - { - sink.diagnose(SourceLoc(), Diagnostics::unexpected, "case in checkExpr", "known type"); - } + return lookUp(nameExpr->nameToken.getContent()); } + else + { + sink.diagnose(SourceLoc(), Diagnostics::unexpected, "case in checkExpr", "known type"); + } + } - RefPtr lookUp(UnownedStringSlice const& name) + RefPtr lookUp(UnownedStringSlice const& name) + { + for (auto scope = currentScope; scope; scope = scope->outer) { - for (auto scope = currentScope; scope; scope = scope->outer) + auto containerDecl = scope->containerDecl; + // TODO: accelerate lookup with a dictionary on the container... + for (auto memberDecl : containerDecl->members) { - auto containerDecl = scope->containerDecl; - // TODO: accelerate lookup with a dictionary on the container... - for (auto memberDecl : containerDecl->members) + if (memberDecl->nameToken.getContent() == name) { - if (memberDecl->nameToken.getContent() == name) - { - return new DirectDeclRef(memberDecl); - } + return new DirectDeclRef(memberDecl); } } - sink.diagnose(SourceLoc(), Diagnostics::undefinedIdentifier, name); - return nullptr; } - }; - + sink.diagnose(SourceLoc(), Diagnostics::undefinedIdentifier, name); + return nullptr; + } +}; +// Emit - // Emit +struct EmitContext +{ +private: + SourceManager& _sourceManager; + RefPtr _module; + DiagnosticSink& _sink; + StringBuilder& _builder; + +public: + EmitContext( + StringBuilder& builder, + DiagnosticSink& sink, + SourceManager& sourceManager, + LogicalModule* module) + : _builder(builder), _sink(sink), _sourceManager(sourceManager), _module(module) + { + } - struct EmitContext + void emitMacrosRec(Decl* decl) { - private: - SourceManager& _sourceManager; - RefPtr _module; - DiagnosticSink& _sink; - StringBuilder& _builder; - - public: - EmitContext( - StringBuilder& builder, - DiagnosticSink& sink, - SourceManager& sourceManager, - LogicalModule* module) - : _builder(builder) - , _sink(sink) - , _sourceManager(sourceManager) - , _module(module) - {} - - void emitMacrosRec(Decl* decl) - { - emitMacrosForDecl(decl); - if (auto container = as(decl)) - { - for (auto member : container->members) - emitMacrosRec(member); - } + emitMacrosForDecl(decl); + if (auto container = as(decl)) + { + for (auto member : container->members) + emitMacrosRec(member); } + } - private: - - void emitMacrosForDecl(Decl* decl) +private: + void emitMacrosForDecl(Decl* decl) + { + if (auto fiddleMacroInvocation = as(decl)) { - if (auto fiddleMacroInvocation = as(decl)) - { - emitMacroForFiddleInvocation(fiddleMacroInvocation); - } - else - { - // do nothing with most decls - } + emitMacroForFiddleInvocation(fiddleMacroInvocation); } - - void emitMacroForFiddleInvocation( - FiddleMacroInvocation* fiddleInvocation) + else { - SourceLoc loc = fiddleInvocation->fiddleToken.getLoc(); - auto humaneLoc = _sourceManager.getHumaneLoc(loc); - auto lineNumber = humaneLoc.line; + // do nothing with most decls + } + } + + void emitMacroForFiddleInvocation(FiddleMacroInvocation* fiddleInvocation) + { + SourceLoc loc = fiddleInvocation->fiddleToken.getLoc(); + auto humaneLoc = _sourceManager.getHumaneLoc(loc); + auto lineNumber = humaneLoc.line; #define MACRO_LINE_ENDING " \\\n" - // Un-define the old `FIDDLE_#` macro for the - // given line number, since this file might - // be pulling in another generated header - // via one of its dependencies. - // - _builder.append("#ifdef FIDDLE_"); - _builder.append(lineNumber); - _builder.append("\n#undef FIDDLE_"); - _builder.append(lineNumber); - _builder.append("\n#endif\n"); - - _builder.append("#define FIDDLE_"); - _builder.append(lineNumber); - _builder.append("(...)"); - _builder.append(MACRO_LINE_ENDING); - - auto decl = as(fiddleInvocation->node); - if (decl) + // Un-define the old `FIDDLE_#` macro for the + // given line number, since this file might + // be pulling in another generated header + // via one of its dependencies. + // + _builder.append("#ifdef FIDDLE_"); + _builder.append(lineNumber); + _builder.append("\n#undef FIDDLE_"); + _builder.append(lineNumber); + _builder.append("\n#endif\n"); + + _builder.append("#define FIDDLE_"); + _builder.append(lineNumber); + _builder.append("(...)"); + _builder.append(MACRO_LINE_ENDING); + + auto decl = as(fiddleInvocation->node); + if (decl) + { + if (auto base = decl->directBaseType) { - if (auto base = decl->directBaseType) - { - _builder.append("private: typedef "); - emitTypedDecl(base, "Super"); - _builder.append(";" MACRO_LINE_ENDING); - } + _builder.append("private: typedef "); + emitTypedDecl(base, "Super"); + _builder.append(";" MACRO_LINE_ENDING); + } - if (decl->isSubTypeOf("NodeBase")) - { - _builder.append("friend class ::Slang::ASTBuilder;" MACRO_LINE_ENDING); - _builder.append("friend struct ::Slang::SyntaxClassInfo;" MACRO_LINE_ENDING); + if (decl->isSubTypeOf("NodeBase")) + { + _builder.append("friend class ::Slang::ASTBuilder;" MACRO_LINE_ENDING); + _builder.append("friend struct ::Slang::SyntaxClassInfo;" MACRO_LINE_ENDING); - _builder.append("public: static const ::Slang::SyntaxClassInfo kSyntaxClassInfo;" MACRO_LINE_ENDING); + _builder.append("public: static const ::Slang::SyntaxClassInfo " + "kSyntaxClassInfo;" MACRO_LINE_ENDING); - _builder.append("public: static constexpr ASTNodeType kType = ASTNodeType::"); - _builder.append(decl->nameToken.getContent()); - _builder.append(";" MACRO_LINE_ENDING); + _builder.append("public: static constexpr ASTNodeType kType = ASTNodeType::"); + _builder.append(decl->nameToken.getContent()); + _builder.append(";" MACRO_LINE_ENDING); - _builder.append("public: "); - _builder.append(decl->nameToken.getContent()); - _builder.append("() {}" MACRO_LINE_ENDING); - } - _builder.append("public:" MACRO_LINE_ENDING); + _builder.append("public: "); + _builder.append(decl->nameToken.getContent()); + _builder.append("() {}" MACRO_LINE_ENDING); } - _builder.append("/* end */\n\n"); + _builder.append("public:" MACRO_LINE_ENDING); } + _builder.append("/* end */\n\n"); + } - void emitTypedDecl(Expr* expr, const char* name) + void emitTypedDecl(Expr* expr, const char* name) + { + if (auto declRef = as(expr)) { - if (auto declRef = as(expr)) - { - _builder.append(declRef->decl->nameToken.getContent()); - _builder.append(" "); - _builder.append(name); - } + _builder.append(declRef->decl->nameToken.getContent()); + _builder.append(" "); + _builder.append(name); } + } #if 0 void emitLineDirective(Token const& lexeme) @@ -1338,461 +1294,439 @@ namespace fiddle private: #endif - }; - +}; - - - - - - Decl* findDecl_(ContainerDecl* outerDecl, UnownedStringSlice const& name) +Decl* findDecl_(ContainerDecl* outerDecl, UnownedStringSlice const& name) +{ + for (auto memberDecl : outerDecl->members) { - for (auto memberDecl : outerDecl->members) - { - if (memberDecl->nameToken.getContent() == name) - return memberDecl; - } - return nullptr; + if (memberDecl->nameToken.getContent() == name) + return memberDecl; } + return nullptr; +} - bool AggTypeDecl::isSubTypeOf(char const* name) +bool AggTypeDecl::isSubTypeOf(char const* name) +{ + Decl* decl = this; + while (decl) { - Decl* decl = this; - while (decl) + if (decl->nameToken.getContent() == UnownedTerminatedStringSlice(name)) { - if (decl->nameToken.getContent() == UnownedTerminatedStringSlice(name)) - { - return true; - } + return true; + } - auto aggType = as(decl); - if (!aggType) - break; + auto aggType = as(decl); + if (!aggType) + break; - auto baseTypeExpr = aggType->directBaseType; - if (!baseTypeExpr) - break; + auto baseTypeExpr = aggType->directBaseType; + if (!baseTypeExpr) + break; - auto declRef = as(baseTypeExpr); - if (!declRef) - break; + auto declRef = as(baseTypeExpr); + if (!declRef) + break; - decl = declRef->decl; - } - return false; + decl = declRef->decl; } + return false; +} - bool isTrivia(TokenType lexemeType) +bool isTrivia(TokenType lexemeType) +{ + switch (lexemeType) { - switch (lexemeType) - { - default: - return false; + default: + return false; - case TokenType::LineComment: - case TokenType::BlockComment: - case TokenType::NewLine: - case TokenType::WhiteSpace: - return true; - } + case TokenType::LineComment: + case TokenType::BlockComment: + case TokenType::NewLine: + case TokenType::WhiteSpace: + return true; } +} + +List collectTokensWithTrivia(TokenList const& lexemes) +{ + TokenReader reader(lexemes); - List collectTokensWithTrivia(TokenList const& lexemes) + List allTokensWithTrivia; + for (;;) { - TokenReader reader(lexemes); + RefPtr currentTokenWithTriviaNode = new TokenWithTriviaNode(); + TokenWithTrivia currentTokenWithTrivia = currentTokenWithTriviaNode; + allTokensWithTrivia.add(currentTokenWithTrivia); - List allTokensWithTrivia; - for (;;) + while (isTrivia(reader.peekTokenType())) { - RefPtr currentTokenWithTriviaNode = new TokenWithTriviaNode(); - TokenWithTrivia currentTokenWithTrivia = currentTokenWithTriviaNode; - allTokensWithTrivia.add(currentTokenWithTrivia); - - while (isTrivia(reader.peekTokenType())) - { - auto trivia = reader.advanceToken(); - currentTokenWithTriviaNode->leadingTrivia.add(trivia); - } + auto trivia = reader.advanceToken(); + currentTokenWithTriviaNode->leadingTrivia.add(trivia); + } - auto token = reader.advanceToken(); - currentTokenWithTriviaNode->token = token; + auto token = reader.advanceToken(); + currentTokenWithTriviaNode->token = token; - if (token.type == TokenType::EndOfFile) - return allTokensWithTrivia; + if (token.type == TokenType::EndOfFile) + return allTokensWithTrivia; - while (isTrivia(reader.peekTokenType())) - { - auto trivia = reader.advanceToken(); - currentTokenWithTriviaNode->trailingTrivia.add(trivia); + while (isTrivia(reader.peekTokenType())) + { + auto trivia = reader.advanceToken(); + currentTokenWithTriviaNode->trailingTrivia.add(trivia); - if (trivia.type == TokenType::NewLine) - break; - } + if (trivia.type == TokenType::NewLine) + break; } } +} - void readTokenTree( - List const& tokens, - Index& ioIndex); +void readTokenTree(List const& tokens, Index& ioIndex); - void readBalancedToken( - List const& tokens, - Index& ioIndex, - TokenType closeType) - { - auto open = tokens[ioIndex++]; - auto openNode = (TokenWithTriviaNode*)open; +void readBalancedToken(List const& tokens, Index& ioIndex, TokenType closeType) +{ + auto open = tokens[ioIndex++]; + auto openNode = (TokenWithTriviaNode*)open; - Index startIndex = ioIndex; - for (;;) + Index startIndex = ioIndex; + for (;;) + { + auto token = tokens[ioIndex]; + if (token.getType() == closeType) { - auto token = tokens[ioIndex]; - if (token.getType() == closeType) - { - ioIndex++; - break; - } + ioIndex++; + break; + } - switch (token.getType()) - { - default: - readTokenTree(tokens, ioIndex); - continue; + switch (token.getType()) + { + default: + readTokenTree(tokens, ioIndex); + continue; - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - case TokenType::EndOfFile: - break; - } + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + case TokenType::EndOfFile: break; } - openNode->skipCount = ioIndex - startIndex; + break; } + openNode->skipCount = ioIndex - startIndex; +} - void readTokenTree( - List const& tokens, - Index& ioIndex) +void readTokenTree(List const& tokens, Index& ioIndex) +{ + switch (tokens[ioIndex].getType()) { - switch (tokens[ioIndex].getType()) - { - default: - ioIndex++; - return; + default: + ioIndex++; + return; - case TokenType::LBrace: - return readBalancedToken(tokens, ioIndex, TokenType::RBrace); + case TokenType::LBrace: + return readBalancedToken(tokens, ioIndex, TokenType::RBrace); - case TokenType::LBracket: - return readBalancedToken(tokens, ioIndex, TokenType::RBracket); + case TokenType::LBracket: + return readBalancedToken(tokens, ioIndex, TokenType::RBracket); - case TokenType::LParent: - return readBalancedToken(tokens, ioIndex, TokenType::RParent); - } + case TokenType::LParent: + return readBalancedToken(tokens, ioIndex, TokenType::RParent); } +} - void matchBalancedTokens(List tokens) +void matchBalancedTokens(List tokens) +{ + Index index = 0; + for (;;) { - Index index = 0; - for (;;) + auto& token = tokens[index]; + switch (token.getType()) { - auto& token = tokens[index]; - switch (token.getType()) - { - case TokenType::EndOfFile: - return; + case TokenType::EndOfFile: + return; - default: - readTokenTree(tokens, index); - break; + default: + readTokenTree(tokens, index); + break; - case TokenType::RBrace: - case TokenType::RBracket: - case TokenType::RParent: - // error!!! - index++; - break; - } + case TokenType::RBrace: + case TokenType::RBracket: + case TokenType::RParent: + // error!!! + index++; + break; } } +} - bool findOutputFileIncludeDirective( - List tokens, - String outputFileName) - { - auto cursor = tokens.begin(); - auto end = tokens.end() - 1; +bool findOutputFileIncludeDirective(List tokens, String outputFileName) +{ + auto cursor = tokens.begin(); + auto end = tokens.end() - 1; - while (cursor != end) + while (cursor != end) + { + if (cursor->getType() != TokenType::Pound) { - if (cursor->getType() != TokenType::Pound) - { - cursor++; - continue; - } cursor++; + continue; + } + cursor++; - if (cursor->getContent() != "include") - continue; - cursor++; + if (cursor->getContent() != "include") + continue; + cursor++; - if (cursor->getType() != TokenType::StringLiteral) - continue; + if (cursor->getType() != TokenType::StringLiteral) + continue; - auto includedFileName = getStringLiteralTokenValue(cursor->getToken()); - if (includedFileName == outputFileName) - return true; - } - return false; + auto includedFileName = getStringLiteralTokenValue(cursor->getToken()); + if (includedFileName == outputFileName) + return true; } + return false; +} - RefPtr parseSourceUnit( - SourceView* inputSourceView, - LogicalModule* logicalModule, - RootNamePool* rootNamePool, - DiagnosticSink* sink, - SourceManager* sourceManager, - String outputFileName) +RefPtr parseSourceUnit( + SourceView* inputSourceView, + LogicalModule* logicalModule, + RootNamePool* rootNamePool, + DiagnosticSink* sink, + SourceManager* sourceManager, + String outputFileName) +{ + Lexer lexer; + NamePool namePool; + namePool.setRootNamePool(rootNamePool); + + // We suppress any diagnostics that might get emitted during lexing, + // so that we can ignore any files we don't understand. + // + DiagnosticSink lexerSink; + lexer.initialize(inputSourceView, &lexerSink, &namePool, sourceManager->getMemoryArena()); + + auto inputTokens = lexer.lexAllTokens(); + auto tokensWithTrivia = collectTokensWithTrivia(inputTokens); + matchBalancedTokens(tokensWithTrivia); + + Parser parser(*sink, tokensWithTrivia, logicalModule); + auto sourceUnit = parser.parseSourceUnit(); + + // As a quick validation check, if the source file had + // any `FIDDLE()` invocations in it, then we check to + // make sure it also has a `#include` of the corresponding + // output file name... + if (hasAnyFiddleInvocations(sourceUnit)) { - Lexer lexer; - NamePool namePool; - namePool.setRootNamePool(rootNamePool); - - // We suppress any diagnostics that might get emitted during lexing, - // so that we can ignore any files we don't understand. - // - DiagnosticSink lexerSink; - lexer.initialize(inputSourceView, &lexerSink, &namePool, sourceManager->getMemoryArena()); - - auto inputTokens = lexer.lexAllTokens(); - auto tokensWithTrivia = collectTokensWithTrivia(inputTokens); - matchBalancedTokens(tokensWithTrivia); - - Parser parser(*sink, tokensWithTrivia, logicalModule); - auto sourceUnit = parser.parseSourceUnit(); - - // As a quick validation check, if the source file had - // any `FIDDLE()` invocations in it, then we check to - // make sure it also has a `#include` of the corresponding - // output file name... - if (hasAnyFiddleInvocations(sourceUnit)) + if (!findOutputFileIncludeDirective(tokensWithTrivia, outputFileName)) { - if (!findOutputFileIncludeDirective(tokensWithTrivia, outputFileName)) - { - sink->diagnose(inputSourceView->getRange().begin, fiddle::Diagnostics::expectedIncludeOfOutputHeader, outputFileName); - } + sink->diagnose( + inputSourceView->getRange().begin, + fiddle::Diagnostics::expectedIncludeOfOutputHeader, + outputFileName); } - - return sourceUnit; } - void push(lua_State* L, Val* val); + return sourceUnit; +} - void push(lua_State* L, UnownedStringSlice const& text) - { - lua_pushlstring(L, text.begin(), text.getLength()); - } +void push(lua_State* L, Val* val); + +void push(lua_State* L, UnownedStringSlice const& text) +{ + lua_pushlstring(L, text.begin(), text.getLength()); +} - template - void push(lua_State* L, Listconst& values) +template +void push(lua_State* L, List const& values) +{ + // Note: Lua tables are naturally indexed starting at 1. + Index nextIndex = 1; + lua_newtable(L); + for (auto value : values) { - // Note: Lua tables are naturally indexed starting at 1. - Index nextIndex = 1; - lua_newtable(L); - for (auto value : values) - { - Index index = nextIndex++; + Index index = nextIndex++; - push(L, value); - lua_seti(L, -2, index); - } + push(L, value); + lua_seti(L, -2, index); } +} + +void getAllSubclasses(AggTypeDecl* decl, List>& ioSubclasses) +{ + ioSubclasses.add(decl); + for (auto subclass : decl->directSubTypeDecls) + getAllSubclasses(subclass, ioSubclasses); +} + +List> getAllSubclasses(AggTypeDecl* decl) +{ + List> result; + getAllSubclasses(decl, result); + return result; +} + +int _toStringVal(lua_State* L) +{ + Val* val = (Val*)lua_touserdata(L, 1); - void getAllSubclasses( - AggTypeDecl* decl, - List>& ioSubclasses) + if (auto directDeclRef = as(val)) { - ioSubclasses.add(decl); - for (auto subclass : decl->directSubTypeDecls) - getAllSubclasses(subclass, ioSubclasses); + val = directDeclRef->decl; } - List> getAllSubclasses(AggTypeDecl* decl) + if (auto decl = as(val)) { - List> result; - getAllSubclasses(decl, result); - return result; + push(L, decl->nameToken.getContent()); + return 1; } - int _toStringVal(lua_State* L) - { - Val* val = (Val*)lua_touserdata(L, 1); + lua_pushfstring(L, "fiddle::Val @ 0x%p", val); + return 1; +} - if (auto directDeclRef = as(val)) - { - val = directDeclRef->decl; - } +int _indexVal(lua_State* L) +{ + Val* val = (Val*)lua_touserdata(L, 1); + char const* name = lua_tostring(L, 2); - if (auto decl = as(val)) + if (auto containerDecl = as(val)) + { + for (auto m : containerDecl->members) { - push(L, decl->nameToken.getContent()); - return 1; + if (m->nameToken.getContent() == UnownedTerminatedStringSlice(name)) + { + push(L, m); + return 1; + } } - - lua_pushfstring(L, "fiddle::Val @ 0x%p", val); - return 1; } - int _indexVal(lua_State* L) + if (auto classDecl = as(val)) { - Val* val = (Val*)lua_touserdata(L, 1); - char const* name = lua_tostring(L, 2); - - if (auto containerDecl = as(val)) + if (strcmp(name, "subclasses") == 0) { - for (auto m : containerDecl->members) - { - if (m->nameToken.getContent() == UnownedTerminatedStringSlice(name)) - { - push(L, m); - return 1; - } - } + auto value = getAllSubclasses(classDecl); + push(L, value); + return 1; } - if (auto classDecl = as(val)) + if (strcmp(name, "directSuperClass") == 0) { - if (strcmp(name, "subclasses") == 0) - { - auto value = getAllSubclasses(classDecl); - push(L, value); - return 1; - } - - if (strcmp(name, "directSuperClass") == 0) - { - push(L, classDecl->directBaseType); - return 1; - } - - if (strcmp(name, "directFields") == 0) - { - List> fields; - for (auto m : classDecl->members) - { - if (auto f = as(m)) - fields.add(f); - } - push(L, fields); - return 1; - } + push(L, classDecl->directBaseType); + return 1; } - if (auto decl = as(val)) + if (strcmp(name, "directFields") == 0) { - if (strcmp(name, "isAbstract") == 0) + List> fields; + for (auto m : classDecl->members) { - lua_pushboolean(L, - decl->findModifier() != nullptr); - return 1; + if (auto f = as(m)) + fields.add(f); } + push(L, fields); + return 1; } - - return 0; } - void push(lua_State* L, Val* val) + if (auto decl = as(val)) { - if (!val) + if (strcmp(name, "isAbstract") == 0) { - lua_pushnil(L); - return; + lua_pushboolean(L, decl->findModifier() != nullptr); + return 1; } + } - lua_pushlightuserdata(L, val); - if (luaL_newmetatable(L, "fiddle::Val")) - { - lua_pushcfunction(L, &_indexVal); - lua_setfield(L, -2, "__index"); + return 0; +} - lua_pushcfunction(L, &_toStringVal); - lua_setfield(L, -2, "__tostring"); - } - lua_setmetatable(L, -2); +void push(lua_State* L, Val* val) +{ + if (!val) + { + lua_pushnil(L); + return; } - void registerValWithScript(String name, Val* val) + lua_pushlightuserdata(L, val); + if (luaL_newmetatable(L, "fiddle::Val")) { - auto L = getLuaState(); + lua_pushcfunction(L, &_indexVal); + lua_setfield(L, -2, "__index"); - push(L, val); - lua_setglobal(L, name.getBuffer()); + lua_pushcfunction(L, &_toStringVal); + lua_setfield(L, -2, "__tostring"); } + lua_setmetatable(L, -2); +} +void registerValWithScript(String name, Val* val) +{ + auto L = getLuaState(); - void registerScrapedStuffWithScript( - LogicalModule* logicalModule) - { - for (auto decl : logicalModule->members) - { - if (!decl->nameToken) - continue; + push(L, val); + lua_setglobal(L, name.getBuffer()); +} - registerValWithScript( - decl->nameToken.getContent(), - decl); - } - } - bool _hasAnyFiddleInvocationsRec( - Decl* decl) +void registerScrapedStuffWithScript(LogicalModule* logicalModule) +{ + for (auto decl : logicalModule->members) { - if (as(decl)) - return true; + if (!decl->nameToken) + continue; - if (auto container = as(decl)) - { - for (auto m : container->members) - { - if (_hasAnyFiddleInvocationsRec(m)) - return true; - } - } - return false; + registerValWithScript(decl->nameToken.getContent(), decl); } +} - bool hasAnyFiddleInvocations( - SourceUnit* sourceUnit) - { - return _hasAnyFiddleInvocationsRec(sourceUnit); - } +bool _hasAnyFiddleInvocationsRec(Decl* decl) +{ + if (as(decl)) + return true; - void checkModule( - LogicalModule* module, - DiagnosticSink* sink) + if (auto container = as(decl)) { - CheckContext context(*sink); - context.checkModule(module); + for (auto m : container->members) + { + if (_hasAnyFiddleInvocationsRec(m)) + return true; + } } + return false; +} +bool hasAnyFiddleInvocations(SourceUnit* sourceUnit) +{ + return _hasAnyFiddleInvocationsRec(sourceUnit); +} - void emitSourceUnitMacros( - SourceUnit* sourceUnit, - StringBuilder& builder, - DiagnosticSink* sink, - SourceManager* sourceManager, - LogicalModule* logicalModule) - { - // The basic task here is to find each of the - // `FIDDLE()` macro invocations, and for each - // of them produce a matching definition that - // will be used as the expansion of that one - // +void checkModule(LogicalModule* module, DiagnosticSink* sink) +{ + CheckContext context(*sink); + context.checkModule(module); +} - EmitContext context(builder, *sink, *sourceManager, logicalModule); - context.emitMacrosRec(sourceUnit); - } +void emitSourceUnitMacros( + SourceUnit* sourceUnit, + StringBuilder& builder, + DiagnosticSink* sink, + SourceManager* sourceManager, + LogicalModule* logicalModule) +{ + // The basic task here is to find each of the + // `FIDDLE()` macro invocations, and for each + // of them produce a matching definition that + // will be used as the expansion of that one + // + + EmitContext context(builder, *sink, *sourceManager, logicalModule); + context.emitMacrosRec(sourceUnit); } + +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-scrape.h b/tools/slang-fiddle/slang-fiddle-scrape.h index 03c0511c4aa..5cd0b6d057d 100644 --- a/tools/slang-fiddle/slang-fiddle-scrape.h +++ b/tools/slang-fiddle/slang-fiddle-scrape.h @@ -1,362 +1,352 @@ // slang-fiddle-scrape.h #pragma once -#include "slang-fiddle-diagnostics.h" - #include "compiler-core/slang-lexer.h" +#include "slang-fiddle-diagnostics.h" namespace fiddle { - using namespace Slang; +using namespace Slang; - class Val : public RefObject - { - public: - }; - - class Node : public Val - { - public: - }; +class Val : public RefObject +{ +public: +}; - // Grouping Tokens and Trivia +class Node : public Val +{ +public: +}; - class TokenWithTriviaNode : public RefObject - { - public: - TokenType getType() const { - return token.type; - } +// Grouping Tokens and Trivia - List leadingTrivia; - Token token; - List trailingTrivia; - Count skipCount = 0; - }; +class TokenWithTriviaNode : public RefObject +{ +public: + TokenType getType() const { return token.type; } - struct TokenWithTrivia - { - public: - TokenWithTrivia() - {} + List leadingTrivia; + Token token; + List trailingTrivia; + Count skipCount = 0; +}; - TokenWithTrivia( - RefPtr node) - : node(node) - {} +struct TokenWithTrivia +{ +public: + TokenWithTrivia() {} - SourceLoc const& getLoc() const - { - return node->token.loc; - } + TokenWithTrivia(RefPtr node) + : node(node) + { + } - Token const& getToken() const - { - return node->token; - } + SourceLoc const& getLoc() const { return node->token.loc; } - TokenType getType() const - { - return node ? node->getType() : TokenType::Unknown; - } + Token const& getToken() const { return node->token; } - UnownedStringSlice getContent() const - { - return node ? node->token.getContent() : UnownedStringSlice(); - } + TokenType getType() const { return node ? node->getType() : TokenType::Unknown; } - Count getSkipCount() const - { - return node ? node->skipCount : 0; - } - - void setType(TokenType type) const - { - node->token.type = type; - } - - List const& getLeadingTrivia() const { return node->leadingTrivia; } - List const& getTrailingTrivia() const { return node->trailingTrivia; } + UnownedStringSlice getContent() const + { + return node ? node->token.getContent() : UnownedStringSlice(); + } - operator TokenWithTriviaNode* () { return node; } + Count getSkipCount() const { return node ? node->skipCount : 0; } - private: - RefPtr node; - }; + void setType(TokenType type) const { node->token.type = type; } + List const& getLeadingTrivia() const { return node->leadingTrivia; } + List const& getTrailingTrivia() const { return node->trailingTrivia; } + operator TokenWithTriviaNode*() { return node; } +private: + RefPtr node; +}; - // Syntax +// Syntax - class Declarator : public Node - { - }; +class Declarator : public Node +{ +}; - class NameDeclarator : public Declarator +class NameDeclarator : public Declarator +{ +public: + NameDeclarator(TokenWithTrivia nameToken) + : nameToken(nameToken) { - public: - NameDeclarator(TokenWithTrivia nameToken) - : nameToken(nameToken) - {} + } - TokenWithTrivia nameToken; - }; + TokenWithTrivia nameToken; +}; - class PtrDeclarator : public Declarator +class PtrDeclarator : public Declarator +{ +public: + PtrDeclarator(RefPtr base) + : base(base) { - public: - PtrDeclarator(RefPtr base) - : base(base) - {} + } - RefPtr base; - }; + RefPtr base; +}; - class Expr : public Node - { - public: - }; +class Expr : public Node +{ +public: +}; - class ModifierNode : public Node - { - }; +class ModifierNode : public Node +{ +}; - class AbstractModifier : public ModifierNode {}; - class HiddenModifier : public ModifierNode {}; +class AbstractModifier : public ModifierNode +{ +}; +class HiddenModifier : public ModifierNode +{ +}; - enum class Mode - { - Fiddle, - Cpp, - }; +enum class Mode +{ + Fiddle, + Cpp, +}; - class Decl : public Node +class Decl : public Node +{ +public: + template + T* findModifier() { - public: - template - T* findModifier() + for (auto m : modifiers) { - for (auto m : modifiers) - { - if (auto found = as(m)) - return found; - } - return nullptr; + if (auto found = as(m)) + return found; } + return nullptr; + } - List> modifiers; - TokenWithTrivia nameToken; - Mode mode = Mode::Cpp; - }; + List> modifiers; + TokenWithTrivia nameToken; + Mode mode = Mode::Cpp; +}; - class ContainerDecl : public Decl - { - public: - List> members; - Dictionary> mapNameToMember; - }; - - class LogicalContainerDecl : public ContainerDecl - {}; +class ContainerDecl : public Decl +{ +public: + List> members; + Dictionary> mapNameToMember; +}; - class LogicalNamespaceBase : public LogicalContainerDecl - {}; +class LogicalContainerDecl : public ContainerDecl +{ +}; - class LogicalModule : public LogicalNamespaceBase - { - public: - }; +class LogicalNamespaceBase : public LogicalContainerDecl +{ +}; - class LogicalNamespace : public LogicalNamespaceBase - {}; +class LogicalModule : public LogicalNamespaceBase +{ +public: +}; - class PhysicalContainerDecl : public ContainerDecl - { - public: - LogicalContainerDecl* logicalVersion = nullptr; - }; +class LogicalNamespace : public LogicalNamespaceBase +{ +}; - class SourceUnit : public PhysicalContainerDecl - { - public: - }; +class PhysicalContainerDecl : public ContainerDecl +{ +public: + LogicalContainerDecl* logicalVersion = nullptr; +}; - class PhysicalNamespaceDecl : public PhysicalContainerDecl - { - public: +class SourceUnit : public PhysicalContainerDecl +{ +public: +}; - }; +class PhysicalNamespaceDecl : public PhysicalContainerDecl +{ +public: +}; - class AggTypeDecl : public ContainerDecl - { - public: - RefPtr directBaseType; +class AggTypeDecl : public ContainerDecl +{ +public: + RefPtr directBaseType; - List directSubTypeDecls; + List directSubTypeDecls; - bool isSubTypeOf(char const* name); - }; + bool isSubTypeOf(char const* name); +}; - class ClassDecl : public AggTypeDecl {}; - class StructDecl : public AggTypeDecl {}; +class ClassDecl : public AggTypeDecl +{ +}; +class StructDecl : public AggTypeDecl +{ +}; - class VarDecl : public Decl - { - public: - RefPtr type; - RefPtr initExpr; - }; +class VarDecl : public Decl +{ +public: + RefPtr type; + RefPtr initExpr; +}; - class FiddleMacroInvocation : public Decl - { - public: - TokenWithTrivia fiddleToken; // the actual `FIDDLE` identifier +class FiddleMacroInvocation : public Decl +{ +public: + TokenWithTrivia fiddleToken; // the actual `FIDDLE` identifier - RefPtr node; // the node whose generated content should get emitted... - }; + RefPtr node; // the node whose generated content should get emitted... +}; - class UncheckedExpr : public Expr - {}; +class UncheckedExpr : public Expr +{ +}; - class CheckedExpr : public Expr - {}; +class CheckedExpr : public Expr +{ +}; - class NameExpr : public UncheckedExpr +class NameExpr : public UncheckedExpr +{ +public: + NameExpr(TokenWithTrivia nameToken) + : nameToken(nameToken) { - public: - NameExpr(TokenWithTrivia nameToken) - : nameToken(nameToken) - {} + } - TokenWithTrivia nameToken; - }; + TokenWithTrivia nameToken; +}; - class LiteralExpr : public UncheckedExpr +class LiteralExpr : public UncheckedExpr +{ +public: + LiteralExpr(TokenWithTrivia token) + : token(token) { - public: - LiteralExpr(TokenWithTrivia token) - : token(token) - {} + } - TokenWithTrivia token; - }; + TokenWithTrivia token; +}; - class MemberExpr : public UncheckedExpr +class MemberExpr : public UncheckedExpr +{ +public: + MemberExpr(RefPtr base, TokenWithTrivia memberNameToken) + : base(base), memberNameToken(memberNameToken) { - public: - MemberExpr(RefPtr base, TokenWithTrivia memberNameToken) - : base(base) - , memberNameToken(memberNameToken) - {} + } - RefPtr base; - TokenWithTrivia memberNameToken; - }; + RefPtr base; + TokenWithTrivia memberNameToken; +}; - class StaticMemberRef : public UncheckedExpr +class StaticMemberRef : public UncheckedExpr +{ +public: + StaticMemberRef(RefPtr base, TokenWithTrivia memberNameToken) + : base(base), memberNameToken(memberNameToken) { - public: - StaticMemberRef(RefPtr base, TokenWithTrivia memberNameToken) - : base(base) - , memberNameToken(memberNameToken) - {} + } - RefPtr base; - TokenWithTrivia memberNameToken; - }; + RefPtr base; + TokenWithTrivia memberNameToken; +}; - typedef Expr Arg; +typedef Expr Arg; - class PtrType : public UncheckedExpr +class PtrType : public UncheckedExpr +{ +public: + PtrType(RefPtr base) + : base(base) { - public: - PtrType(RefPtr base) - : base(base) - {} + } - RefPtr base; - }; + RefPtr base; +}; - class SpecializeExpr : public UncheckedExpr - { - public: - SpecializeExpr() - {} +class SpecializeExpr : public UncheckedExpr +{ +public: + SpecializeExpr() {} - RefPtr base; - List> args; - }; + RefPtr base; + List> args; +}; - class CallExpr : public UncheckedExpr +class CallExpr : public UncheckedExpr +{ +public: + CallExpr(RefPtr base, List> args) + : base(base), args(args) { - public: - CallExpr(RefPtr base, List> args) - : base(base) - , args(args) - {} + } - RefPtr base; - List> args; - }; + RefPtr base; + List> args; +}; - class DirectDeclRef : public CheckedExpr +class DirectDeclRef : public CheckedExpr +{ +public: + DirectDeclRef(Decl* decl) + : decl(decl) { - public: - DirectDeclRef(Decl* decl) - : decl(decl) - {} - - Decl* decl = nullptr; - }; + } - // + Decl* decl = nullptr; +}; - Decl* findDecl_(ContainerDecl* outerDecl, UnownedStringSlice const& name); +// - template - T* findDecl(ContainerDecl* outerDecl, UnownedStringSlice const& name) - { - auto decl = findDecl_(outerDecl, name); - if (!decl) - return nullptr; +Decl* findDecl_(ContainerDecl* outerDecl, UnownedStringSlice const& name); - auto asType = as(decl); - if (!asType) - { - // TODO: might need this case to be an error... - return nullptr; - } +template +T* findDecl(ContainerDecl* outerDecl, UnownedStringSlice const& name) +{ + auto decl = findDecl_(outerDecl, name); + if (!decl) + return nullptr; - return asType; + auto asType = as(decl); + if (!asType) + { + // TODO: might need this case to be an error... + return nullptr; } + return asType; +} - RefPtr parseSourceUnit( - SourceView* inputSourceView, - LogicalModule* logicalModule, - RootNamePool* rootNamePool, - DiagnosticSink* sink, - SourceManager* sourceManager, - String outputFileName); +RefPtr parseSourceUnit( + SourceView* inputSourceView, + LogicalModule* logicalModule, + RootNamePool* rootNamePool, + DiagnosticSink* sink, + SourceManager* sourceManager, + String outputFileName); - bool hasAnyFiddleInvocations( - SourceUnit* sourceUnit); +bool hasAnyFiddleInvocations(SourceUnit* sourceUnit); - void checkModule( - LogicalModule* module, - DiagnosticSink* sink); +void checkModule(LogicalModule* module, DiagnosticSink* sink); - void registerScrapedStuffWithScript( - LogicalModule* logicalModule); +void registerScrapedStuffWithScript(LogicalModule* logicalModule); - void emitSourceUnitMacros( - SourceUnit* sourceUnit, - StringBuilder& builder, - DiagnosticSink* sink, - SourceManager* sourceManager, - LogicalModule* logicalModule); -} +void emitSourceUnitMacros( + SourceUnit* sourceUnit, + StringBuilder& builder, + DiagnosticSink* sink, + SourceManager* sourceManager, + LogicalModule* logicalModule); +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-script.cpp b/tools/slang-fiddle/slang-fiddle-script.cpp index af1ac2f2bc9..0a07e4798ca 100644 --- a/tools/slang-fiddle/slang-fiddle-script.cpp +++ b/tools/slang-fiddle/slang-fiddle-script.cpp @@ -2,173 +2,171 @@ #include "slang-fiddle-script.h" #include "../external/lua/lapi.h" -#include "../external/lua/lualib.h" #include "../external/lua/lauxlib.h" +#include "../external/lua/lualib.h" namespace fiddle { - DiagnosticSink* _sink = nullptr; - StringBuilder* _builder = nullptr; - Count _templateCounter = 0; +DiagnosticSink* _sink = nullptr; +StringBuilder* _builder = nullptr; +Count _templateCounter = 0; - void diagnoseLuaError(lua_State* L) +void diagnoseLuaError(lua_State* L) +{ + size_t size = 0; + char const* buffer = lua_tolstring(L, -1, &size); + String message = UnownedStringSlice(buffer, size); + message = message + "\n"; + if (_sink) { - size_t size = 0; - char const* buffer = lua_tolstring(L, -1, &size); - String message = UnownedStringSlice(buffer, size); - message = message + "\n"; - if (_sink) - { - _sink->diagnoseRaw(Severity::Error, message.getBuffer()); - } - else - { - fprintf(stderr, "%s", message.getBuffer()); - } + _sink->diagnoseRaw(Severity::Error, message.getBuffer()); } - - int _handleLuaError(lua_State* L) + else { - diagnoseLuaError(L); - return lua_error(L); + fprintf(stderr, "%s", message.getBuffer()); } +} + +int _handleLuaError(lua_State* L) +{ + diagnoseLuaError(L); + return lua_error(L); +} + +int _original(lua_State* L) +{ + // We ignore the text that we want to just pass + // through unmodified... + return 0; +} + +int _raw(lua_State* L) +{ + size_t size = 0; + char const* buffer = lua_tolstring(L, 1, &size); - int _original(lua_State* L) + _builder->append(UnownedStringSlice(buffer, size)); + return 0; +} + +int _splice(lua_State* L) +{ + auto savedBuilder = _builder; + + StringBuilder spliceBuilder; + _builder = &spliceBuilder; + + lua_pushvalue(L, 1); + auto result = lua_pcall(L, 0, 1, 0); + + _builder = savedBuilder; + + if (result != LUA_OK) { - // We ignore the text that we want to just pass - // through unmodified... - return 0; + return _handleLuaError(L); } - int _raw(lua_State* L) + // The actual string value follows whatever + // got printed to the output (unless it is + // nil). + // + _builder->append(spliceBuilder.produceString()); + if (!lua_isnil(L, -1)) { size_t size = 0; - char const* buffer = lua_tolstring(L, 1, &size); - + char const* buffer = luaL_tolstring(L, -1, &size); _builder->append(UnownedStringSlice(buffer, size)); - return 0; } + return 0; +} - int _splice(lua_State* L) +int _template(lua_State* L) +{ + auto templateID = _templateCounter++; + + _builder->append("\n#if FIDDLE_GENERATED_OUTPUT_ID == "); + _builder->append(templateID); + _builder->append("\n"); + + lua_pushvalue(L, 1); + auto result = lua_pcall(L, 0, 0, 0); + if (result != LUA_OK) { - auto savedBuilder = _builder; - - StringBuilder spliceBuilder; - _builder = &spliceBuilder; - - lua_pushvalue(L, 1); - auto result = lua_pcall(L, 0, 1, 0); - - _builder = savedBuilder; - - if (result != LUA_OK) - { - return _handleLuaError(L); - } - - // The actual string value follows whatever - // got printed to the output (unless it is - // nil). - // - _builder->append(spliceBuilder.produceString()); - if (!lua_isnil(L, -1)) - { - size_t size = 0; - char const* buffer = luaL_tolstring(L, -1, &size); - _builder->append(UnownedStringSlice(buffer, size)); - } - return 0; + return _handleLuaError(L); } - int _template(lua_State* L) - { - auto templateID = _templateCounter++; + _builder->append("\n#endif\n"); - _builder->append("\n#if FIDDLE_GENERATED_OUTPUT_ID == "); - _builder->append(templateID); - _builder->append("\n"); + return 0; +} - lua_pushvalue(L, 1); - auto result = lua_pcall(L, 0, 0, 0); - if (result != LUA_OK) - { - return _handleLuaError(L); - } +lua_State* L = nullptr; - _builder->append("\n#endif\n"); +void ensureLuaInitialized() +{ + if (L) + return; - return 0; - } + L = luaL_newstate(); + luaL_openlibs(L); - lua_State* L = nullptr; + lua_pushcclosure(L, &_original, 0); + lua_setglobal(L, "ORIGINAL"); - void ensureLuaInitialized() - { - if (L) return; + lua_pushcclosure(L, &_raw, 0); + lua_setglobal(L, "RAW"); - L = luaL_newstate(); - luaL_openlibs(L); + lua_pushcclosure(L, &_splice, 0); + lua_setglobal(L, "SPLICE"); - lua_pushcclosure(L, &_original, 0); - lua_setglobal(L, "ORIGINAL"); + lua_pushcclosure(L, &_template, 0); + lua_setglobal(L, "TEMPLATE"); - lua_pushcclosure(L, &_raw, 0); - lua_setglobal(L, "RAW"); + // TODO: register custom stuff here... +} - lua_pushcclosure(L, &_splice, 0); - lua_setglobal(L, "SPLICE"); +lua_State* getLuaState() +{ + ensureLuaInitialized(); + return L; +} - lua_pushcclosure(L, &_template, 0); - lua_setglobal(L, "TEMPLATE"); - // TODO: register custom stuff here... - } +String evaluateScriptCode(String originalFileName, String scriptSource, DiagnosticSink* sink) +{ + StringBuilder builder; + _builder = &builder; + _templateCounter = 0; - lua_State* getLuaState() + ensureLuaInitialized(); + + String luaChunkName = "@" + originalFileName; + + if (LUA_OK != luaL_loadbuffer( + L, + scriptSource.getBuffer(), + scriptSource.getLength(), + luaChunkName.getBuffer())) { - ensureLuaInitialized(); - return L; + size_t size = 0; + char const* buffer = lua_tolstring(L, -1, &size); + String message = UnownedStringSlice(buffer, size); + message = message + "\n"; + sink->diagnoseRaw(Severity::Error, message.getBuffer()); + throw 99; } - - String evaluateScriptCode( - String originalFileName, - String scriptSource, - DiagnosticSink* sink) + if (LUA_OK != lua_pcall(L, 0, 0, 0)) { - StringBuilder builder; - _builder = &builder; - _templateCounter = 0; - - ensureLuaInitialized(); - - String luaChunkName = "@" + originalFileName; - - if (LUA_OK != luaL_loadbuffer( - L, - scriptSource.getBuffer(), - scriptSource.getLength(), - luaChunkName.getBuffer())) - { - size_t size = 0; - char const* buffer = lua_tolstring(L, -1, &size); - String message = UnownedStringSlice(buffer, size); - message = message + "\n"; - sink->diagnoseRaw(Severity::Error, message.getBuffer()); - throw 99; - } - - if (LUA_OK != lua_pcall(L, 0, 0, 0)) - { - size_t size = 0; - char const* buffer = lua_tolstring(L, -1, &size); - String message = UnownedStringSlice(buffer, size); - message = message + "\n"; - sink->diagnoseRaw(Severity::Error, message.getBuffer()); - throw 99; - } - - _builder = nullptr; - return builder.produceString(); + size_t size = 0; + char const* buffer = lua_tolstring(L, -1, &size); + String message = UnownedStringSlice(buffer, size); + message = message + "\n"; + sink->diagnoseRaw(Severity::Error, message.getBuffer()); + throw 99; } + + _builder = nullptr; + return builder.produceString(); } +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-script.h b/tools/slang-fiddle/slang-fiddle-script.h index fcb5faf4df5..d8221a2e819 100644 --- a/tools/slang-fiddle/slang-fiddle-script.h +++ b/tools/slang-fiddle/slang-fiddle-script.h @@ -1,24 +1,19 @@ // slang-fiddle-script.h #pragma once -#include "slang-fiddle-diagnostics.h" -#include "slang-fiddle-scrape.h" - -#include "core/slang-string.h" -#include "core/slang-list.h" -#include "compiler-core/slang-source-loc.h" - #include "../external/lua/lapi.h" #include "../external/lua/lauxlib.h" +#include "compiler-core/slang-source-loc.h" +#include "core/slang-list.h" +#include "core/slang-string.h" +#include "slang-fiddle-diagnostics.h" +#include "slang-fiddle-scrape.h" namespace fiddle { - using namespace Slang; +using namespace Slang; - lua_State* getLuaState(); +lua_State* getLuaState(); - String evaluateScriptCode( - String originalFileName, - String scriptSource, - DiagnosticSink* sink); -} +String evaluateScriptCode(String originalFileName, String scriptSource, DiagnosticSink* sink); +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-template.cpp b/tools/slang-fiddle/slang-fiddle-template.cpp index ddf01f8942a..86bd60930d9 100644 --- a/tools/slang-fiddle/slang-fiddle-template.cpp +++ b/tools/slang-fiddle/slang-fiddle-template.cpp @@ -5,552 +5,526 @@ namespace fiddle { - struct TextTemplateParserBase +struct TextTemplateParserBase +{ +protected: + TextTemplateParserBase( + SourceView* inputSourceView, + DiagnosticSink* sink, + UnownedStringSlice source) + : _inputSourceView(inputSourceView) + , _sink(sink) + , _cursor(source.begin()) + , _end(source.end()) { - protected: - TextTemplateParserBase( - SourceView* inputSourceView, - DiagnosticSink* sink, - UnownedStringSlice source) - : _inputSourceView(inputSourceView) - , _sink(sink) - , _cursor(source.begin()) - , _end(source.end()) - {} - - SourceView* _inputSourceView = nullptr; - DiagnosticSink* _sink = nullptr; - char const* _cursor = nullptr; - char const* _end = nullptr; - - bool atEnd() - { - return _cursor == _end; - } + } - UnownedStringSlice readLine() - { - auto lineBegin = _cursor; + SourceView* _inputSourceView = nullptr; + DiagnosticSink* _sink = nullptr; + char const* _cursor = nullptr; + char const* _end = nullptr; - while (!atEnd()) - { - char const* lineEnd = _cursor; - switch (*_cursor) - { - default: - _cursor++; - continue; + bool atEnd() { return _cursor == _end; } - case '\r': - _cursor++; - if (*_cursor == '\n') - _cursor++; - break; + UnownedStringSlice readLine() + { + auto lineBegin = _cursor; + + while (!atEnd()) + { + char const* lineEnd = _cursor; + switch (*_cursor) + { + default: + _cursor++; + continue; - case '\n': + case '\r': + _cursor++; + if (*_cursor == '\n') _cursor++; - break; - } + break; - return UnownedStringSlice(lineBegin, lineEnd); + case '\n': + _cursor++; + break; } - return UnownedStringSlice(lineBegin, _end); + return UnownedStringSlice(lineBegin, lineEnd); } - }; - struct TextTemplateParser : TextTemplateParserBase + return UnownedStringSlice(lineBegin, _end); + } +}; + +struct TextTemplateParser : TextTemplateParserBase +{ +public: + TextTemplateParser( + SourceView* inputSourceView, + DiagnosticSink* sink, + UnownedStringSlice templateSource) + : TextTemplateParserBase(inputSourceView, sink, templateSource) { - public: - TextTemplateParser( - SourceView* inputSourceView, - DiagnosticSink* sink, - UnownedStringSlice templateSource) - : TextTemplateParserBase(inputSourceView, sink, templateSource) - {} - - char const* findScriptStmtLine( - UnownedStringSlice line) + } + + char const* findScriptStmtLine(UnownedStringSlice line) + { + char const* lineCursor = line.begin(); + char const* lineEnd = line.end(); + while (lineCursor != lineEnd) { - char const* lineCursor = line.begin(); - char const* lineEnd = line.end(); - while (lineCursor != lineEnd) + switch (*lineCursor) { - switch (*lineCursor) - { - default: - return nullptr; + default: + return nullptr; - case ' ': case '\t': - lineCursor++; - continue; + case ' ': + case '\t': + lineCursor++; + continue; - case '%': - return lineCursor; - } + case '%': + return lineCursor; } - return nullptr; } + return nullptr; + } - List> stmts; + List> stmts; - void addRaw( - char const* rawBegin, - char const* rawEnd) - { - if (rawBegin == rawEnd) - return; + void addRaw(char const* rawBegin, char const* rawEnd) + { + if (rawBegin == rawEnd) + return; - auto stmt = RefPtr(new TextTemplateRawStmt()); - stmt->text = UnownedStringSlice(rawBegin, rawEnd); - stmts.add(stmt); - } + auto stmt = RefPtr(new TextTemplateRawStmt()); + stmt->text = UnownedStringSlice(rawBegin, rawEnd); + stmts.add(stmt); + } - void addScriptStmtLine( - char const* sourceBegin, - char const* sourceEnd) - { - auto stmt = RefPtr(new TextTemplateScriptStmt()); - stmt->scriptSource = UnownedStringSlice(sourceBegin, sourceEnd); - stmts.add(stmt); - } + void addScriptStmtLine(char const* sourceBegin, char const* sourceEnd) + { + auto stmt = RefPtr(new TextTemplateScriptStmt()); + stmt->scriptSource = UnownedStringSlice(sourceBegin, sourceEnd); + stmts.add(stmt); + } - void addScriptSpliceExpr( - char const* sourceBegin, - char const* sourceEnd) - { - auto stmt = RefPtr(new TextTemplateSpliceStmt()); - stmt->scriptExprSource = UnownedStringSlice(sourceBegin, sourceEnd); - stmts.add(stmt); - } + void addScriptSpliceExpr(char const* sourceBegin, char const* sourceEnd) + { + auto stmt = RefPtr(new TextTemplateSpliceStmt()); + stmt->scriptExprSource = UnownedStringSlice(sourceBegin, sourceEnd); + stmts.add(stmt); + } - bool isIdentifierStartChar(int c) - { - return (('a' <= c) && (c <= 'z')) - || (('A' <= c) && (c <= 'Z')) - || (c == '_'); - } + bool isIdentifierStartChar(int c) + { + return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || (c == '_'); + } - bool isIdentifierChar(int c) - { - return isIdentifierStartChar(c) - || (('0' <= c) && (c <= '9')); - } + bool isIdentifierChar(int c) { return isIdentifierStartChar(c) || (('0' <= c) && (c <= '9')); } - RefPtr parseTextTemplateBody() + RefPtr parseTextTemplateBody() + { + bool isAtStartOfLine = true; + bool isInScriptLine = false; + int depthInSplice = 0; + + char const* currentLineBegin = _cursor; + char const* currentSpanBegin = _cursor; + while (!atEnd()) { - bool isAtStartOfLine = true; - bool isInScriptLine = false; - int depthInSplice = 0; + char const* currentSpanEnd = _cursor; - char const* currentLineBegin = _cursor; - char const* currentSpanBegin = _cursor; - while (!atEnd()) - { - char const* currentSpanEnd = _cursor; + bool wasAtStartOfLine = isAtStartOfLine; + isAtStartOfLine = false; - bool wasAtStartOfLine = isAtStartOfLine; - isAtStartOfLine = false; + int c = *_cursor++; + switch (c) + { + default: + break; - int c = *_cursor++; - switch (c) + case '\r': + if (*_cursor == '\n') { - default: - break; + _cursor++; + } + case '\n': + isAtStartOfLine = true; + currentLineBegin = _cursor; + if (isInScriptLine) + { + addScriptStmtLine(currentSpanBegin, currentSpanEnd); + isInScriptLine = false; + currentSpanBegin = currentSpanEnd; + } + break; - case '\r': - if (*_cursor == '\n') - { - _cursor++; - } - case '\n': - isAtStartOfLine = true; - currentLineBegin = _cursor; - if (isInScriptLine) - { - addScriptStmtLine(currentSpanBegin, currentSpanEnd); - isInScriptLine = false; - currentSpanBegin = currentSpanEnd; - } - break; + case ' ': + case '\t': + isAtStartOfLine = wasAtStartOfLine; + break; - case ' ': case '\t': - isAtStartOfLine = wasAtStartOfLine; - break; + case '%': + if (wasAtStartOfLine && !depthInSplice) + { + addRaw(currentSpanBegin, currentLineBegin); + isInScriptLine = true; + currentSpanBegin = _cursor; + } + break; - case '%': - if (wasAtStartOfLine && !depthInSplice) - { - addRaw(currentSpanBegin, currentLineBegin); - isInScriptLine = true; - currentSpanBegin = _cursor; - } - break; + case '$': + if (isInScriptLine) + continue; + if (depthInSplice) + throw 99; - case '$': - if (isInScriptLine) - continue; - if (depthInSplice) - throw 99; + if (*_cursor == '(') + { + _cursor++; + addRaw(currentSpanBegin, currentSpanEnd); + depthInSplice = 1; + currentSpanBegin = _cursor; + break; + } + else if (isIdentifierStartChar(*_cursor)) + { + addRaw(currentSpanBegin, currentSpanEnd); - if (*_cursor == '(') - { + auto spliceExprBegin = _cursor; + while (isIdentifierChar(*_cursor)) _cursor++; - addRaw(currentSpanBegin, currentSpanEnd); - depthInSplice = 1; - currentSpanBegin = _cursor; - break; - } - else if (isIdentifierStartChar(*_cursor)) - { - addRaw(currentSpanBegin, currentSpanEnd); - - auto spliceExprBegin = _cursor; - while (isIdentifierChar(*_cursor)) - _cursor++; - auto spliceExprEnd = _cursor; - addScriptSpliceExpr(spliceExprBegin, spliceExprEnd); - currentSpanBegin = _cursor; - break; - } + auto spliceExprEnd = _cursor; + addScriptSpliceExpr(spliceExprBegin, spliceExprEnd); + currentSpanBegin = _cursor; break; + } + break; - case '(': - if (!depthInSplice) - continue; - depthInSplice++; - break; + case '(': + if (!depthInSplice) + continue; + depthInSplice++; + break; - case ')': - if (!depthInSplice) - continue; - depthInSplice--; - if (depthInSplice == 0) - { - addScriptSpliceExpr(currentSpanBegin, currentSpanEnd); - currentSpanBegin = _cursor; - } - break; + case ')': + if (!depthInSplice) + continue; + depthInSplice--; + if (depthInSplice == 0) + { + addScriptSpliceExpr(currentSpanBegin, currentSpanEnd); + currentSpanBegin = _cursor; } - } - addRaw(currentSpanBegin, _end); - - if (stmts.getCount() == 1) - return stmts[0]; - else - { - auto stmt = RefPtr(new TextTemplateSeqStmt()); - stmt->stmts = stmts; - return stmt; + break; } } + addRaw(currentSpanBegin, _end); - private: + if (stmts.getCount() == 1) + return stmts[0]; + else + { + auto stmt = RefPtr(new TextTemplateSeqStmt()); + stmt->stmts = stmts; + return stmt; + } + } - }; +private: +}; +char const* templateStartMarker = "FIDDLE TEMPLATE"; +char const* outputStartMarker = "FIDDLE OUTPUT"; +char const* endMarker = "FIDDLE END"; - char const* templateStartMarker = "FIDDLE TEMPLATE"; - char const* outputStartMarker = "FIDDLE OUTPUT"; - char const* endMarker = "FIDDLE END"; +struct TextTemplateFileParser : TextTemplateParserBase +{ +public: + TextTemplateFileParser(SourceView* inputSourceView, DiagnosticSink* sink) + : TextTemplateParserBase(inputSourceView, sink, inputSourceView->getContent()) + { + } - struct TextTemplateFileParser : TextTemplateParserBase + RefPtr parseTextTemplateFile() { - public: - TextTemplateFileParser( - SourceView* inputSourceView, - DiagnosticSink* sink) - : TextTemplateParserBase(inputSourceView, sink, inputSourceView->getContent()) - {} - - RefPtr parseTextTemplateFile() + auto textTemplateFile = RefPtr(new TextTemplateFile()); + textTemplateFile->originalFileContent = _inputSourceView->getContent(); + while (!atEnd()) { - auto textTemplateFile = RefPtr(new TextTemplateFile()); - textTemplateFile->originalFileContent = _inputSourceView->getContent(); - while (!atEnd()) - { - auto textTemplate = parseOptionalTextTemplate(); - if (textTemplate) - textTemplateFile->textTemplates.add(textTemplate); - } - return textTemplateFile; + auto textTemplate = parseOptionalTextTemplate(); + if (textTemplate) + textTemplateFile->textTemplates.add(textTemplate); } + return textTemplateFile; + } - private: - Count _templateCounter = 0; +private: + Count _templateCounter = 0; - bool matches(UnownedStringSlice const& line, char const* marker) - { - auto index = line.indexOf(UnownedTerminatedStringSlice(marker)); - return index >= 0; - } + bool matches(UnownedStringSlice const& line, char const* marker) + { + auto index = line.indexOf(UnownedTerminatedStringSlice(marker)); + return index >= 0; + } - bool findMatchingLine( - char const* marker, - UnownedStringSlice& outMatchingLine) + bool findMatchingLine(char const* marker, UnownedStringSlice& outMatchingLine) + { + while (!atEnd()) { - while (!atEnd()) + auto line = readLine(); + if (!matches(line, marker)) { - auto line = readLine(); - if (!matches(line, marker)) - { - // TODO: If the line doesn't match the expected marker, - // but it *does* match one of the other markers, then - // we should consider it a probable error. - - continue; - } + // TODO: If the line doesn't match the expected marker, + // but it *does* match one of the other markers, then + // we should consider it a probable error. - outMatchingLine = line; - return true; + continue; } - return false; - } - SourceLoc getLoc(char const* ptr) - { - auto offset = ptr - _inputSourceView->getContent().begin(); - auto startLoc = _inputSourceView->getRange().begin; - auto loc = SourceLoc::fromRaw(startLoc.getRaw() + offset); - return loc; + outMatchingLine = line; + return true; } + return false; + } - SourceLoc getLoc(UnownedStringSlice text) - { - return getLoc(text.begin()); - } + SourceLoc getLoc(char const* ptr) + { + auto offset = ptr - _inputSourceView->getContent().begin(); + auto startLoc = _inputSourceView->getRange().begin; + auto loc = SourceLoc::fromRaw(startLoc.getRaw() + offset); + return loc; + } - RefPtr parseTextTemplateBody( - UnownedStringSlice const& source) - { - TextTemplateParser parser(_inputSourceView, _sink, source); - return parser.parseTextTemplateBody(); - } + SourceLoc getLoc(UnownedStringSlice text) { return getLoc(text.begin()); } - RefPtr parseOptionalTextTemplate() - { - // The idea is pretty simple; we scan through the source, one line at - // a time, until we find a line that matches our template start pattern. - // - // If we *don't* find the start marker, then there must not be any - // templates left. - // - UnownedStringSlice templateStartLine; - if (!findMatchingLine(templateStartMarker, templateStartLine)) - return nullptr; + RefPtr parseTextTemplateBody(UnownedStringSlice const& source) + { + TextTemplateParser parser(_inputSourceView, _sink, source); + return parser.parseTextTemplateBody(); + } - char const* templateSourceBegin = _cursor; + RefPtr parseOptionalTextTemplate() + { + // The idea is pretty simple; we scan through the source, one line at + // a time, until we find a line that matches our template start pattern. + // + // If we *don't* find the start marker, then there must not be any + // templates left. + // + UnownedStringSlice templateStartLine; + if (!findMatchingLine(templateStartMarker, templateStartLine)) + return nullptr; - // If we *do* find a start line for a template, then we will expect - // to find the other two kinds of lines, to round things out. + char const* templateSourceBegin = _cursor; - UnownedStringSlice outputStartLine; - if (!findMatchingLine(outputStartMarker, outputStartLine)) - { - // TODO: need to diagnose a problem here... - _sink->diagnose(getLoc(templateStartLine), fiddle::Diagnostics::expectedOutputStartMarker, outputStartMarker); - } + // If we *do* find a start line for a template, then we will expect + // to find the other two kinds of lines, to round things out. - char const* templateSourceEnd = outputStartLine.begin(); + UnownedStringSlice outputStartLine; + if (!findMatchingLine(outputStartMarker, outputStartLine)) + { + // TODO: need to diagnose a problem here... + _sink->diagnose( + getLoc(templateStartLine), + fiddle::Diagnostics::expectedOutputStartMarker, + outputStartMarker); + } - char const* existingOutputBegin = _cursor; + char const* templateSourceEnd = outputStartLine.begin(); - UnownedStringSlice endLine; - if (!findMatchingLine(endMarker, endLine)) - { - // TODO: need to diagnose a problem here... - _sink->diagnose(getLoc(templateStartLine), fiddle::Diagnostics::expectedEndMarker, endMarker); - } - char const* existingOutputEnd = endLine.begin(); - - auto templateSource = UnownedStringSlice(templateSourceBegin, templateSourceEnd); - auto templateBody = parseTextTemplateBody(templateSource); - - auto textTemplate = RefPtr(new TextTemplate()); - textTemplate->id = _templateCounter++; - textTemplate->templateStartLine = templateStartLine; - textTemplate->templateSource = templateSource; - textTemplate->body = templateBody; - textTemplate->outputStartLine = outputStartLine; - textTemplate->existingOutputContent = UnownedStringSlice(existingOutputBegin, existingOutputEnd); - textTemplate->endLine = endLine; - return textTemplate; + char const* existingOutputBegin = _cursor; + + UnownedStringSlice endLine; + if (!findMatchingLine(endMarker, endLine)) + { + // TODO: need to diagnose a problem here... + _sink->diagnose( + getLoc(templateStartLine), + fiddle::Diagnostics::expectedEndMarker, + endMarker); } - }; + char const* existingOutputEnd = endLine.begin(); + + auto templateSource = UnownedStringSlice(templateSourceBegin, templateSourceEnd); + auto templateBody = parseTextTemplateBody(templateSource); + + auto textTemplate = RefPtr(new TextTemplate()); + textTemplate->id = _templateCounter++; + textTemplate->templateStartLine = templateStartLine; + textTemplate->templateSource = templateSource; + textTemplate->body = templateBody; + textTemplate->outputStartLine = outputStartLine; + textTemplate->existingOutputContent = + UnownedStringSlice(existingOutputBegin, existingOutputEnd); + textTemplate->endLine = endLine; + return textTemplate; + } +}; - struct TextTemplateScriptCodeEmitter +struct TextTemplateScriptCodeEmitter +{ +public: + TextTemplateScriptCodeEmitter(TextTemplateFile* templateFile) + : _templateFile(templateFile) { - public: - TextTemplateScriptCodeEmitter(TextTemplateFile* templateFile) - : _templateFile(templateFile) - {} + } - String emitScriptCodeForTextTemplateFile() - { - // We start by emitting the content of the template - // file out as Lua code, so that we can evaluate - // it all using the Lua VM. - // - // We go to some effort to make sure that the line - // numbers in the generated Lua will match those - // in the input. - // - - char const* originalFileRawSpanStart = _templateFile->originalFileContent.begin(); - for (auto t : _templateFile->textTemplates) - { - flushOriginalFileRawSpan( - originalFileRawSpanStart, - t->templateSource.begin()); + String emitScriptCodeForTextTemplateFile() + { + // We start by emitting the content of the template + // file out as Lua code, so that we can evaluate + // it all using the Lua VM. + // + // We go to some effort to make sure that the line + // numbers in the generated Lua will match those + // in the input. + // - evaluateTextTemplate(t); + char const* originalFileRawSpanStart = _templateFile->originalFileContent.begin(); + for (auto t : _templateFile->textTemplates) + { + flushOriginalFileRawSpan(originalFileRawSpanStart, t->templateSource.begin()); - originalFileRawSpanStart = t->outputStartLine.begin(); - } - flushOriginalFileRawSpan( - originalFileRawSpanStart, - _templateFile->originalFileContent.end()); + evaluateTextTemplate(t); - return _builder.produceString(); + originalFileRawSpanStart = t->outputStartLine.begin(); } + flushOriginalFileRawSpan( + originalFileRawSpanStart, + _templateFile->originalFileContent.end()); - private: - TextTemplateFile* _templateFile = nullptr; - StringBuilder _builder; + return _builder.produceString(); + } - void flushOriginalFileRawSpan( - char const* begin, - char const* end) - { - if (begin == end) - return; +private: + TextTemplateFile* _templateFile = nullptr; + StringBuilder _builder; - // TODO: implement the important stuff... - _builder.append("ORIGINAL [==["); - _builder.append(UnownedStringSlice(begin, end)); + void flushOriginalFileRawSpan(char const* begin, char const* end) + { + if (begin == end) + return; + + // TODO: implement the important stuff... + _builder.append("ORIGINAL [==["); + _builder.append(UnownedStringSlice(begin, end)); + _builder.append("]==]"); + } + + void evaluateTextTemplate(TextTemplate* textTemplate) + { + // TODO: there really needs to be some framing around this... + _builder.append("TEMPLATE(function() "); + evaluateTextTemplateStmt(textTemplate->body); + _builder.append(" end)"); + } + + void evaluateTextTemplateStmt(TextTemplateStmt* stmt) + { + if (auto seqStmt = as(stmt)) + { + for (auto s : seqStmt->stmts) + evaluateTextTemplateStmt(s); + } + else if (auto rawStmt = as(stmt)) + { + _builder.append("RAW [==["); + _builder.append(rawStmt->text); _builder.append("]==]"); } - - void evaluateTextTemplate(TextTemplate* textTemplate) + else if (auto scriptStmt = as(stmt)) { - // TODO: there really needs to be some framing around this... - _builder.append("TEMPLATE(function() "); - evaluateTextTemplateStmt(textTemplate->body); - _builder.append(" end)"); + _builder.append(scriptStmt->scriptSource); + _builder.append(" "); } - - void evaluateTextTemplateStmt(TextTemplateStmt* stmt) + else if (auto spliceStmt = as(stmt)) { - if (auto seqStmt = as(stmt)) - { - for (auto s : seqStmt->stmts) - evaluateTextTemplateStmt(s); - } - else if (auto rawStmt = as(stmt)) - { - _builder.append("RAW [==["); - _builder.append(rawStmt->text); - _builder.append("]==]"); - } - else if (auto scriptStmt = as(stmt)) - { - _builder.append(scriptStmt->scriptSource); - _builder.append(" "); - } - else if (auto spliceStmt = as(stmt)) - { - _builder.append("SPLICE(function()return("); - _builder.append(spliceStmt->scriptExprSource); - _builder.append(")end)"); - } - else - { - throw 99; - } + _builder.append("SPLICE(function()return("); + _builder.append(spliceStmt->scriptExprSource); + _builder.append(")end)"); } - }; + else + { + throw 99; + } + } +}; - RefPtr parseTextTemplateFile( - SourceView* inputSourceView, - DiagnosticSink* sink) - { - TextTemplateFileParser parser(inputSourceView, sink); - return parser.parseTextTemplateFile(); - } +RefPtr parseTextTemplateFile(SourceView* inputSourceView, DiagnosticSink* sink) +{ + TextTemplateFileParser parser(inputSourceView, sink); + return parser.parseTextTemplateFile(); +} - void generateTextTemplateOutputs( - String originalFileName, - TextTemplateFile* file, - StringBuilder& builder, - DiagnosticSink* sink) - { - TextTemplateScriptCodeEmitter emitter(file); - String scriptCode = emitter.emitScriptCodeForTextTemplateFile(); +void generateTextTemplateOutputs( + String originalFileName, + TextTemplateFile* file, + StringBuilder& builder, + DiagnosticSink* sink) +{ + TextTemplateScriptCodeEmitter emitter(file); + String scriptCode = emitter.emitScriptCodeForTextTemplateFile(); - String output = evaluateScriptCode( - originalFileName, - scriptCode, - sink); + String output = evaluateScriptCode(originalFileName, scriptCode, sink); - builder.append(output); - builder.append("\n"); - } + builder.append(output); + builder.append("\n"); +} - String generateModifiedInputFileForTextTemplates( - String templateOutputFileName, - TextTemplateFile* file, - DiagnosticSink* sink) - { - // The basic idea here is that we need to emit most of - // the body of the file exactly as it originally - // appeared, and then only modifify the few lines - // that represent the text template output. - // - // TODO(tfoley): We could also use this as an opportunity - // to insert the `FIDDLE(...)` markers that the scraping - // tool needs, but that is more work than makes sense - // right now. +String generateModifiedInputFileForTextTemplates( + String templateOutputFileName, + TextTemplateFile* file, + DiagnosticSink* sink) +{ + // The basic idea here is that we need to emit most of + // the body of the file exactly as it originally + // appeared, and then only modifify the few lines + // that represent the text template output. + // + // TODO(tfoley): We could also use this as an opportunity + // to insert the `FIDDLE(...)` markers that the scraping + // tool needs, but that is more work than makes sense + // right now. - StringBuilder builder; + StringBuilder builder; - char const* originalFileRawSpanStart = file->originalFileContent.begin(); - for (auto t : file->textTemplates) + char const* originalFileRawSpanStart = file->originalFileContent.begin(); + for (auto t : file->textTemplates) + { + builder.append( + UnownedStringSlice(originalFileRawSpanStart, t->existingOutputContent.begin())); + + builder.append("#define FIDDLE_GENERATED_OUTPUT_ID "); + builder.append(t->id); + builder.append("\n"); + builder.append("#include \""); + for (auto c : templateOutputFileName) { - builder.append(UnownedStringSlice( - originalFileRawSpanStart, - t->existingOutputContent.begin())); - - builder.append("#define FIDDLE_GENERATED_OUTPUT_ID "); - builder.append(t->id); - builder.append("\n"); - builder.append("#include \""); - for (auto c : templateOutputFileName) + switch (c) { - switch (c) - { - case '"': - case '\\': - builder.appendChar('\\'); - builder.appendChar(c); - break; - - default: - builder.appendChar(c); - break; - } - + case '"': + case '\\': + builder.appendChar('\\'); + builder.appendChar(c); + break; + + default: + builder.appendChar(c); + break; } - builder.append("\"\n"); - originalFileRawSpanStart = t->existingOutputContent.end(); } - builder.append(UnownedStringSlice( - originalFileRawSpanStart, - file->originalFileContent.end())); - - return builder.produceString(); + builder.append("\"\n"); + originalFileRawSpanStart = t->existingOutputContent.end(); } + builder.append(UnownedStringSlice(originalFileRawSpanStart, file->originalFileContent.end())); + return builder.produceString(); } + +} // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-template.h b/tools/slang-fiddle/slang-fiddle-template.h index 0a0e3a26828..51798c902a5 100644 --- a/tools/slang-fiddle/slang-fiddle-template.h +++ b/tools/slang-fiddle/slang-fiddle-template.h @@ -1,84 +1,81 @@ // slang-fiddle-template.h #pragma once -#include "slang-fiddle-diagnostics.h" - -#include "core/slang-string.h" -#include "core/slang-list.h" #include "compiler-core/slang-source-loc.h" +#include "core/slang-list.h" +#include "core/slang-string.h" +#include "slang-fiddle-diagnostics.h" namespace fiddle { - using namespace Slang; - - class TextTemplateStmt : public RefObject - { - public: - }; - - class TextTemplateScriptStmt : public TextTemplateStmt - { - public: - UnownedStringSlice scriptSource; - }; - - class TextTemplateRawStmt : public TextTemplateStmt - { - public: - // TODO(tfoley): Add a `SourceLoc` here, so - // that we can emit approriate `#line` directives - // to the output... - - UnownedStringSlice text; - }; - - class TextTemplateSpliceStmt : public TextTemplateStmt - { - public: - UnownedStringSlice scriptExprSource; - }; - - class TextTemplateSeqStmt : public TextTemplateStmt - { - public: - List> stmts; - }; - - class TextTemplate : public RefObject - { - public: - /// ID of this template within the enclosing file - Index id; - - UnownedStringSlice templateStartLine; - UnownedStringSlice outputStartLine; - UnownedStringSlice endLine; - - UnownedStringSlice templateSource; - UnownedStringSlice existingOutputContent; - - RefPtr body; - }; - - class TextTemplateFile : public RefObject - { - public: - UnownedStringSlice originalFileContent; - List> textTemplates; - }; - - RefPtr parseTextTemplateFile( - SourceView* inputSourceView, - DiagnosticSink* sink); - - void generateTextTemplateOutputs( - String originalFileName, - TextTemplateFile* file, - StringBuilder& builder, - DiagnosticSink* sink); - - String generateModifiedInputFileForTextTemplates( - String templateOutputFileName, - TextTemplateFile* file, - DiagnosticSink* sink); -} +using namespace Slang; + +class TextTemplateStmt : public RefObject +{ +public: +}; + +class TextTemplateScriptStmt : public TextTemplateStmt +{ +public: + UnownedStringSlice scriptSource; +}; + +class TextTemplateRawStmt : public TextTemplateStmt +{ +public: + // TODO(tfoley): Add a `SourceLoc` here, so + // that we can emit approriate `#line` directives + // to the output... + + UnownedStringSlice text; +}; + +class TextTemplateSpliceStmt : public TextTemplateStmt +{ +public: + UnownedStringSlice scriptExprSource; +}; + +class TextTemplateSeqStmt : public TextTemplateStmt +{ +public: + List> stmts; +}; + +class TextTemplate : public RefObject +{ +public: + /// ID of this template within the enclosing file + Index id; + + UnownedStringSlice templateStartLine; + UnownedStringSlice outputStartLine; + UnownedStringSlice endLine; + + UnownedStringSlice templateSource; + UnownedStringSlice existingOutputContent; + + RefPtr body; +}; + +class TextTemplateFile : public RefObject +{ +public: + UnownedStringSlice originalFileContent; + List> textTemplates; +}; + +RefPtr parseTextTemplateFile(SourceView* inputSourceView, DiagnosticSink* sink); + +void generateTextTemplateOutputs( + String originalFileName, + TextTemplateFile* file, + StringBuilder& builder, + DiagnosticSink* sink); + +String generateModifiedInputFileForTextTemplates( + String templateOutputFileName, + TextTemplateFile* file, + DiagnosticSink* sink); +} // namespace fiddle