diff --git a/src/sfizz/parser/Parser.cpp b/src/sfizz/parser/Parser.cpp index f54398ac..0442081a 100644 --- a/src/sfizz/parser/Parser.cpp +++ b/src/sfizz/parser/Parser.cpp @@ -33,21 +33,23 @@ void Parser::reset() } void Parser::parseFile(const fs::path& path) +{ + parseVirtualFile(path, nullptr); +} + +void Parser::parseString(const fs::path& path, absl::string_view sfzView) +{ + parseVirtualFile(path, absl::make_unique(path, sfzView)); +} + +void Parser::parseVirtualFile(const fs::path& path, std::unique_ptr reader) { reset(); if (_listener) _listener->onParseBegin(); - if (path.empty()) - return; - - if (path.is_relative()) - setOriginalDirectory(originalDirectory() / path); - else - setOriginalDirectory(path.parent_path()); - - includeNewFile(path); + includeNewFile(path, std::move(reader)); processTopLevel(); flushCurrentHeader(); @@ -55,32 +57,14 @@ void Parser::parseFile(const fs::path& path) _listener->onParseEnd(); } -void Parser::parseString(absl::string_view sfzView) -{ - reset(); - - if (_listener) - _listener->onParseBegin(); - - _included.push_back(absl::make_unique(sfzView)); - processTopLevel(); - flushCurrentHeader(); - - if (_listener) - _listener->onParseEnd(); -} - -void Parser::setOriginalDirectory(const fs::path& originalDirectory) noexcept -{ - _originalDirectory = originalDirectory; -} - -void Parser::includeNewFile(const fs::path& path) +void Parser::includeNewFile(const fs::path& path, std::unique_ptr reader) { fs::path fullPath = (path.empty() || path.is_absolute()) ? path : _originalDirectory / path; - if (_pathsIncluded.find(fullPath.string()) != _pathsIncluded.end()) { + if (_pathsIncluded.empty()) + _originalDirectory = fullPath.parent_path(); + else if (_pathsIncluded.find(fullPath.string()) != _pathsIncluded.end()) { if (_recursiveIncludeGuardEnabled) return; } @@ -92,15 +76,18 @@ void Parser::includeNewFile(const fs::path& path) return; } - auto fileReader = absl::make_unique(fullPath); - if (fileReader->hasError()) { - SourceLocation loc = fileReader->location(); - emitError({ loc, loc }, "Cannot open file for reading: " + fullPath.string()); - return; + if (!reader) { + auto fileReader = absl::make_unique(fullPath); + if (fileReader->hasError()) { + SourceLocation loc = fileReader->location(); + emitError({ loc, loc }, "Cannot open file for reading: " + fullPath.string()); + return; + } + reader = std::move(fileReader); } _pathsIncluded.insert(fullPath.string()); - _included.push_back(std::move(fileReader)); + _included.push_back(std::move(reader)); } void Parser::processTopLevel() diff --git a/src/sfizz/parser/Parser.h b/src/sfizz/parser/Parser.h index 5ab1d75b..56b3d7ca 100644 --- a/src/sfizz/parser/Parser.h +++ b/src/sfizz/parser/Parser.h @@ -29,13 +29,13 @@ public: void addDefinition(absl::string_view id, absl::string_view value); void parseFile(const fs::path& path); - void parseString(absl::string_view sfzView); + void parseString(const fs::path& path, absl::string_view sfzView); + void parseVirtualFile(const fs::path& path, std::unique_ptr reader); void setRecursiveIncludeGuardEnabled(bool en) { _recursiveIncludeGuardEnabled = en; } void setMaximumIncludeDepth(size_t depth) { _maxIncludeDepth = depth; } const fs::path& originalDirectory() const noexcept { return _originalDirectory; } - void setOriginalDirectory(const fs::path& originalDirectory) noexcept; typedef absl::flat_hash_set IncludeFileSet; typedef absl::flat_hash_map DefinitionSet; @@ -63,7 +63,7 @@ public: void setListener(Listener* listener) noexcept { _listener = listener; } private: - void includeNewFile(const fs::path& path); + void includeNewFile(const fs::path& path, std::unique_ptr reader = nullptr); void processTopLevel(); void processDirective(); void processHeader(); diff --git a/src/sfizz/parser/ParserPrivate.cpp b/src/sfizz/parser/ParserPrivate.cpp index 27d1d153..38a99059 100644 --- a/src/sfizz/parser/ParserPrivate.cpp +++ b/src/sfizz/parser/ParserPrivate.cpp @@ -139,10 +139,9 @@ int FileReader::getNextStreamByte() return _fileStream.get(); } -StringViewReader::StringViewReader(absl::string_view sfzView) - : Reader({}), _sfzView(sfzView) +StringViewReader::StringViewReader(const fs::path& filePath, absl::string_view sfzView) + : Reader(filePath), _sfzView(sfzView) { - } int StringViewReader::getNextStreamByte() diff --git a/src/sfizz/parser/ParserPrivate.h b/src/sfizz/parser/ParserPrivate.h index 520f87a6..7e271e26 100644 --- a/src/sfizz/parser/ParserPrivate.h +++ b/src/sfizz/parser/ParserPrivate.h @@ -124,7 +124,7 @@ private: */ class StringViewReader : public Reader { public: - explicit StringViewReader(absl::string_view sfzView); + explicit StringViewReader(const fs::path& filePath, absl::string_view sfzView); protected: int getNextStreamByte() override; diff --git a/tests/DemoParser.cpp b/tests/DemoParser.cpp index 42893a76..278cb353 100644 --- a/tests/DemoParser.cpp +++ b/tests/DemoParser.cpp @@ -2,7 +2,6 @@ #include "parser/Parser.h" #include #include -#include #include #include #include @@ -114,14 +113,8 @@ void Application::requestParseCheck() void Application::runParseCheck() { QByteArray code = _ui.sfzEdit->toPlainText().toLatin1(); - - QTemporaryFile temp(QDir::tempPath() + "/parseXXXXXX.sfz"); - temp.open(); - temp.write(code); - temp.flush(); - _blockTextChanged = true; - _parser.parseFile(temp.fileName().toStdString()); + _parser.parseString("/virtual.sfz", absl::string_view(code.data(), code.size())); _blockTextChanged = false; } diff --git a/tests/ParsingT.cpp b/tests/ParsingT.cpp index 968f1e57..5d35a1a9 100644 --- a/tests/ParsingT.cpp +++ b/tests/ParsingT.cpp @@ -179,7 +179,7 @@ TEST_CASE("[Parsing] Empty") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(""); + parser.parseString("/empty.sfz", ""); REQUIRE(mock.beginnings == 1); REQUIRE(mock.endings == 1); REQUIRE(mock.errors.empty()); @@ -201,7 +201,7 @@ TEST_CASE("[Parsing] Empty2") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(emptySfz); + parser.parseString("/empty2.sfz", emptySfz); REQUIRE(mock.beginnings == 1); REQUIRE(mock.endings == 1); REQUIRE(mock.errors.empty()); @@ -224,7 +224,7 @@ TEST_CASE("[Parsing] Jpcima good region") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(R"( + parser.parseString("/goodRegion.sfz", R"( sample=*silence key=69 sample=My Directory/My Wave.wav // path with spaces and a comment sample=My Directory/My Wave.wav key=69 // path with spaces, and other opcode following @@ -256,7 +256,7 @@ void memberTestNew(absl::string_view member, absl::string_view opcode, absl::str sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(absl::StrCat(" ", member)); + parser.parseString("/memberTestNew.sfz", absl::StrCat(" ", member)); REQUIRE(mock.opcodes.size() == 1); REQUIRE(mock.headers.size() == 1); REQUIRE(mock.fullBlockHeaders.size() == 1); @@ -296,7 +296,7 @@ TEST_CASE("[Parsing] bad headers") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString( + parser.parseString("/badHeaders.sfz", R"(<> dummy_member=no )" @@ -317,7 +317,7 @@ void defineTestNew(const std::string& directive, const std::string& variable, co sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(directive); + parser.parseString("/defineTestNew.sfz", directive); const auto defines = parser.getDefines(); REQUIRE(defines.contains(variable)); REQUIRE(defines.at(variable) == value); @@ -342,7 +342,8 @@ TEST_CASE("[Parsing] Malformed includes") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString(R"(#include "MyFileWhichDoesNotExist1.sfz + parser.parseString("/malformedIncludes.sfz", +R"(#include "MyFileWhichDoesNotExist1.sfz #include MyFileWhichDoesNotExist1.sfz)"); REQUIRE(mock.errors.size() == 2); REQUIRE(mock.errors[0].start.lineNumber == 0); @@ -362,7 +363,7 @@ TEST_CASE("[Parsing] Headers (new parser)") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString("
param1=value1 param2=value2 "); + parser.parseString("/headers.sfz", "
param1=value1 param2=value2 "); std::vector> expectedMembers = { {{"param1", "value1"}, {"param2", "value2"}}, {} @@ -391,7 +392,7 @@ TEST_CASE("[Parsing] Headers (new parser)") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseString("
param1=value1 param2=value2"); + parser.parseString("/eolHeaderMatch.sfz", "
param1=value1 param2=value2"); std::vector> expectedMembers = { {{"param1", "value1"}, {"param2", "value2"}} };