| 448 | } |
| 449 | |
| 450 | const char * llama_grammar_parser::parse_sequence( |
| 451 | const char * src, |
| 452 | const std::string & rule_name, |
| 453 | llama_grammar_rule & rule, |
| 454 | bool is_nested) { |
| 455 | size_t last_sym_start = rule.size(); |
| 456 | const char * pos = src; |
| 457 | |
| 458 | // use UINT64_MAX as the empty value because we aligned to the proper uint64_t type so -1 can't be used |
| 459 | // (though it's technically the same as -1 now) |
| 460 | auto handle_repetitions = [&](uint64_t min_times, uint64_t max_times) { |
| 461 | bool no_max = max_times == UINT64_MAX; |
| 462 | if (last_sym_start == rule.size()) { |
| 463 | throw std::runtime_error(std::string("expecting preceding item to */+/?/{ at ") + pos); |
| 464 | } |
| 465 | |
| 466 | // apply transformation to previous symbol (last_sym_start to end) according to |
| 467 | // the following rewrite rules: |
| 468 | // S{m,n} --> S S S (m times) S'(n-m) |
| 469 | // S'(x) ::= S S'(x-1) | |
| 470 | // (... n-m definitions of these S' rules ...) |
| 471 | // S'(1) ::= S | |
| 472 | // S{m,} --> S S S (m times) S' |
| 473 | // S' ::= S S' | |
| 474 | // S* --> S{0,} |
| 475 | // --> S' ::= S S' | |
| 476 | // S+ --> S{1,} |
| 477 | // --> S S' |
| 478 | // S' ::= S S' | |
| 479 | // S? --> S{0,1} |
| 480 | // --> S' |
| 481 | // S' ::= S | |
| 482 | |
| 483 | llama_grammar_rule prev_rule(rule.begin() + last_sym_start, rule.end()); |
| 484 | if (min_times == 0) { |
| 485 | rule.resize(last_sym_start); |
| 486 | } else { |
| 487 | // Repeat the previous elements (min_times - 1) times |
| 488 | for (uint64_t i = 1; i < min_times; i++) { |
| 489 | rule.insert(rule.end(), prev_rule.begin(), prev_rule.end()); |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | uint32_t last_rec_rule_id = 0; |
| 494 | auto n_opt = no_max ? 1 : max_times - min_times; |
| 495 | |
| 496 | llama_grammar_rule rec_rule(prev_rule); |
| 497 | for (uint64_t i = 0; i < n_opt; i++) { |
| 498 | rec_rule.resize(prev_rule.size()); |
| 499 | uint32_t rec_rule_id = generate_symbol_id( rule_name); |
| 500 | if (i > 0 || no_max) { |
| 501 | rec_rule.push_back({LLAMA_GRETYPE_RULE_REF, no_max ? rec_rule_id : last_rec_rule_id}); |
| 502 | } |
| 503 | rec_rule.push_back({LLAMA_GRETYPE_ALT, 0}); |
| 504 | rec_rule.push_back({LLAMA_GRETYPE_END, 0}); |
| 505 | add_rule( rec_rule_id, rec_rule); |
| 506 | last_rec_rule_id = rec_rule_id; |
| 507 | } |
nothing calls this directly
no test coverage detected