From 4aaccf667c8ba422dbd5a8242a9a5449bc5b4290 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 22 Oct 2025 12:21:37 -0700 Subject: [PATCH 1/4] works --- src/support/string.cpp | 62 +++++++++++++++++++++++++++++----- test/lit/passes/no-inline.wast | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/src/support/string.cpp b/src/support/string.cpp index f8f06a71804..007a3409ca0 100644 --- a/src/support/string.cpp +++ b/src/support/string.cpp @@ -82,21 +82,67 @@ Split handleBracketingOperators(Split split) { return ret; } -bool wildcardMatch(const std::string& pattern, const std::string& value) { - for (size_t i = 0; i < pattern.size(); i++) { +bool wildcardMatch(const std::string& initialPattern, const std::string& initialValue) { + struct Task { + const std::string pattern;// TODO stirng_view + const std::string value; + size_t i; + bool continuation; + }; + std::vector tasks; + std::vector results; + tasks.push_back({initialPattern, initialValue, 0, false}); + while (!tasks.empty()) { + auto task = tasks.back(); + tasks.pop_back(); + auto& [pattern, value, i, continuation] = task; +#if 1 + std::cout << "pat: " << pattern << '\n'; + std::cout << "val: " << value << '\n'; + for (size_t a = 0; a < i + 5; a++) std::cout << ' '; + std::cout << "^\n"; + std::cout << "cont: " << continuation << "\n"; +#endif + if (continuation) { + // See below: We pushed two tasks, and must check if either matched. + auto num = results.size(); + assert(num >= 2); + auto result = results[num - 1] || results[num - 2]; + results.resize(num - 2); + results.push_back(result); + continue; + } + if (i == pattern.size()) { + // We reached the end. + results.push_back(value.size() == pattern.size()); + continue; + } if (pattern[i] == '*') { - return wildcardMatch(pattern.substr(i + 1), value.substr(i)) || - (value.size() > 0 && - wildcardMatch(pattern.substr(i), value.substr(i + 1))); + if (i >= value.size()) { + // A lone wildcard matches the empty string. + results.push_back(pattern.size() == (i + 1)); + continue; + } + // Push a continuation of us, and then the child tasks. We need one of the + // child tasks to be true for us to match. + tasks.push_back({pattern, value, i, true}); + tasks.push_back({pattern.substr(i + 1), value.substr(i), 0, false}); + tasks.push_back({pattern.substr(i), value.substr(i + 1), 0, false}); + continue; } if (i >= value.size()) { - return false; + results.push_back(false); + continue; } if (pattern[i] != value[i]) { - return false; + results.push_back(false); + continue; } + tasks.push_back({pattern, value, i + 1, false}); } - return value.size() == pattern.size(); + assert(results.size() == 1); +//std::cout << initialPattern << " vs " << initialValue << " => " << results[0] << '\n'; + return results[0]; } std::string trim(const std::string& input) { diff --git a/test/lit/passes/no-inline.wast b/test/lit/passes/no-inline.wast index 2e21105cb41..18a793a0728 100644 --- a/test/lit/passes/no-inline.wast +++ b/test/lit/passes/no-inline.wast @@ -638,6 +638,26 @@ ) ) + (func $very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; Test a long name. + ) + + ;; NO_FULL: (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_FULL-NEXT: ) + ;; NO_BOTH: (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: ) + (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; Test a long name with "maybe" in it. + ) + + ;; NO_FULL: (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_FULL-NEXT: ) + ;; NO_BOTH: (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: ) + (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; Test a long name with "maybe" in it, and a partial match earlier ("may"). + ) + ;; YES_ALL: (func $caller ;; YES_ALL-NEXT: (local $0 i32) ;; YES_ALL-NEXT: (local $1 i32) @@ -741,6 +761,18 @@ ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long$4 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long$5 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long$6 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) ;; NO_PART: (func $caller ;; NO_PART-NEXT: (call $maybe-partial-or-full-1 @@ -755,6 +787,18 @@ ;; NO_PART-NEXT: (call $maybe-partial-or-full-2 ;; NO_PART-NEXT: (i32.const 1) ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long$1 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long$2 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) ;; NO_PART-NEXT: ) ;; NO_FULL: (func $caller ;; NO_FULL-NEXT: (local $0 i32) @@ -817,6 +861,12 @@ ;; NO_FULL-NEXT: ) ;; NO_FULL-NEXT: ) ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long$4 + ;; NO_FULL-NEXT: (block + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_FULL-NEXT: (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) ;; NO_FULL-NEXT: ) ;; NO_BOTH: (func $caller ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-1 @@ -831,6 +881,12 @@ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-2 ;; NO_BOTH-NEXT: (i32.const 1) ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: (block + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_BOTH-NEXT: (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) ;; NO_BOTH-NEXT: ) (func $caller ;; In YES_ALL we will fully inline all of these. In NO_FULL we will partially @@ -851,6 +907,9 @@ (call $maybe-partial-or-full-2 (i32.const 1) ) + (call $very-long-name-we-should-not-error-on-even-though-it-is-very-very-long) + (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) ) ) ;; NO_FULL: (func $byn-split-outlined-B$maybe-partial-or-full-1 (param $x i32) From cce59478adc89d58f8d827df5f30ade86260e7dc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 22 Oct 2025 12:22:43 -0700 Subject: [PATCH 2/4] niceer --- src/support/string.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/support/string.cpp b/src/support/string.cpp index 007a3409ca0..4cb673f54f9 100644 --- a/src/support/string.cpp +++ b/src/support/string.cpp @@ -84,8 +84,8 @@ Split handleBracketingOperators(Split split) { bool wildcardMatch(const std::string& initialPattern, const std::string& initialValue) { struct Task { - const std::string pattern;// TODO stirng_view - const std::string value; + std::string_view pattern; + std::string_view value; size_t i; bool continuation; }; @@ -96,13 +96,6 @@ bool wildcardMatch(const std::string& initialPattern, const std::string& initial auto task = tasks.back(); tasks.pop_back(); auto& [pattern, value, i, continuation] = task; -#if 1 - std::cout << "pat: " << pattern << '\n'; - std::cout << "val: " << value << '\n'; - for (size_t a = 0; a < i + 5; a++) std::cout << ' '; - std::cout << "^\n"; - std::cout << "cont: " << continuation << "\n"; -#endif if (continuation) { // See below: We pushed two tasks, and must check if either matched. auto num = results.size(); @@ -141,7 +134,6 @@ bool wildcardMatch(const std::string& initialPattern, const std::string& initial tasks.push_back({pattern, value, i + 1, false}); } assert(results.size() == 1); -//std::cout << initialPattern << " vs " << initialValue << " => " << results[0] << '\n'; return results[0]; } From b206d499c74edcbb3d8b39fb0c831f6c4d25e412 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 22 Oct 2025 12:22:49 -0700 Subject: [PATCH 3/4] form --- src/support/string.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/support/string.cpp b/src/support/string.cpp index 4cb673f54f9..f6ee7f37ebe 100644 --- a/src/support/string.cpp +++ b/src/support/string.cpp @@ -82,7 +82,8 @@ Split handleBracketingOperators(Split split) { return ret; } -bool wildcardMatch(const std::string& initialPattern, const std::string& initialValue) { +bool wildcardMatch(const std::string& initialPattern, + const std::string& initialValue) { struct Task { std::string_view pattern; std::string_view value; From 6d67ec3882616944fb9921f40292a50171436729 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 22 Oct 2025 12:28:04 -0700 Subject: [PATCH 4/4] notes --- src/support/string.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/support/string.cpp b/src/support/string.cpp index f6ee7f37ebe..28fa985d5a1 100644 --- a/src/support/string.cpp +++ b/src/support/string.cpp @@ -84,14 +84,17 @@ Split handleBracketingOperators(Split split) { bool wildcardMatch(const std::string& initialPattern, const std::string& initialValue) { + // Avoid recursion, as strings can be very long. struct Task { std::string_view pattern; std::string_view value; size_t i; + // Whether we continue a task waiting on results of subtasks (see below). bool continuation; }; std::vector tasks; std::vector results; + // We start with the initial data. tasks.push_back({initialPattern, initialValue, 0, false}); while (!tasks.empty()) { auto task = tasks.back(); @@ -117,21 +120,28 @@ bool wildcardMatch(const std::string& initialPattern, results.push_back(pattern.size() == (i + 1)); continue; } - // Push a continuation of us, and then the child tasks. We need one of the + // Push a continuation of us, and then two child tasks. We need one of the // child tasks to be true for us to match. tasks.push_back({pattern, value, i, true}); + // This child task matches if we can skip the '*' (we find what we want + // right after). tasks.push_back({pattern.substr(i + 1), value.substr(i), 0, false}); + // This child task matches if we can skip a character in the value (the + // '*' matches something arbitary, and later we find what we want). tasks.push_back({pattern.substr(i), value.substr(i + 1), 0, false}); continue; } if (i >= value.size()) { + // We reached the end, and sizes do not match. results.push_back(false); continue; } if (pattern[i] != value[i]) { + // The data does not match. results.push_back(false); continue; } + // Proceed onwards. tasks.push_back({pattern, value, i + 1, false}); } assert(results.size() == 1);