Glob pattern matcher (#122)
This commit is contained in:
119
include/Support/GlobPattern.h
Normal file
119
include/Support/GlobPattern.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
using GlobCharSet = std::bitset<256>;
|
||||
|
||||
/// This class implements a glob pattern matcher to parse patterns to
|
||||
/// watch relative to the base path.
|
||||
///
|
||||
/// Glob patterns can have the following syntax:
|
||||
/// - `*` to match one or more characters in a path segment
|
||||
/// - `?` to match on one character in a path segment
|
||||
/// - `**` to match any number of path segments, including none
|
||||
/// - `{}` to group conditions (e.g. `***.{ts,js}` matches all TypeScript
|
||||
/// and JavaScript files)
|
||||
/// - `[]` to declare a range of characters to match in a path segment
|
||||
/// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
|
||||
/// - `[!...]` to negate a range of characters to match in a path segment
|
||||
/// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`,
|
||||
/// but not `example.0`)
|
||||
///
|
||||
/// Note: Use only `/` for path segment seperator
|
||||
class GlobPattern {
|
||||
public:
|
||||
/// \param Pat the pattern to match against
|
||||
/// \param MaxSubPatterns if provided limit the number of allowed subpatterns
|
||||
/// created from expanding braces otherwise disable
|
||||
/// brace expansion
|
||||
static std::expected<GlobPattern, std::string>
|
||||
create(llvm::StringRef s, std::optional<size_t> max_subpattern_num = {});
|
||||
|
||||
// Returns true for glob pattern "*" or "**". Can be used to avoid expensive
|
||||
// preparation/acquisition of the input for match().
|
||||
bool isTrivialMatchAll() const {
|
||||
if(!prefix.empty()) {
|
||||
// have no prefix
|
||||
return false;
|
||||
}
|
||||
if((sub_globs.size() == 1 && sub_globs[0].getPat() == "*") ||
|
||||
(sub_globs.size() == 2 && sub_globs[0].getPat() == "**")) {
|
||||
// not "*" or "**"
|
||||
return true;
|
||||
}
|
||||
// default return false
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \returns \p true if \p str matches this glob pattern
|
||||
bool match(llvm::StringRef s);
|
||||
|
||||
private:
|
||||
/// GlobPattern is seperated into `Prefix + SubGlobPattern`
|
||||
std::string prefix;
|
||||
|
||||
/// if prefix contains full path:
|
||||
///
|
||||
/// xxx/yyy/*.c
|
||||
/// ~~~~~~^
|
||||
///
|
||||
/// prefix contains incomplete path:
|
||||
/// xxx/yyy*.c
|
||||
/// ~~~~~~^
|
||||
///
|
||||
bool prefix_at_seg_end = false;
|
||||
|
||||
/// SubGlobPattern:
|
||||
/// Pattern `foo.{c,cpp,cppm}`
|
||||
/// -> extend to 3 SubGlobPatterns: `foo.c`, `foo.cpp`, `foo.cppm`
|
||||
struct SubGlobPattern {
|
||||
/// \param Pat the pattern to match against
|
||||
static std::expected<SubGlobPattern, std::string> create(llvm::StringRef s);
|
||||
/// \returns \p true if \p S matches this glob pattern
|
||||
bool match(llvm::StringRef str) const;
|
||||
|
||||
llvm::StringRef getPat() const {
|
||||
return llvm::StringRef{pat.data(), pat.size()};
|
||||
}
|
||||
|
||||
struct Bracket {
|
||||
size_t next_offset;
|
||||
GlobCharSet bytes;
|
||||
};
|
||||
|
||||
llvm::SmallVector<Bracket, 0> brackets;
|
||||
|
||||
// GlobSegment devide patterm into segments by '/'
|
||||
// SubPattern:
|
||||
// **include/aaa/bbb/test[0-9].cc
|
||||
// ^~~~~~~~~^~~~^~~~^~~~~~~~~~~~~^
|
||||
// 1 2 3 4
|
||||
// Devided into 4 segments
|
||||
//
|
||||
// SubPattern:
|
||||
// **/include/aaa/bbb/test[0-9].h
|
||||
// ^~^~~~~~~~^~~~^~~~^~~~~~~~~~~~^
|
||||
// 1 2 3 4 5
|
||||
// Devided into 5 segments
|
||||
struct GlobSegment {
|
||||
size_t start;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
llvm::SmallVector<GlobSegment, 6> glob_segments;
|
||||
|
||||
llvm::SmallVector<char, 0> pat;
|
||||
};
|
||||
|
||||
llvm::SmallVector<SubGlobPattern, 1> sub_globs;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
Reference in New Issue
Block a user