24#include "kmp_traits.h"
27using namespace kmp_traits;
99static bool is_word_char(
char c) {
100 return isalnum(
static_cast<unsigned char>(c)) || c ==
'-' || c ==
'_';
103static bool is_digit(
char c) {
104 return static_cast<bool>(isdigit(
static_cast<unsigned char>(c)));
109token kmp_lexer::lex() {
112 const char *start = scan.begin();
117 if (scan.consume_front(
"&&"))
119 if (scan.consume_front(
"||"))
126 return {token_kind::WORD, word};
133 kind = token_kind::COMMA;
136 kind = token_kind::STAR;
139 kind = token_kind::NOT;
142 kind = token_kind::L_PAREN;
145 kind = token_kind::R_PAREN;
148 kind = token_kind::L_BRACKET;
151 kind = token_kind::R_BRACKET;
154 kind = token_kind::COLON;
157 kind = token_kind::UNKNOWN;
168constexpr int MAX_RECURSION_DEPTH = 64;
170using namespace kmp_traits;
171using namespace lexer;
174static bool word_is(
const token &tok,
kmp_str_ref keyword) {
176 return tok.kind == token_kind::WORD && text.
consume_front(keyword) &&
185static bool word_is_number(
const token &tok) {
186 if (tok.kind != token_kind::WORD)
196static kmp_str_ref consume_uid_value(kmp_lexer &lex,
const char *dbg_name) {
197 const token &tok = lex.peek();
198 if (tok.kind != token_kind::WORD)
199 KMP_FATAL(TraitParserInvalidTraitValue, dbg_name,
"uid", tok.text.copy());
212 const char *dbg_name) {
213 if (!word_is(lex.peek(),
"uid"))
218 if (lex.peek().kind != token_kind::L_PAREN)
219 KMP_FATAL(TraitParserError, dbg_name,
"expected '(' after trait name");
221 kmp_str_ref uid = consume_uid_value(lex, dbg_name);
222 if (lex.peek().kind != token_kind::R_PAREN)
223 KMP_FATAL(TraitParserError, dbg_name,
"expected ')' after trait value");
231 kmp_lexer &lex,
int max_recursion,
232 const char *dbg_name);
240 bool negated, kmp_lexer &lex,
242 const char *dbg_name) {
243 if (lex.peek().kind != token_kind::L_PAREN)
245 group.set_negated(negated);
247 if (!consume_trait_expr_group(group, lex, max_recursion, dbg_name))
248 KMP_FATAL(TraitParserError, dbg_name,
249 "expected trait expression after '('");
250 if (lex.peek().kind != token_kind::R_PAREN)
251 KMP_FATAL(TraitParserError, dbg_name,
252 "expected ')' after trait expression group");
262static bool consume_trait_expr(
kmp_trait_expr *&expr, kmp_lexer &lex,
263 int max_recursion,
const char *dbg_name) {
264 if (max_recursion-- <= 0)
265 KMP_FATAL(TraitParserMaxRecursion, dbg_name, MAX_RECURSION_DEPTH);
268 bool negated = lex.peek().kind == token_kind::NOT;
274 if (consume_trait_expr_group_paren(*group, negated, lex, max_recursion,
283 single->set_negated(negated);
284 if (consume_trait(*single, lex, dbg_name)) {
294 KMP_FATAL(TraitParserError, dbg_name,
295 "expected trait expression after '!'");
307 kmp_lexer &lex,
int max_recursion,
308 const char *dbg_name) {
309 if (max_recursion-- <= 0)
310 KMP_FATAL(TraitParserMaxRecursion, dbg_name, MAX_RECURSION_DEPTH);
313 if (!consume_trait_expr(expr, lex, max_recursion, dbg_name))
315 group.add_expr(expr);
318 if (lex.peek().kind == token_kind::OR) {
319 group.set_group_type(kmp_trait_expr_group::OR);
321 }
else if (lex.peek().kind == token_kind::AND) {
322 group.set_group_type(kmp_trait_expr_group::AND);
323 op = token_kind::AND;
332 if (!consume_trait_expr(expr, lex, max_recursion, dbg_name))
333 KMP_FATAL(TraitParserError, dbg_name,
334 "expected trait expression after operator");
335 group.add_expr(expr);
336 if (lex.peek().kind != op)
349static bool consume_device_number(kmp_trait_clause &clause, kmp_lexer &lex,
350 const char *dbg_name) {
351 if (!word_is_number(lex.peek()))
356 KMP_FATAL(TraitParserError, dbg_name,
"device number out of range");
369static bool consume_clause(kmp_trait_clause &clause, kmp_lexer &lex,
370 const char *dbg_name) {
372 if (lex.peek().kind == token_kind::STAR) {
380 if (consume_device_number(clause, lex, dbg_name))
385 if (consume_trait_expr_group(*group, lex, MAX_RECURSION_DEPTH, dbg_name)) {
386 clause.set_expr(group);
395static void consume_list(kmp_trait_context &context, kmp_lexer &lex,
396 const char *dbg_name) {
399 while (lex.peek().kind != token_kind::END) {
400 kmp_trait_clause *clause =
new kmp_trait_clause();
401 if (!consume_clause(*clause, lex, dbg_name)) {
403 KMP_FATAL(TraitParserFailed, dbg_name, lex_pos.
copy());
405 context.add_clause(clause);
407 lex_pos = lex.remaining();
408 if (lex.peek().kind == token_kind::COMMA)
410 else if (lex.peek().kind != token_kind::END)
411 KMP_FATAL(TraitParserFailed, dbg_name, lex_pos.
copy());
417kmp_trait_context *kmp_trait_context::parse_from_spec(
kmp_str_ref spec,
418 const char *dbg_name) {
419 kmp_trait_context *context =
new kmp_trait_context();
420 lexer::kmp_lexer lex(spec);
421 parser::consume_list(*context, lex, dbg_name);
kmp_str_ref is a non-owning string class (similar to llvm::StringRef).
kmp_str_ref take_while(const Fn &predicate) const
size_t find_if_not(const Fn &predicate) const
size_t length() const
Get the length of the string.
bool consume_front(kmp_str_ref prefix)
bool consume_integer(int &value, bool allow_zero=true, bool allow_negative=false)
bool empty() const
Check if the string is empty.
void drop_front(size_t n)
Represents a specific device number.
Represents a single (possibly negated) trait.
Represents a wildcard trait that matches any device.