TextMateLib 1.0
Modern C++ implementation of the TextMate syntax highlighting engine
Loading...
Searching...
No Matches
matcher.h
1#ifndef TEXTMATELIB_MATCHER_H
2#define TEXTMATELIB_MATCHER_H
3
4#include "types.h"
5#include <string>
6#include <vector>
7#include <functional>
8
9namespace tml {
10
11// Matcher function type
12template<typename T>
13using Matcher = std::function<bool(const T&)>;
14
15// MatcherWithPriority structure
16template<typename T>
17struct MatcherWithPriority {
18 Matcher<T> matcher;
19 int priority; // -1, 0, or 1
20
21 MatcherWithPriority() : priority(0) {}
22 MatcherWithPriority(const Matcher<T>& m, int p) : matcher(m), priority(p) {}
23};
24
25// Helper functions
26bool isIdentifier(const std::string& token);
27bool isIdentifier(const std::string* token);
28
29// Tokenizer class
30class SelectorTokenizer {
31private:
32 std::string _input;
33 size_t _position;
34
35public:
36 explicit SelectorTokenizer(const std::string& input);
37 std::string* next();
38};
39
40// Create matchers from a selector string (template implementation in header)
41template<typename T>
42std::vector<MatcherWithPriority<T>> createMatchers(
43 const std::string& selector,
44 std::function<bool(const std::vector<std::string>&, const T&)> matchesName
45) {
46 std::vector<MatcherWithPriority<T>> results;
47 SelectorTokenizer tokenizer(selector);
48 std::string* token = tokenizer.next();
49
50 // Forward declarations of parsing functions
51 std::function<Matcher<T>(std::string*&)> parseOperand;
52 std::function<Matcher<T>(std::string*&)> parseConjunction;
53 std::function<Matcher<T>(std::string*&)> parseInnerExpression;
54
55 // parseOperand: Parse a single operand (identifier, negation, or parenthesized expression)
56 parseOperand = [&](std::string*& tok) -> Matcher<T> {
57 if (tok && *tok == "-") {
58 delete tok;
59 tok = tokenizer.next();
60 Matcher<T> expressionToNegate = parseOperand(tok);
61 return [expressionToNegate](const T& matcherInput) -> bool {
62 return expressionToNegate ? !expressionToNegate(matcherInput) : true;
63 };
64 }
65 if (tok && *tok == "(") {
66 delete tok;
67 tok = tokenizer.next();
68 Matcher<T> expressionInParents = parseInnerExpression(tok);
69 if (tok && *tok == ")") {
70 delete tok;
71 tok = tokenizer.next();
72 }
73 return expressionInParents;
74 }
75 if (isIdentifier(tok)) {
76 std::vector<std::string> identifiers;
77 while (isIdentifier(tok)) {
78 identifiers.push_back(*tok);
79 delete tok;
80 tok = tokenizer.next();
81 }
82 return [identifiers, matchesName](const T& matcherInput) -> bool {
83 return matchesName(identifiers, matcherInput);
84 };
85 }
86 return Matcher<T>(); // null matcher
87 };
88
89 // parseConjunction: Parse a conjunction (AND) of operands
90 parseConjunction = [&](std::string*& tok) -> Matcher<T> {
91 std::vector<Matcher<T>> matchers;
92 Matcher<T> matcher = parseOperand(tok);
93 while (matcher) {
94 matchers.push_back(matcher);
95 matcher = parseOperand(tok);
96 }
97 return [matchers](const T& matcherInput) -> bool {
98 for (const auto& m : matchers) {
99 if (!m(matcherInput)) {
100 return false;
101 }
102 }
103 return true;
104 };
105 };
106
107 // parseInnerExpression: Parse disjunction (OR) of conjunctions
108 parseInnerExpression = [&](std::string*& tok) -> Matcher<T> {
109 std::vector<Matcher<T>> matchers;
110 Matcher<T> matcher = parseConjunction(tok);
111 while (matcher) {
112 matchers.push_back(matcher);
113 if (tok && (*tok == "|" || *tok == ",")) {
114 do {
115 delete tok;
116 tok = tokenizer.next();
117 } while (tok && (*tok == "|" || *tok == ","));
118 } else {
119 break;
120 }
121 matcher = parseConjunction(tok);
122 }
123 return [matchers](const T& matcherInput) -> bool {
124 for (const auto& m : matchers) {
125 if (m(matcherInput)) {
126 return true;
127 }
128 }
129 return false;
130 };
131 };
132
133 // Main parsing loop
134 while (token != nullptr) {
135 int priority = 0;
136 if (token->length() == 2 && token->at(1) == ':') {
137 switch (token->at(0)) {
138 case 'R': priority = 1; break;
139 case 'L': priority = -1; break;
140 default:
141 // Unknown priority
142 break;
143 }
144 delete token;
145 token = tokenizer.next();
146 }
147 Matcher<T> matcher = parseConjunction(token);
148 results.push_back(MatcherWithPriority<T>(matcher, priority));
149 if (token == nullptr || *token != ",") {
150 break;
151 }
152 delete token;
153 token = tokenizer.next();
154 }
155
156 if (token != nullptr) {
157 delete token;
158 }
159
160 return results;
161}
162
163} // namespace tml
164
165#endif // TEXTMATELIB_MATCHER_H
Core type definitions and interfaces for TextMateLib.