| 338 | } |
| 339 | |
| 340 | const char * llama_grammar_parser::parse_sequence( |
| 341 | const char * src, |
| 342 | const std::string & rule_name, |
| 343 | llama_grammar_rule & rule, |
| 344 | bool is_nested) { |
| 345 | size_t last_sym_start = rule.size(); |
| 346 | const char * pos = src; |
| 347 | |
| 348 | auto handle_repetitions = [&](int min_times, int max_times) { |
| 349 | |
| 350 | if (last_sym_start == rule.size()) { |
| 351 | throw std::runtime_error(std::string("expecting preceding item to */+/?/{ at ") + pos); |
| 352 | } |
| 353 | |
| 354 | // apply transformation to previous symbol (last_sym_start to end) according to |
| 355 | // the following rewrite rules: |
| 356 | // S{m,n} --> S S S (m times) S'(n-m) |
| 357 | // S'(x) ::= S S'(x-1) | |
| 358 | // (... n-m definitions of these S' rules ...) |
| 359 | // S'(1) ::= S | |
| 360 | // S{m,} --> S S S (m times) S' |
| 361 | // S' ::= S S' | |
| 362 | // S* --> S{0,} |
| 363 | // --> S' ::= S S' | |
| 364 | // S+ --> S{1,} |
| 365 | // --> S S' |
| 366 | // S' ::= S S' | |
| 367 | // S? --> S{0,1} |
| 368 | // --> S' |
| 369 | // S' ::= S | |
| 370 | |
| 371 | llama_grammar_rule prev_rule(rule.begin() + last_sym_start, rule.end()); |
| 372 | if (min_times == 0) { |
| 373 | rule.resize(last_sym_start); |
| 374 | } else { |
| 375 | // Repeat the previous elements (min_times - 1) times |
| 376 | for (int i = 1; i < min_times; i++) { |
| 377 | rule.insert(rule.end(), prev_rule.begin(), prev_rule.end()); |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | uint32_t last_rec_rule_id = 0; |
| 382 | auto n_opt = max_times < 0 ? 1 : max_times - min_times; |
| 383 | |
| 384 | llama_grammar_rule rec_rule(prev_rule); |
| 385 | for (int i = 0; i < n_opt; i++) { |
| 386 | rec_rule.resize(prev_rule.size()); |
| 387 | uint32_t rec_rule_id = generate_symbol_id( rule_name); |
| 388 | if (i > 0 || max_times < 0) { |
| 389 | rec_rule.push_back({LLAMA_GRETYPE_RULE_REF, max_times < 0 ? rec_rule_id : last_rec_rule_id}); |
| 390 | } |
| 391 | rec_rule.push_back({LLAMA_GRETYPE_ALT, 0}); |
| 392 | rec_rule.push_back({LLAMA_GRETYPE_END, 0}); |
| 393 | add_rule( rec_rule_id, rec_rule); |
| 394 | last_rec_rule_id = rec_rule_id; |
| 395 | } |
| 396 | if (n_opt > 0) { |
| 397 | rule.push_back({LLAMA_GRETYPE_RULE_REF, last_rec_rule_id}); |
nothing calls this directly
no test coverage detected