char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
acecd5603
char/aliceai-t5-moe
1#include "peg-parser.h" 2 3#include "common.h" 4#include "json-schema-to-grammar.h" 5#include "log.h" 6#include "trie.h" 7#include "unicode.h" 8 9#include <algorithm> 10#include <initializer_list> 11#include <map> 12#include <memory> 13#include <regex> 14#include <set> 15#include <stdexcept> 16 17// Trick to catch missing branches 18template < typename T > 19inline constexpr bool is_always_false_v = false; 20 21const char * common_peg_parse_result_type_name (common_peg_parse_result_type type ) { 22switch (type ) { 23case COMMON_PEG_PARSE_RESULT_FAIL :return "fail" ; 24case COMMON_PEG_PARSE_RESULT_SUCCESS :return "success" ; 25case COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT :return "need_more_input" ; 26default :return "unknown" ; 27 } 28} 29 30static bool is_hex_digit (const char c ) { 31return (c >='0' && c <='9' )|| (c >='a' && c <='f' )|| (c >='A' && c <='F' ); 32} 33 34static std::pair < uint32_t ,size_t > parse_hex_escape (const std::string & str ,size_t pos ,int hex_count ) { 35if (pos + hex_count > str .length ()) { 36return {0 ,0 }; 37 } 38 39uint32_t value = 0 ; 40for (int i = 0 ;i < hex_count ;i ++ ) { 41char c = str [pos + i ]; 42if (!is_hex_digit (c )) { 43return {0 ,0 }; 44 } 45value <<=4 ; 46if ('a' <=c && c <='f' ) { 47value += c - 'a' + 10 ; 48 }else if ('A' <=c && c <='F' ) { 49value += c - 'A' + 10 ; 50 }else if ('0' <=c && c <='9' ) { 51value += c - '0' ; 52 }else { 53break ; 54 } 55 } 56return {value ,static_cast < size_t > (hex_count )}; 57} 58 59static std::pair < uint32_t ,size_t > parse_char_class_char (const std::string & content ,size_t pos ) { 60if (content [pos ]== '\\' && pos + 1 < content .length ()) { 61switch (content [pos + 1 ]) { 62case 'x' : { 63auto result = parse_hex_escape (content ,pos + 2 ,2 ); 64if (result .second > 0 ) { 65return {result .first ,2 + result .second }; 66 } 67// Invalid escape, treat as literal 'x' 68return {static_cast < uint32_t > ('x' ),2 }; 69 } 70case 'u' : { 71auto result = parse_hex_escape (content ,pos + 2 ,4 ); 72if (result .second > 0 ) { 73return {result .first ,2 + result .second }; 74 } 75// Invalid escape, treat as literal 'u' 76return {static_cast < uint32_t > ('u' ),2 }; 77 } 78case 'U' : { 79auto result = parse_hex_escape (content ,pos + 2 ,8 ); 80if (result .second > 0 ) { 81return {result .first ,2 + result .second }; 82 } 83// Invalid escape, treat as literal 'U' 84return {static_cast < uint32_t > ('U' ),2 }; 85 } 86case 'n' :return {'\n' ,2 }; 87case 't' :return {'\t' ,2 }; 88case 'r' :return {'\r' ,2 }; 89case '\\' :return {'\\' ,2 }; 90case ']' :return {']' ,2 }; 91case '[' :return {'[' ,2 }; 92default :return {static_cast < uint32_t > (content [pos + 1 ]),2 }; 93 } 94 } 95 96// Regular character - return as codepoint 97return {static_cast < uint32_t > (static_cast < unsigned char > (content [pos ])),1 }; 98} 99 100static std::pair < std::vector < common_peg_chars_parser::char_range > ,bool > parse_char_classes (const std::string & classes ) { 101 std::vector < common_peg_chars_parser::char_range > ranges ; 102bool negated = false; 103 104 std::string content = classes ; 105if (content .front ()== '[' ) { 106content = content .substr (1 ); 107 } 108 109if (content .back ()== ']' ) { 110content .pop_back (); 111 } 112 113// Check for negation 114if (!content .empty ()&& content .front ()== '^' ) { 115negated = true; 116content = content .substr (1 ); 117 } 118 119size_t i = 0 ; 120while (i < content .length ()) { 121auto [start ,start_len ]= parse_char_class_char (content ,i ); 122i += start_len ; 123 124if (i + 1 < content .length ()&& content [i ]== '-' ) { 125// Range detected 126auto [end ,end_len ]= parse_char_class_char (content ,i + 1 ); 127ranges .push_back (common_peg_chars_parser::char_range {start ,end }); 128i += 1 + end_len ; 129 }else { 130ranges .push_back (common_peg_chars_parser::char_range {start ,start }); 131 } 132 } 133 134return {ranges ,negated }; 135} 136 137common_peg_ast_id common_peg_ast_arena::find_by_tag (const common_peg_ast_node & parent ,const std::string & tag ,int max_depth )const { 138for (auto child_id :parent .children ) { 139const auto & child = get (child_id ); 140if (child .tag == tag ) { 141return child_id ; 142 } 143if (max_depth > 1 ) { 144auto result = find_by_tag (child ,tag ,max_depth - 1 ); 145if (result != COMMON_PEG_INVALID_AST_ID ) { 146return result ; 147 } 148 } 149 } 150return COMMON_PEG_INVALID_AST_ID ; 151} 152 153common_peg_ast_id common_peg_ast_arena::find_by_rule (const common_peg_ast_node & parent ,const std::string & rule ,int max_depth )const { 154for (auto child_id :parent .children ) { 155const auto & child = get (child_id ); 156if (child .rule == rule ) { 157return child_id ; 158 } 159if (max_depth > 1 ) { 160auto result = find_by_rule (child ,rule ,max_depth - 1 ); 161if (result != COMMON_PEG_INVALID_AST_ID ) { 162return result ; 163 } 164 } 165 } 166return COMMON_PEG_INVALID_AST_ID ; 167} 168 169void common_peg_ast_arena::visit (common_peg_ast_id id ,const common_peg_ast_visitor & visitor )const { 170if (id == COMMON_PEG_INVALID_AST_ID ) { 171return ; 172 } 173const auto & node = get (id ); 174visitor (node ); 175for (const auto & child :node .children ) { 176visit (child ,visitor ); 177 } 178} 179 180void common_peg_ast_arena::visit (const common_peg_parse_result & result ,const common_peg_ast_visitor & visitor )const { 181for (const auto & node :result .nodes ) { 182visit (node ,visitor ); 183 } 184} 185 186struct parser_executor ; 187 188common_peg_parser_id common_peg_arena::add_parser (common_peg_parser_variant parser ) { 189common_peg_parser_id id = parsers_ .size (); 190parsers_ .push_back (std::move (parser )); 191return id ; 192} 193 194void common_peg_arena::add_rule (const std::string & name ,common_peg_parser_id id ) { 195rules_ [name ]= id ; 196} 197 198common_peg_parser_id common_peg_arena::get_rule (const std::string & name )const { 199auto it = rules_ .find (name ); 200if (it == rules_ .end ()) { 201throw std::runtime_error ("Rule not found: " + name ); 202 } 203return it -> second ; 204} 205 206struct parser_executor { 207const common_peg_arena & arena ; 208common_peg_parse_context & ctx ; 209size_t start_pos ; 210 211parser_executor (const common_peg_arena & arena ,common_peg_parse_context & ctx ,size_t start ) 212 :arena (arena ),ctx (ctx ),start_pos (start ) {} 213 214 std::string debug_indent ()const {return std::string (ctx .parse_depth * 2 ,' ' ); } 215 216 std::string debug_input_snippet (size_t pos ,size_t len = 60 )const { 217if (pos >=ctx .input .size ()) { 218return "<EOF>" ; 219 } 220auto snippet = ctx .input .substr (pos ,len ); 221// Escape newlines for display 222 std::string result ; 223for (char c :snippet ) { 224if (c == '\n' ) { 225result += "\\n" ; 226 }else if (c == '\r' ) { 227result += "\\r" ; 228 }else if (c == '\t' ) { 229result += "\\t" ; 230 }else { 231result += c ; 232 } 233 } 234if (pos + len < ctx .input .size ()) { 235result += "..." ; 236 } 237return result ; 238 } 239 240common_peg_parse_result operator()(const common_peg_epsilon_parser & /* p */ )const { 241return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ); 242 } 243 244common_peg_parse_result operator()(const common_peg_start_parser & /* p */ )const { 245return common_peg_parse_result ( 246start_pos == 0 ?COMMON_PEG_PARSE_RESULT_SUCCESS :COMMON_PEG_PARSE_RESULT_FAIL , 247start_pos 248 ); 249 } 250 251common_peg_parse_result operator()(const common_peg_end_parser & /* p */ )const { 252return common_peg_parse_result ( 253start_pos >=ctx .input .size () ?COMMON_PEG_PARSE_RESULT_SUCCESS :COMMON_PEG_PARSE_RESULT_FAIL , 254start_pos 255 ); 256 } 257 258common_peg_parse_result operator()(const common_peg_literal_parser & p ) { 259auto pos = start_pos ; 260for (auto i = 0u ;i < p .literal .size ();++ i ) { 261if (pos >=ctx .input .size ()) { 262if (!ctx .is_lenient ()) { 263return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 264 } 265return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos ); 266 } 267if (ctx .input [pos ]!= p .literal [i ]) { 268return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 269 } 270++ pos ; 271 } 272 273return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 274 } 275 276common_peg_parse_result operator()(const common_peg_sequence_parser & p ) { 277if (ctx .is_debug ()) { 278LOG_DBG ("%sSEQ start at %zu '%s' (%zu children)\n" ,debug_indent ().c_str (),start_pos , 279debug_input_snippet (start_pos ).c_str (),p .children .size ()); 280 } 281ctx .parse_depth ++ ; 282 283auto pos = start_pos ; 284 std::vector < common_peg_ast_id > nodes ; 285 286for (size_t i = 0 ;i < p .children .size ();i ++ ) { 287const auto & child_id = p .children [i ]; 288if (ctx .is_debug ()) { 289fprintf (stderr ,"%sSEQ child %zu: %s\n" ,debug_indent ().c_str (),i ,arena .dump (child_id ).c_str ()); 290 } 291auto result = arena .parse (child_id ,ctx ,pos ); 292 293if (ctx .is_debug ()) { 294fprintf (stderr ,"%sSEQ child %zu: %s at %zu->%zu\n" ,debug_indent ().c_str (),i , 295common_peg_parse_result_type_name (result .type ),result .start ,result .end ); 296 } 297 298if (result .fail ()) { 299ctx .parse_depth -- ; 300if (ctx .is_debug ()) { 301fprintf (stderr ,"%sSEQ -> FAIL\n" ,debug_indent ().c_str ()); 302 } 303return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ,result .end ); 304 } 305 306if (!result .nodes .empty ()) { 307nodes .insert (nodes .end (),result .nodes .begin (),result .nodes .end ()); 308 } 309 310if (result .need_more_input ()) { 311ctx .parse_depth -- ; 312if (ctx .is_debug ()) { 313fprintf (stderr ,"%sSEQ -> NEED_MORE\n" ,debug_indent ().c_str ()); 314 } 315return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,result .end , std::move (nodes )); 316 } 317 318pos = result .end ; 319 } 320 321ctx .parse_depth -- ; 322if (ctx .is_debug ()) { 323fprintf (stderr ,"%sSEQ -> SUCCESS at %zu->%zu\n" ,debug_indent ().c_str (),start_pos ,pos ); 324 } 325return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos , std::move (nodes )); 326 } 327 328common_peg_parse_result operator()(const common_peg_choice_parser & p ) { 329if (ctx .is_debug ()) { 330fprintf (stderr ,"%sCHOICE start at %zu '%s' (%zu options)\n" ,debug_indent ().c_str (),start_pos , 331debug_input_snippet (start_pos ).c_str (),p .children .size ()); 332 } 333ctx .parse_depth ++ ; 334 335auto pos = start_pos ; 336for (size_t i = 0 ;i < p .children .size ();i ++ ) { 337const auto & child_id = p .children [i ]; 338if (ctx .is_debug ()) { 339fprintf (stderr ,"%sCHOICE option %zu: %s\n" ,debug_indent ().c_str (),i ,arena .dump (child_id ).c_str ()); 340 } 341auto result = arena .parse (child_id ,ctx ,pos ); 342if (ctx .is_debug ()) { 343fprintf (stderr ,"%sCHOICE option %zu: %s\n" ,debug_indent ().c_str (),i , 344common_peg_parse_result_type_name (result .type )); 345 } 346if (!result .fail ()) { 347ctx .parse_depth -- ; 348if (ctx .is_debug ()) { 349fprintf (stderr ,"%sCHOICE -> %s (option %zu)\n" ,debug_indent ().c_str (), 350common_peg_parse_result_type_name (result .type ),i ); 351 } 352return result ; 353 } 354 } 355 356ctx .parse_depth -- ; 357if (ctx .is_debug ()) { 358fprintf (stderr ,"%sCHOICE -> FAIL (no options matched)\n" ,debug_indent ().c_str ()); 359 } 360return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 361 } 362 363common_peg_parse_result operator()(const common_peg_repetition_parser & p ) { 364if (ctx .is_debug ()) { 365fprintf (stderr ,"%sREPEAT start at %zu '%s' (min=%d, max=%d)\n" ,debug_indent ().c_str (),start_pos , 366debug_input_snippet (start_pos ).c_str (),p .min_count ,p .max_count ); 367 } 368ctx .parse_depth ++ ; 369 370auto pos = start_pos ; 371int match_count = 0 ; 372 std::vector < common_peg_ast_id > nodes ; 373 374// Try to match up to max_count times (or unlimited if max_count is -1) 375while (p .max_count == -1 || match_count < p .max_count ) { 376if (pos >=ctx .input .size ()) { 377if (ctx .is_debug ()) { 378fprintf (stderr ,"%sREPEAT: at end of input, count=%d\n" ,debug_indent ().c_str (),match_count ); 379 } 380break ; 381 } 382 383auto result = arena .parse (p .child ,ctx ,pos ); 384 385if (ctx .is_debug ()) { 386fprintf (stderr ,"%sREPEAT iter %d: %s at %zu->%zu, nodes=%zu\n" ,debug_indent ().c_str (),match_count , 387common_peg_parse_result_type_name (result .type ),result .start ,result .end ,result .nodes .size ()); 388fprintf (stderr ,"%sREPEAT CHILD: %s\n" ,debug_indent ().c_str (),arena .dump (p .child ).c_str ()); 389 } 390 391if (result .success ()) { 392// Prevent infinite loop on empty matches 393if (result .end == pos ) { 394if (ctx .is_debug ()) { 395fprintf (stderr ,"%s REPEAT: empty match, stopping\n" ,debug_indent ().c_str ()); 396 } 397break ; 398 } 399 400if (!result .nodes .empty ()) { 401nodes .insert (nodes .end (),result .nodes .begin (),result .nodes .end ()); 402 } 403 404pos = result .end ; 405match_count ++ ; 406continue ; 407 } 408 409if (result .need_more_input ()) { 410if (!result .nodes .empty ()) { 411nodes .insert (nodes .end (),result .nodes .begin (),result .nodes .end ()); 412 } 413 414ctx .parse_depth -- ; 415if (ctx .is_debug ()) { 416fprintf (stderr ,"%sREPEAT -> NEED_MORE (count=%d, nodes=%zu)\n" ,debug_indent ().c_str (), 417match_count ,nodes .size ()); 418 } 419return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,result .end , std::move (nodes )); 420 } 421 422// Child failed - stop trying 423if (ctx .is_debug ()) { 424fprintf (stderr ,"%sREPEAT: child failed, stopping\n" ,debug_indent ().c_str ()); 425 } 426break ; 427 } 428 429// Check if we got enough matches 430if (p .min_count > 0 && match_count < p .min_count ) { 431ctx .parse_depth -- ; 432if (pos >=ctx .input .size ()&& ctx .is_lenient ()) { 433if (ctx .is_debug ()) { 434fprintf (stderr ,"%sREPEAT -> NEED_MORE (not enough matches: %d < %d)\n" ,debug_indent ().c_str (), 435match_count ,p .min_count ); 436 } 437return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos , std::move (nodes )); 438 } 439if (ctx .is_debug ()) { 440fprintf (stderr ,"%sREPEAT -> FAIL (not enough matches: %d < %d)\n" ,debug_indent ().c_str (),match_count , 441p .min_count ); 442 } 443return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ,pos ); 444 } 445 446ctx .parse_depth -- ; 447if (ctx .is_debug ()) { 448fprintf (stderr ,"%sREPEAT -> SUCCESS (count=%d, nodes=%zu)\n" ,debug_indent ().c_str (),match_count , 449nodes .size ()); 450 } 451return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos , std::move (nodes )); 452 } 453 454common_peg_parse_result operator()(const common_peg_and_parser & p ) { 455auto result = arena .parse (p .child ,ctx ,start_pos ); 456// Pass result but don't consume input 457return common_peg_parse_result (result .type ,start_pos ); 458 } 459 460common_peg_parse_result operator()(const common_peg_not_parser & p ) { 461auto result = arena .parse (p .child ,ctx ,start_pos ); 462 463if (result .success ()) { 464// Fail if the underlying parser matches 465return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 466 } 467 468if (result .need_more_input ()) { 469// Propagate - need to know what child would match before negating 470return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ); 471 } 472 473// Child failed, so negation succeeds 474return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ); 475 } 476 477common_peg_parse_result operator()(const common_peg_any_parser & /* p */ )const { 478// Parse a single UTF-8 codepoint (not just a single byte) 479auto result = common_parse_utf8_codepoint (ctx .input ,start_pos ); 480 481if (result .status == utf8_parse_result::INCOMPLETE ) { 482if (!ctx .is_lenient ()) { 483return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 484 } 485return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ); 486 } 487if (result .status == utf8_parse_result::INVALID ) { 488return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 489 } 490return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,start_pos + result .bytes_consumed ); 491 } 492 493common_peg_parse_result operator()(const common_peg_space_parser & /* p */ ) { 494auto pos = start_pos ; 495while (pos < ctx .input .size ()) { 496auto c = static_cast < unsigned char > (ctx .input [pos ]); 497if (std::isspace (c )) { 498++ pos ; 499 }else { 500break ; 501 } 502 } 503 504return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 505 } 506 507common_peg_parse_result operator()(const common_peg_chars_parser & p )const { 508auto pos = start_pos ; 509int match_count = 0 ; 510 511// Try to match up to max_count times (or unlimited if max_count is -1) 512while (p .max_count == -1 || match_count < p .max_count ) { 513auto result = common_parse_utf8_codepoint (ctx .input ,pos ); 514 515if (result .status == utf8_parse_result::INCOMPLETE ) { 516if (match_count >=p .min_count ) { 517// We have enough matches, succeed with what we have 518return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 519 } 520// Not enough matches yet 521if (!ctx .is_lenient ()) { 522return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 523 } 524return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos ); 525 } 526 527if (result .status == utf8_parse_result::INVALID ) { 528// Malformed UTF-8 in input 529if (match_count >=p .min_count ) { 530// We have enough matches, succeed up to here 531return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 532 } 533// Not enough matches, fail 534return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 535 } 536 537// Check if this codepoint matches our character class 538bool matches = false; 539for (const auto & range :p .ranges ) { 540if (range .contains (result .codepoint )) { 541matches = true; 542break ; 543 } 544 } 545 546// If negated, invert the match result 547if (p .negated ) { 548matches = !matches ; 549 } 550 551if (matches ) { 552pos += result .bytes_consumed ; 553++ match_count ; 554 }else { 555// Character doesn't match, stop matching 556break ; 557 } 558 } 559 560// Check if we got enough matches 561if (match_count < p .min_count ) { 562if (pos >=ctx .input .size ()&& ctx .is_lenient ()) { 563return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos ); 564 } 565return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ,pos ); 566 } 567 568return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 569 } 570 571static common_peg_parse_result handle_escape_sequence (common_peg_parse_context & ctx ,size_t start ,size_t & pos ,const char delimiter ) { 572auto save = pos ; 573 574++ pos ;// consume '\' 575if (pos >=ctx .input .size ()) { 576if (!ctx .is_lenient ()) { 577return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start ); 578 } 579pos = save ;// suppress unmatched '\' 580return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start ,pos ); 581 } 582 583char c = ctx .input [pos ]; 584 585if (c == delimiter || c == '\\' || c == '/' || c == 'b' || c == 'f' || c == 'n' || c == 'r' || c == 't' ) { 586++ pos ; 587return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start ,pos ); 588 } 589 590if (c == 'u' ) { 591auto result = handle_unicode_escape (ctx ,start ,pos ); 592if (result .need_more_input ()) { 593pos = save ;// suppress incomplete sequence 594return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start ,pos ); 595 } 596return result ; 597 } 598 599return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start ); 600 } 601 602static common_peg_parse_result handle_unicode_escape (common_peg_parse_context & ctx ,size_t start ,size_t & pos ) { 603++ pos ;// consume 'u' 604for (int i = 0 ;i < 4 ;++ i ) { 605if (pos >=ctx .input .size ()) { 606if (!ctx .is_lenient ()) { 607return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start ); 608 } 609return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start ,pos ); 610 } 611if (!is_hex_digit (ctx .input [pos ])) { 612return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start ); 613 } 614++ pos ; 615 } 616return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start ,pos ); 617 } 618 619common_peg_parse_result operator()(const common_peg_string_parser & p ) { 620auto pos = start_pos ; 621 622// Parse string content (without quotes) 623while (pos < ctx .input .size ()) { 624char c = ctx .input [pos ]; 625 626if (c == p .delimiter ) { 627// Found closing delimiter - success (don't consume it) 628return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 629 } 630 631if (c == '\\' ) { 632auto result = handle_escape_sequence (ctx ,start_pos ,pos ,p .delimiter ); 633if (!result .success ()) { 634return result ; 635 } 636 }else { 637auto utf8_result = common_parse_utf8_codepoint (ctx .input ,pos ); 638 639if (utf8_result .status == utf8_parse_result::INCOMPLETE ) { 640if (!ctx .is_lenient ()) { 641return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 642 } 643return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos ); 644 } 645 646if (utf8_result .status == utf8_parse_result::INVALID ) { 647return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 648 } 649 650pos += utf8_result .bytes_consumed ; 651 } 652 } 653 654// Reached end without finding closing quote 655if (!ctx .is_lenient ()) { 656return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ,pos ); 657 } 658return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,pos ); 659 } 660 661common_peg_parse_result operator()(const common_peg_until_parser & p )const { 662common_trie matcher (p .delimiters ); 663 664// Scan input and check for delimiters 665size_t pos = start_pos ; 666size_t last_valid_pos = start_pos ; 667 668while (pos < ctx .input .size ()) { 669auto utf8_result = common_parse_utf8_codepoint (ctx .input ,pos ); 670 671if (utf8_result .status == utf8_parse_result::INCOMPLETE ) { 672// Incomplete UTF-8 sequence 673if (!ctx .is_lenient ()) { 674// Input is complete but UTF-8 is incomplete = malformed 675return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 676 } 677// Return what we have so far (before incomplete sequence) 678return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,last_valid_pos ); 679 } 680 681if (utf8_result .status == utf8_parse_result::INVALID ) { 682// Malformed UTF-8 683return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_FAIL ,start_pos ); 684 } 685 686// Check if a delimiter starts at this position 687auto match = matcher .check_at (ctx .input ,pos ); 688 689if (match == common_trie::COMPLETE_MATCH ) { 690// Found a complete delimiter, return everything before it 691return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 692 } 693 694if (match == common_trie::PARTIAL_MATCH ) { 695// Found a partial match extending to end of input, return everything before it 696return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,pos ); 697 } 698 699pos += utf8_result .bytes_consumed ; 700last_valid_pos = pos ; 701 } 702 703if (last_valid_pos == ctx .input .size ()&& ctx .is_lenient ()) { 704// Reached the end of a partial stream, there might still be more input that we need to consume. 705return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_NEED_MORE_INPUT ,start_pos ,last_valid_pos ); 706 } 707return common_peg_parse_result (COMMON_PEG_PARSE_RESULT_SUCCESS ,start_pos ,last_valid_pos ); 708 } 709 710common_peg_parse_result operator()(const common_peg_schema_parser & p ) { 711return arena .parse (p .child ,ctx ,start_pos ); 712 } 713 714common_peg_parse_result operator()(const common_peg_rule_parser & p ) { 715// Parse the child 716auto result = arena .parse (p .child ,ctx ,start_pos ); 717 718if (!result .fail ()) { 719 std::string_view text ; 720if (result .start < ctx .input .size ()) { 721text = std::string_view (ctx .input ).substr (result .start ,result .end - result .start ); 722 } 723 724auto node_id = ctx .ast .add_node ( 725p .name , 726"" , 727result .start , 728result .end , 729text , 730 std::move (result .nodes ), 731result .need_more_input () 732 ); 733 734return common_peg_parse_result (result .type ,result .start ,result .end , {node_id }); 735 } 736 737return result ; 738 } 739 740common_peg_parse_result operator()(const common_peg_tag_parser & p ) { 741// Parse the child 742if (ctx .is_debug ()) { 743fprintf (stderr ,"%sTAG: %s\n" ,debug_indent ().c_str (),p .tag .c_str ()); 744 } 745auto result = arena .parse (p .child ,ctx ,start_pos ); 746 747if (!result .fail ()) { 748 std::string_view text ; 749if (result .start < ctx .input .size ()) { 750text = std::string_view (ctx .input ).substr (result .start ,result .end - result .start ); 751 } 752 753auto node_id = ctx .ast .add_node ( 754"" , 755p .tag , 756result .start , 757result .end , 758text , 759 std::move (result .nodes ), 760result .need_more_input () 761 ); 762 763return common_peg_parse_result (result .type ,result .start ,result .end , {node_id }); 764 } 765 766return result ; 767 } 768 769common_peg_parse_result operator()(const common_peg_ref_parser & p ) { 770auto rule_id = arena .get_rule (p .name ); 771return arena .parse (rule_id ,ctx ,start_pos ); 772 } 773 774common_peg_parse_result operator()(const common_peg_atomic_parser & p ) { 775auto result = arena .parse (p .child ,ctx ,start_pos ); 776if (result .need_more_input ()) { 777// Clear nodes so they don't propagate up. 778result .nodes .clear (); 779 } 780return result ; 781 } 782 783common_peg_parse_result operator()(const common_peg_gbnf_parser & p ) { 784return arena .parse (p .child ,ctx ,start_pos ); 785 } 786 787common_peg_parse_result operator()(const common_peg_ac_parser & p ) { 788return arena .parse (p .child ,ctx ,start_pos ); 789 } 790}; 791 792common_peg_parse_result common_peg_arena::parse (common_peg_parse_context & ctx ,size_t start )const { 793if (root_ == COMMON_PEG_INVALID_PARSER_ID ) { 794throw std::runtime_error ("No root parser set" ); 795 } 796return parse (root_ ,ctx ,start ); 797} 798 799common_peg_parse_result common_peg_arena::parse (common_peg_parser_id id ,common_peg_parse_context & ctx ,size_t start )const { 800// Execute parser 801const auto & parser = parsers_ .at (id ); 802parser_executor exec (* this ,ctx ,start ); 803return std::visit (exec ,parser ); 804} 805 806common_peg_parser_id common_peg_arena::resolve_ref (common_peg_parser_id id ) { 807const auto & parser = parsers_ .at (id ); 808if (auto ref = std::get_if < common_peg_ref_parser > (& parser )) { 809return get_rule (ref -> name ); 810 } 811return id ; 812} 813 814static void bfs_node (common_peg_ast_arena & arena , std::ostringstream & oss ,const common_peg_ast_node & node ,int indent ) { 815for (int i = 0 ;i < indent ;i ++ ) { 816oss <<" " ; 817 } 818oss <<"NODE " <<node .id ; 819if (!node .rule .empty ()) { 820oss <<" (rule " <<node .rule <<")" ; 821 } 822if (!node .tag .empty ()) { 823oss <<" (tag " <<node .tag <<")" ; 824 } 825oss <<" ['" <<node .text <<"']\n" ; 826for (const auto child :node .children ) { 827bfs_node (arena ,oss ,arena .get (child ),indent + 1 ); 828 } 829} 830 831std::string common_peg_ast_arena::dump () { 832 std::ostringstream oss ; 833for (auto & node :nodes_ ) { 834bfs_node (* this ,oss ,node ,0 ); 835 } 836return oss .str (); 837} 838 839void common_peg_arena::resolve_refs () { 840// Walk through all parsers and replace refs with their corresponding rule IDs 841for (auto & parser :parsers_ ) { 842 std::visit ([this ](auto & p ) { 843using T = std::decay_t < decltype(p )> ; 844 845if constexpr (std::is_same_v < T ,common_peg_sequence_parser > ) { 846for (auto & child :p .children ) { 847child = resolve_ref (child ); 848 } 849 }else if constexpr (std::is_same_v < T ,common_peg_choice_parser > ) { 850for (auto & child :p .children ) { 851child = resolve_ref (child ); 852 } 853 }else if constexpr (std::is_same_v < T ,common_peg_repetition_parser > || 854 std::is_same_v < T ,common_peg_and_parser > || 855 std::is_same_v < T ,common_peg_not_parser > || 856 std::is_same_v < T ,common_peg_tag_parser > || 857 std::is_same_v < T ,common_peg_atomic_parser > || 858 std::is_same_v < T ,common_peg_gbnf_parser > || 859 std::is_same_v < T ,common_peg_ac_parser > ) { 860p .child = resolve_ref (p .child ); 861 }else if constexpr (std::is_same_v < T ,common_peg_rule_parser > ) { 862p .child = resolve_ref (p .child ); 863 }else if constexpr (std::is_same_v < T ,common_peg_schema_parser > ) { 864p .child = resolve_ref (p .child ); 865 }else if constexpr (std::is_same_v < T ,common_peg_epsilon_parser > || 866 std::is_same_v < T ,common_peg_start_parser > || 867 std::is_same_v < T ,common_peg_end_parser > || 868 std::is_same_v < T ,common_peg_ref_parser > || 869 std::is_same_v < T ,common_peg_until_parser > || 870 std::is_same_v < T ,common_peg_literal_parser > || 871 std::is_same_v < T ,common_peg_string_parser > || 872 std::is_same_v < T ,common_peg_chars_parser > || 873 std::is_same_v < T ,common_peg_any_parser > || 874 std::is_same_v < T ,common_peg_space_parser > ) { 875// These rules do not have children 876 }else { 877 static_assert(is_always_false_v < T > ); 878 } 879 },parser ); 880 } 881 882// Also flatten root if it's a ref 883if (root_ != COMMON_PEG_INVALID_PARSER_ID ) { 884root_ = resolve_ref (root_ ); 885 } 886} 887 888std::string common_peg_arena::dump (common_peg_parser_id id )const { 889 std::set < common_peg_parser_id > visited ; 890return dump_impl (id ,visited ); 891} 892 893std::string common_peg_arena::dump_impl (common_peg_parser_id id , 894 std::set < common_peg_parser_id > & visited )const { 895// Check for cycles 896if (visited .count (id )) { 897return "[cycle]" ; 898 } 899visited .insert (id ); 900 901const auto & parser = parsers_ .at (id ); 902 903return std::visit ([this ,& visited ](const auto & p )-> std::string { 904using T = std::decay_t < decltype(p )> ; 905 906if constexpr (std::is_same_v < T ,common_peg_epsilon_parser > ) { 907return "Epsilon" ; 908 }else if constexpr (std::is_same_v < T ,common_peg_start_parser > ) { 909return "Start" ; 910 }else if constexpr (std::is_same_v < T ,common_peg_end_parser > ) { 911return "End" ; 912 }else if constexpr (std::is_same_v < T ,common_peg_literal_parser > ) { 913return "Literal(" + p .literal + ")" ; 914 }else if constexpr (std::is_same_v < T ,common_peg_sequence_parser > ) { 915 std::vector < std::string > parts ; 916for (const auto & child :p .children ) { 917parts .push_back (dump_impl (child ,visited )); 918 } 919return "Sequence(" + string_join (parts ,", " )+ ")" ; 920 }else if constexpr (std::is_same_v < T ,common_peg_choice_parser > ) { 921 std::vector < std::string > parts ; 922for (const auto & child :p .children ) { 923parts .push_back (dump_impl (child ,visited )); 924 } 925return "Choice(" + string_join (parts ,", " )+ ")" ; 926 }else if constexpr (std::is_same_v < T ,common_peg_repetition_parser > ) { 927if (p .max_count == -1 ) { 928return "Repetition(" + dump_impl (p .child ,visited )+ ", " + std::to_string (p .min_count )+ 929", unbounded)" ; 930 } 931return "Repetition(" + dump_impl (p .child ,visited )+ ", " + std::to_string (p .min_count )+ ", " + std::to_string (p .max_count )+ ")" ; 932 }else if constexpr (std::is_same_v < T ,common_peg_and_parser > ) { 933return "And(" + dump_impl (p .child ,visited )+ ")" ; 934 }else if constexpr (std::is_same_v < T ,common_peg_not_parser > ) { 935return "Not(" + dump_impl (p .child ,visited )+ ")" ; 936 }else if constexpr (std::is_same_v < T ,common_peg_atomic_parser > ) { 937return "Atomic(" + dump_impl (p .child ,visited )+ ")" ; 938 }else if constexpr (std::is_same_v < T ,common_peg_gbnf_parser > ) { 939return "Gbnf(" + p .grammar + ", " + dump_impl (p .child ,visited )+ ")" ; 940 }else if constexpr (std::is_same_v < T ,common_peg_ac_parser > ) { 941return "Ac(" + string_join (p .delimiters ," | " )+ ", " + dump_impl (p .child ,visited )+ ")" ; 942 }else if constexpr (std::is_same_v < T ,common_peg_any_parser > ) { 943return "Any" ; 944 }else if constexpr (std::is_same_v < T ,common_peg_space_parser > ) { 945return "Space" ; 946 }else if constexpr (std::is_same_v < T ,common_peg_chars_parser > ) { 947if (p .max_count == -1 ) { 948return "CharRepeat(" + p .pattern + ", " + std::to_string (p .min_count )+ ", unbounded)" ; 949 } 950return "CharRepeat(" + p .pattern + ", " + std::to_string (p .min_count )+ ", " + std::to_string (p .max_count )+ ")" ; 951 }else if constexpr (std::is_same_v < T ,common_peg_string_parser > ) { 952return "String(" + std::string (1 ,p .delimiter )+ ")" ; 953 }else if constexpr (std::is_same_v < T ,common_peg_until_parser > ) { 954return "Until(" + string_join (p .delimiters ," | " )+ ")" ; 955 }else if constexpr (std::is_same_v < T ,common_peg_schema_parser > ) { 956return "Schema(" + dump_impl (p .child ,visited )+ ", " + (p .node ? common_chat_schema::kind_name (p .node -> kind ()) :"null" )+ ")" ; 957 }else if constexpr (std::is_same_v < T ,common_peg_rule_parser > ) { 958return "Rule(" + p .name + ", " + dump_impl (p .child ,visited )+ ")" ; 959 }else if constexpr (std::is_same_v < T ,common_peg_ref_parser > ) { 960return "Ref(" + p .name + ")" ; 961 }else if constexpr (std::is_same_v < T ,common_peg_tag_parser > ) { 962return "Tag(" + p .tag + ", " + dump (p .child )+ ")" ; 963 }else if constexpr (std::is_same_v < T ,common_peg_atomic_parser > ) { 964return "Atomic(" + dump (p .child )+ ")" ; 965 }else { 966return "Unknown" ; 967 } 968 },parser ); 969} 970 971common_peg_parser & common_peg_parser::operator= (const common_peg_parser & other ) { 972id_ = other .id_ ; 973return * this ; 974} 975 976common_peg_parser & common_peg_parser::operator+= (const common_peg_parser & other ) { 977id_ = builder_ .sequence ({id_ ,other .id_ }); 978return * this ; 979} 980 981common_peg_parser & common_peg_parser::operator|=(const common_peg_parser & other ) { 982id_ = builder_ .choice ({id_ ,other .id_ }); 983return * this ; 984} 985 986common_peg_parser common_peg_parser::operator+ (const common_peg_parser & other )const { 987return builder_ .sequence ({id_ ,other .id_ }); 988} 989 990common_peg_parser common_peg_parser::operator|(const common_peg_parser & other )const { 991return builder_ .choice ({id_ ,other .id_ }); 992} 993 994common_peg_parser common_peg_parser::operator<<(const common_peg_parser & other )const { 995return builder_ .sequence ({id_ ,builder_ .space (),other .id_ }); 996} 997 998common_peg_parser common_peg_parser::operator+ (const char * str )const { 999return * this + builder_ .literal (str ); 1000} 1001 1002common_peg_parser common_peg_parser::operator+ (const std::string & str )const { 1003return * this + builder_ .literal (str ); 1004} 1005 1006common_peg_parser common_peg_parser::operator<<(const char * str )const { 1007return * this <<builder_ .literal (str ); 1008} 1009 1010common_peg_parser common_peg_parser::operator<<(const std::string & str )const { 1011return * this <<builder_ .literal (str ); 1012} 1013 1014common_peg_parser common_peg_parser::operator|(const char * str )const { 1015return * this |builder_ .literal (str ); 1016} 1017 1018common_peg_parser common_peg_parser::operator|(const std::string & str )const { 1019return * this |builder_ .literal (str ); 1020} 1021 1022common_peg_parser operator+ (const char * str ,const common_peg_parser & p ) { 1023return p .builder ().literal (str )+ p ; 1024} 1025 1026common_peg_parser operator+ (const std::string & str ,const common_peg_parser & p ) { 1027return operator + (str .c_str (),p ); 1028} 1029 1030common_peg_parser operator<<(const char * str ,const common_peg_parser & p ) { 1031return p .builder ().literal (str ) <<p ; 1032} 1033 1034common_peg_parser operator<<(const std::string & str ,const common_peg_parser & p ) { 1035return operator <<(str .c_str (),p ); 1036} 1037 1038common_peg_parser operator|(const char * str ,const common_peg_parser & p ) { 1039return p .builder ().literal (str ) |p ; 1040} 1041 1042common_peg_parser operator|(const std::string & str ,const common_peg_parser & p ) { 1043return operator |(str .c_str (),p ); 1044} 1045 1046static std::string rule_name (const std::string & name ) { 1047static const std::regex invalid_rule_chars_re ("[^a-zA-Z0-9-]+" ); 1048return std::regex_replace (name ,invalid_rule_chars_re ,"-" ); 1049} 1050 1051common_peg_parser_builder::common_peg_parser_builder () {} 1052 1053common_peg_parser common_peg_parser_builder::sequence (const std::vector < common_peg_parser_id > & parsers ) { 1054// Flatten nested sequences 1055 std::vector < common_peg_parser_id > flattened ; 1056for (const auto & p :parsers ) { 1057const auto & parser = arena_ .get (p ); 1058if (auto seq = std::get_if < common_peg_sequence_parser > (& parser )) { 1059flattened .insert (flattened .end (),seq -> children .begin (),seq -> children .end ()); 1060 }else { 1061flattened .push_back (p ); 1062 } 1063 } 1064return wrap (arena_ .add_parser (common_peg_sequence_parser {flattened })); 1065} 1066 1067common_peg_parser common_peg_parser_builder::sequence (const std::vector < common_peg_parser > & parsers ) { 1068 std::vector < common_peg_parser_id > ids ; 1069ids .reserve (parsers .size ()); 1070for (const auto & p :parsers ) { 1071ids .push_back (p .id ()); 1072 } 1073return sequence (ids ); 1074} 1075 1076common_peg_parser common_peg_parser_builder::sequence (std::initializer_list < common_peg_parser > parsers ) { 1077 std::vector < common_peg_parser_id > ids ; 1078ids .reserve (parsers .size ()); 1079for (const auto & p :parsers ) { 1080ids .push_back (p .id ()); 1081 } 1082return sequence (ids ); 1083} 1084 1085common_peg_parser common_peg_parser_builder::choice (const std::vector < common_peg_parser_id > & parsers ) { 1086// Flatten nested choices 1087 std::vector < common_peg_parser_id > flattened ; 1088for (const auto & p :parsers ) { 1089const auto & parser = arena_ .get (p ); 1090if (auto choice = std::get_if < common_peg_choice_parser > (& parser )) { 1091flattened .insert (flattened .end (),choice -> children .begin (),choice -> children .end ()); 1092 }else { 1093flattened .push_back (p ); 1094 } 1095 } 1096return wrap (arena_ .add_parser (common_peg_choice_parser {flattened })); 1097} 1098 1099common_peg_parser common_peg_parser_builder::choice (const std::vector < common_peg_parser > & parsers ) { 1100 std::vector < common_peg_parser_id > ids ; 1101ids .reserve (parsers .size ()); 1102for (const auto & p :parsers ) { 1103ids .push_back (p .id ()); 1104 } 1105return choice (ids ); 1106} 1107 1108common_peg_parser common_peg_parser_builder::choice (std::initializer_list < common_peg_parser > parsers ) { 1109 std::vector < common_peg_parser_id > ids ; 1110ids .reserve (parsers .size ()); 1111for (const auto & p :parsers ) { 1112ids .push_back (p .id ()); 1113 } 1114return choice (ids ); 1115} 1116 1117common_peg_parser common_peg_parser_builder::chars (const std::string & classes ,int min ,int max ) { 1118auto [ranges ,negated ]= parse_char_classes (classes ); 1119return wrap (arena_ .add_parser (common_peg_chars_parser {classes ,ranges ,negated ,min ,max })); 1120} 1121 1122common_peg_parser common_peg_parser_builder::schema (const common_peg_parser & p ,const std::string & name ,common_chat_schema_document_ptr doc ,const common_chat_schema & node ,bool raw ) { 1123return wrap (arena_ .add_parser (common_peg_schema_parser {p .id (),name , std::move (doc ),& node ,raw })); 1124} 1125 1126common_peg_parser common_peg_parser_builder::schema (const common_peg_parser & p ,const std::string & name ,const common_json & schema ,bool raw ) { 1127auto doc = std::make_shared < const common_chat_schema_document > (common_chat_schema_from_json (schema )); 1128return this -> schema (p ,name ,doc ,* doc -> root ,raw ); 1129} 1130 1131common_peg_parser common_peg_parser_builder::rule (const std::string & name ,const common_peg_parser & p ,bool trigger ) { 1132auto clean_name = rule_name (name ); 1133auto rule_id = arena_ .add_parser (common_peg_rule_parser {clean_name ,p .id (),trigger }); 1134arena_ .add_rule (clean_name ,rule_id ); 1135return ref (clean_name ); 1136} 1137 1138common_peg_parser common_peg_parser_builder::rule (const std::string & name ,const std::function < common_peg_parser ()> & builder_fn ,bool trigger ) { 1139auto clean_name = rule_name (name ); 1140if (arena_ .has_rule (clean_name )) { 1141return ref (clean_name ); 1142 } 1143 1144// Create placeholder rule to allow recursive references 1145auto placeholder = any ();// Temporary placeholder 1146auto placeholder_rule_id = arena_ .add_parser (common_peg_rule_parser {clean_name ,placeholder .id (),trigger }); 1147arena_ .add_rule (clean_name ,placeholder_rule_id ); 1148 1149// Build the actual parser 1150auto parser = builder_fn (); 1151 1152// Replace placeholder with actual rule 1153auto rule_id = arena_ .add_parser (common_peg_rule_parser {clean_name ,parser .id (),trigger }); 1154arena_ .rules_ [clean_name ]= rule_id ; 1155 1156return ref (clean_name ); 1157} 1158 1159void common_peg_parser_builder::set_root (const common_peg_parser & p ) { 1160arena_ .set_root (p .id ()); 1161} 1162 1163common_peg_arena common_peg_parser_builder::build () { 1164arena_ .resolve_refs (); 1165return std::move (arena_ ); 1166} 1167 1168// String primitives 1169 1170common_peg_parser common_peg_parser_builder::string_content (char delimiter ) { 1171return wrap (arena_ .add_parser (common_peg_string_parser {delimiter })); 1172} 1173 1174common_peg_parser common_peg_parser_builder::double_quoted_string () { 1175return rule ("double-quoted-string" , [this ]() { 1176return sequence ({literal ("\"" ),string_content ('"' ),literal ("\"" )}); 1177 }); 1178} 1179 1180common_peg_parser common_peg_parser_builder::single_quoted_string () { 1181return rule ("single-quoted-string" , [this ]() { 1182return sequence ({literal ("'" ),string_content ('\'' ),literal ("'" )}); 1183 }); 1184} 1185 1186common_peg_parser common_peg_parser_builder::quoted_string () { 1187return rule ("quoted-string" , [this ]() { 1188return choice ({double_quoted_string (),single_quoted_string ()}); 1189 }); 1190} 1191 1192// JSON parsers 1193 1194common_peg_parser common_peg_parser_builder::json_number () { 1195return rule ("json-number" , [this ]() { 1196auto digit1_9 = chars ("[1-9]" ,1 ,1 ); 1197auto digits = chars ("[0-9]" ); 1198auto int_part = choice ({literal ("0" ),sequence ({digit1_9 ,chars ("[0-9]" ,0 ,-1 )})}); 1199auto frac = sequence ({literal ("." ),digits }); 1200auto exp = sequence ({choice ({literal ("e" ),literal ("E" )}),optional (chars ("[+-]" ,1 ,1 )),digits }); 1201// Negative lookahead: only commit the number when the next character can't extend it. 1202// At EOF in partial mode, chars returns NEED_MORE → negate propagates NEED_MORE → number not committed. 1203// This prevents premature commits of partial numbers (e.g. "3" when "3.14" is incoming). 1204auto not_number_continuation = negate (chars ("[0-9.eE+-]" ,1 ,1 )); 1205return sequence ({optional (literal ("-" )),int_part ,optional (frac ),optional (exp ),not_number_continuation }); 1206 }); 1207} 1208 1209common_peg_parser common_peg_parser_builder::json_string () { 1210return rule ("json-string" , [this ]() { 1211return sequence ({literal ("\"" ),string_content ('"' ),literal ("\"" )}); 1212 }); 1213} 1214 1215common_peg_parser common_peg_parser_builder::json_bool () { 1216return rule ("json-bool" , [this ]() { 1217return choice ({literal ("true" ),literal ("false" )}); 1218 }); 1219} 1220 1221common_peg_parser common_peg_parser_builder::json_null () { 1222return rule ("json-null" , [this ]() { 1223return literal ("null" ); 1224 }); 1225} 1226 1227common_peg_parser common_peg_parser_builder::json_object () { 1228return rule ("json-object" , [this ]() { 1229auto ws = space (); 1230auto member = sequence ({json_string (),ws ,literal (":" ),ws ,json ()}); 1231auto members = sequence ({member ,zero_or_more (sequence ({ws ,literal ("," ),ws ,member }))}); 1232return sequence ({ 1233literal ("{" ), 1234ws , 1235choice ({ 1236literal ("}" ), 1237sequence ({members ,ws ,literal ("}" )}) 1238 }) 1239 }); 1240 }); 1241} 1242 1243common_peg_parser common_peg_parser_builder::json_array () { 1244return rule ("json-array" , [this ]() { 1245auto ws = space (); 1246auto elements = sequence ({json (),zero_or_more (sequence ({ws ,literal ("," ),ws ,json ()}))}); 1247return sequence ({ 1248literal ("[" ), 1249ws , 1250choice ({ 1251literal ("]" ), 1252sequence ({elements ,ws ,literal ("]" )}) 1253 }) 1254 }); 1255 }); 1256} 1257 1258common_peg_parser common_peg_parser_builder::json () { 1259return rule ("json-value" , [this ]() { 1260return choice ({ 1261json_object (), 1262json_array (), 1263json_string (), 1264json_number (), 1265json_bool (), 1266json_null () 1267 }); 1268 }); 1269} 1270 1271common_peg_parser common_peg_parser_builder::python_string () { 1272return rule ("python-string" , [this ]() { 1273return choice ({double_quoted_string (),single_quoted_string ()}); 1274 }); 1275} 1276 1277common_peg_parser common_peg_parser_builder::python_number () { 1278return json_number (); 1279} 1280 1281common_peg_parser common_peg_parser_builder::python_bool () { 1282return rule ("python-bool" , [this ]() { 1283return choice ({literal ("True" ),literal ("False" )}); 1284 }); 1285} 1286 1287common_peg_parser common_peg_parser_builder::python_null () { 1288return rule ("python-none" , [this ]() { 1289return literal ("None" ); 1290 }); 1291} 1292 1293common_peg_parser common_peg_parser_builder::python_dict () { 1294return rule ("python-dict" , [this ]() { 1295auto ws = space (); 1296auto member = sequence ({python_string (),ws ,literal (":" ),ws ,python_value ()}); 1297auto members = sequence ({member ,zero_or_more (sequence ({ws ,literal ("," ),ws ,member }))}); 1298return sequence ({ 1299literal ("{" ), 1300ws , 1301choice ({ 1302literal ("}" ), 1303sequence ({members ,ws ,literal ("}" )}) 1304 }), 1305ws 1306 }); 1307 }); 1308} 1309 1310common_peg_parser common_peg_parser_builder::python_array () { 1311return rule ("python-array" , [this ]() { 1312auto ws = space (); 1313auto elements = sequence ({python_value (),zero_or_more (sequence ({literal ("," ),ws ,python_value ()}))}); 1314return sequence ({ 1315literal ("[" ), 1316ws , 1317choice ({ 1318literal ("]" ), 1319sequence ({elements ,ws ,literal ("]" )}) 1320 }), 1321ws 1322 }); 1323 }); 1324} 1325 1326common_peg_parser common_peg_parser_builder::python_value () { 1327return rule ("python-value" , [this ]() { 1328return choice ({ 1329python_dict (), 1330python_array (), 1331python_string (), 1332python_number (), 1333python_bool (), 1334python_null () 1335 }); 1336 }); 1337} 1338 1339common_peg_parser common_peg_parser_builder::marker () { 1340auto sharp_bracket_parser = literal ("<" )+ until (">" )+ literal (">" ); 1341auto square_bracket_parser = literal ("[" )+ until ("]" )+ literal ("]" ); 1342return choice ({sharp_bracket_parser ,square_bracket_parser }); 1343} 1344 1345common_peg_parser common_peg_parser_builder::json_member (const std::string & key ,const common_peg_parser & p ) { 1346auto ws = space (); 1347return sequence ({ 1348literal ("\"" + key + "\"" ), 1349ws , 1350literal (":" ), 1351ws , 1352p , 1353 }); 1354} 1355 1356common_peg_parser common_peg_parser_builder::ac (const common_peg_parser & p ,const std::vector < std::string > & delimiters ) { 1357if (delimiters .empty ()) { 1358throw std::runtime_error ("ac parser requires at least one delimiter" ); 1359 } 1360return add (common_peg_ac_parser {p ,delimiters }); 1361} 1362 1363static std::string gbnf_escape_char_class (uint32_t c ) { 1364if (c == '-' || c == ']' || c == '[' || c == '\\' ) { 1365return "\\" + std::string (1 , (char )c ); 1366 } 1367// Escape whitespace control characters 1368if (c == '\n' ) { 1369return "\\n" ; 1370 } 1371if (c == '\t' ) { 1372return "\\t" ; 1373 } 1374if (c == '\r' ) { 1375return "\\r" ; 1376 } 1377 1378// Printable ASCII 1379if (c >=0x20 && c <=0x7E ) { 1380return std::string (1 , (char )c ); 1381 } 1382 1383// Hex escape 1384char buf [16 ]; 1385const char * hex = "0123456789ABCDEF" ; 1386 1387if (c <=0xFF ) { 1388buf [0 ]= '\\' ; 1389buf [1 ]= 'x' ; 1390buf [2 ]= hex [(c >>4 )& 0xF ]; 1391buf [3 ]= hex [c & 0xF ]; 1392buf [4 ]= '\0' ; 1393 }else if (c <=0xFFFF ) { 1394buf [0 ]= '\\' ; 1395buf [1 ]= 'u' ; 1396buf [2 ]= hex [(c >>12 )& 0xF ]; 1397buf [3 ]= hex [(c >>8 )& 0xF ]; 1398buf [4 ]= hex [(c >>4 )& 0xF ]; 1399buf [5 ]= hex [c & 0xF ]; 1400buf [6 ]= '\0' ; 1401 }else { 1402buf [0 ]= '\\' ; 1403buf [1 ]= 'U' ; 1404for (int i = 0 ;i < 8 ;i ++ ) { 1405buf [2 + i ]= hex [(c >> ((7 - i )* 4 ))& 0xF ]; 1406 } 1407buf [10 ]= '\0' ; 1408 } 1409 1410return std::string (buf ); 1411} 1412 1413static std::string gbnf_char_class (const std::vector < uint32_t > & chars ,bool negate ) { 1414 std::string s = negate ?"[^" :"[" ; 1415for (uint32_t ch :chars ) { 1416s += gbnf_escape_char_class (ch ); 1417 } 1418return s + "]" ; 1419} 1420 1421static std::string gbnf_ac_grammar ( 1422const common_grammar_builder & builder , 1423const std::string & prefix , 1424const std::vector < std::string > & strings , 1425const std::function < std::string (const std::vector < uint32_t > & , 1426const std::map < size_t , std::vector < uint32_t >> & , 1427const std::vector < uint32_t > & , 1428const std::function < std::string (size_t )> & )> & build_rule ) { 1429common_aho_corasick ac (strings ); 1430 1431auto state_name = [& ](size_t s )-> std::string { 1432if (s == 0 ) { 1433return prefix ; 1434 } 1435 std::string num = std::to_string (s ); 1436num = num .size ()== 1 ? ("0" + num ) :num ; 1437return prefix + "-" + num ; 1438 }; 1439 1440for (size_t q = 0 ;q < ac .num_states ();q ++ ) { 1441if (ac .is_terminal (q )) { 1442continue ;// match states 1443 } 1444 1445 std::map < size_t , std::vector < uint32_t >> buckets ; 1446 std::vector < uint32_t > completing ;// chars that complete a delimiter 1447 std::vector < uint32_t > specific ;// chars with an explicit transition 1448for (uint32_t c :ac .alphabet ) { 1449size_t d = ac .next (q ,c ); 1450if (ac .is_terminal (d )) { 1451completing .push_back (c ); 1452specific .push_back (c ); 1453 }else if (d != 0 ) { 1454buckets [d ].push_back (c );// specific non-root destination 1455specific .push_back (c ); 1456 } 1457 } 1458 1459builder .add_rule (state_name (q ),build_rule (completing ,buckets ,specific ,state_name )); 1460 } 1461 1462// An empty delimiter makes the start state terminal. Emit an entry rule 1463// that matches the empty string so the returned reference stays valid. 1464if (ac .is_terminal (0 )) { 1465builder .add_rule (prefix ,"|" ); 1466 } 1467 1468return state_name (0 ); 1469} 1470 1471// GBNF grammar matching strings that contain no string in `strings` as a 1472// substring. Emits the complement of an Aho-Corasick automaton DFA and returns 1473// the start state rule name. 1474// 1475// ref: https://github.com/ggml-org/llama.cpp/pull/24839 1476static std::string gbnf_excluding_grammar (const common_grammar_builder & builder , 1477const std::string & prefix , 1478const std::vector < std::string > & strings ) { 1479return gbnf_ac_grammar (builder ,prefix ,strings , 1480 [](const std::vector < uint32_t > & /*completing*/ , 1481const std::map < size_t , std::vector < uint32_t >> & buckets , 1482const std::vector < uint32_t > & specific , 1483const std::function < std::string (size_t )> & state_name ) { 1484// every state is accepting and completing chars get no 1485// alternative, so a forbidden string can never be matched 1486 std::string rhs = "|" ; 1487for (const auto & [d ,chars ] :buckets ) { 1488rhs += " " + gbnf_char_class (chars , false)+ " " + state_name (d )+ " |" ; 1489 } 1490rhs += " " + gbnf_char_class (specific , true)+ " " + state_name (0 ); 1491return rhs ; 1492 }); 1493} 1494 1495// GBNF grammar matching everything up to and including the first occurrence of 1496// any string in `strings`. Emits the Aho-Corasick automaton DFA and returns 1497// the start state rule name. 1498static std::string gbnf_including_grammar (const common_grammar_builder & builder , 1499const std::string & prefix , 1500const std::vector < std::string > & strings ) { 1501return gbnf_ac_grammar (builder ,prefix ,strings , 1502 [](const std::vector < uint32_t > & completing , 1503const std::map < size_t , std::vector < uint32_t >> & buckets , 1504const std::vector < uint32_t > & specific , 1505const std::function < std::string (size_t )> & state_name ) { 1506 std::vector < std::string > alts ; 1507if (!completing .empty ()) { 1508alts .push_back (gbnf_char_class (completing , false));// terminate on match 1509 } 1510for (const auto & [d ,chars ] :buckets ) { 1511alts .push_back (gbnf_char_class (chars , false)+ " " + state_name (d )); 1512 } 1513// every other character keeps scanning from the start state 1514alts .push_back (gbnf_char_class (specific , true)+ " " + state_name (0 )); 1515return string_join (alts ," | " ); 1516 }); 1517} 1518 1519static std::set < std::string > collect_reachable_rules ( 1520const common_peg_arena & arena , 1521const common_peg_parser_id & rule 1522) { 1523 std::set < std::string > reachable ; 1524 std::set < std::string > visited ; 1525 1526 std::function < void (common_peg_parser_id )> visit = [& ](common_peg_parser_id id ) { 1527const auto & parser = arena .get (id ); 1528 1529 std::visit ([& ](const auto & p ) { 1530using T = std::decay_t < decltype(p )> ; 1531 1532if constexpr (std::is_same_v < T ,common_peg_epsilon_parser > || 1533 std::is_same_v < T ,common_peg_start_parser > || 1534 std::is_same_v < T ,common_peg_end_parser > || 1535 std::is_same_v < T ,common_peg_until_parser > || 1536 std::is_same_v < T ,common_peg_literal_parser > || 1537 std::is_same_v < T ,common_peg_chars_parser > || 1538 std::is_same_v < T ,common_peg_space_parser > || 1539 std::is_same_v < T ,common_peg_any_parser > || 1540 std::is_same_v < T ,common_peg_string_parser > ) { 1541// These parsers do not have any children 1542 }else if constexpr (std::is_same_v < T ,common_peg_sequence_parser > ) { 1543for (auto child :p .children ) { 1544visit (child ); 1545 } 1546 }else if constexpr (std::is_same_v < T ,common_peg_choice_parser > ) { 1547for (auto child :p .children ) { 1548visit (child ); 1549 } 1550 }else if constexpr (std::is_same_v < T ,common_peg_repetition_parser > || 1551 std::is_same_v < T ,common_peg_and_parser > || 1552 std::is_same_v < T ,common_peg_not_parser > || 1553 std::is_same_v < T ,common_peg_tag_parser > || 1554 std::is_same_v < T ,common_peg_atomic_parser > || 1555 std::is_same_v < T ,common_peg_gbnf_parser > || 1556 std::is_same_v < T ,common_peg_ac_parser > || 1557 std::is_same_v < T ,common_peg_schema_parser > ) { 1558visit (p .child ); 1559 }else if constexpr (std::is_same_v < T ,common_peg_rule_parser > ) { 1560if (visited .find (p .name )== visited .end ()) { 1561visited .insert (p .name ); 1562reachable .insert (p .name ); 1563visit (p .child ); 1564 } 1565 }else if constexpr (std::is_same_v < T ,common_peg_ref_parser > ) { 1566// Traverse rules so we pick up everything 1567auto referenced_rule = arena .get_rule (p .name ); 1568visit (referenced_rule ); 1569 }else { 1570 static_assert(is_always_false_v < T > ); 1571 } 1572 },parser ); 1573 }; 1574 1575visit (rule ); 1576return reachable ; 1577} 1578 1579// GBNF generation implementation 1580void common_peg_arena::build_grammar (const common_grammar_builder & builder ,bool lazy )const { 1581// A raw string value is parsed by the child rather than constrained by the schema 1582auto schema_delegates = [](const common_peg_schema_parser & s )-> bool { 1583return !s .node || (s .raw && s .node -> may_be_string ()); 1584 }; 1585 1586// Unwrap the parser so we can properly check if it's a sequence or choice 1587auto effective_parser = [& ](common_peg_parser_id id )-> const common_peg_parser_variant & { 1588while (true) { 1589const auto & p = parsers_ .at (id ); 1590if (const auto * tag = std::get_if < common_peg_tag_parser > (& p )) { 1591id = tag -> child ; 1592 }else if (const auto * atomic = std::get_if < common_peg_atomic_parser > (& p )) { 1593id = atomic -> child ; 1594 }else if (const auto * schema = std::get_if < common_peg_schema_parser > (& p )) { 1595if (schema_delegates (* schema )) { 1596id = schema -> child ; 1597 }else { 1598return p ; 1599 } 1600 }else { 1601return p ; 1602 } 1603 } 1604 }; 1605 1606// Generate GBNF for a parser 1607 std::function < std::string (common_peg_parser_id )> to_gbnf = [& ](common_peg_parser_id id )-> std::string { 1608const auto & parser = parsers_ .at (id ); 1609 1610return std::visit ([& ](const auto & p )-> std::string { 1611using T = std::decay_t < decltype(p )> ; 1612 1613if constexpr (std::is_same_v < T ,common_peg_epsilon_parser > || 1614 std::is_same_v < T ,common_peg_start_parser > || 1615 std::is_same_v < T ,common_peg_end_parser > ) { 1616return "" ; 1617 }else if constexpr (std::is_same_v < T ,common_peg_literal_parser > ) { 1618return gbnf_format_literal (p .literal ); 1619 }else if constexpr (std::is_same_v < T ,common_peg_sequence_parser > ) { 1620 std::string s ; 1621for (const auto & child :p .children ) { 1622auto child_gbnf = to_gbnf (child ); 1623if (child_gbnf .empty ()) { 1624continue ; 1625 } 1626if (!s .empty ()) { 1627s += " " ; 1628 } 1629const auto & child_parser = effective_parser (child ); 1630if (std::holds_alternative < common_peg_choice_parser > (child_parser )|| 1631 std::holds_alternative < common_peg_sequence_parser > (child_parser )) { 1632s += "(" + child_gbnf + ")" ; 1633 }else { 1634s += child_gbnf ; 1635 } 1636 } 1637return s ; 1638 }else if constexpr (std::is_same_v < T ,common_peg_choice_parser > ) { 1639 std::string s ; 1640for (const auto & child :p .children ) { 1641if (!s .empty ()) { 1642s += " | " ; 1643 } 1644auto child_gbnf = to_gbnf (child ); 1645const auto & child_parser = effective_parser (child ); 1646if (std::holds_alternative < common_peg_choice_parser > (child_parser )) { 1647s += "(" + child_gbnf + ")" ; 1648 }else { 1649s += child_gbnf ; 1650 } 1651 } 1652return s ; 1653 }else if constexpr (std::is_same_v < T ,common_peg_repetition_parser > ) { 1654auto child_gbnf = to_gbnf (p .child ); 1655const auto & child_parser = effective_parser (p .child ); 1656if (std::holds_alternative < common_peg_choice_parser > (child_parser )|| 1657 std::holds_alternative < common_peg_sequence_parser > (child_parser )) { 1658child_gbnf = "(" + child_gbnf + ")" ; 1659 } 1660if (p .min_count == 0 && p .max_count == 1 ) { 1661return child_gbnf + "?" ; 1662 } 1663if (p .min_count == 0 && p .max_count == -1 ) { 1664return child_gbnf + "*" ; 1665 } 1666if (p .min_count == 1 && p .max_count == -1 ) { 1667return child_gbnf + "+" ; 1668 } 1669if (p .max_count == -1 ) { 1670return child_gbnf + "{" + std::to_string (p .min_count )+ ",}" ; 1671 } 1672if (p .min_count == p .max_count ) { 1673if (p .min_count == 1 ) { 1674return child_gbnf ; 1675 } 1676return child_gbnf + "{" + std::to_string (p .min_count )+ "}" ; 1677 } 1678return child_gbnf + "{" + std::to_string (p .min_count )+ "," + std::to_string (p .max_count )+ "}" ; 1679 }else if constexpr (std::is_same_v < T ,common_peg_and_parser > || std::is_same_v < T ,common_peg_not_parser > ) { 1680return "" ;// Lookahead not supported in GBNF 1681 }else if constexpr (std::is_same_v < T ,common_peg_any_parser > ) { 1682return "." ; 1683 }else if constexpr (std::is_same_v < T ,common_peg_space_parser > ) { 1684return "space" ; 1685 }else if constexpr (std::is_same_v < T ,common_peg_chars_parser > ) { 1686 std::string result = p .pattern ; 1687if (p .min_count == 0 && p .max_count == 1 ) { 1688return result + "?" ; 1689 } 1690if (p .min_count == 0 && p .max_count == -1 ) { 1691return result + "*" ; 1692 } 1693if (p .min_count == 1 && p .max_count == -1 ) { 1694return result + "+" ; 1695 } 1696if (p .max_count == -1 ) { 1697return result + "{" + std::to_string (p .min_count )+ ",}" ; 1698 } 1699if (p .min_count == p .max_count ) { 1700if (p .min_count == 1 ) { 1701return result ; 1702 } 1703return result + "{" + std::to_string (p .min_count )+ "}" ; 1704 } 1705return result + "{" + std::to_string (p .min_count )+ "," + std::to_string (p .max_count )+ "}" ; 1706 }else if constexpr (std::is_same_v < T ,common_peg_string_parser > ) { 1707const std::string delim (1 ,p .delimiter ); 1708return R"(( [^)" + delim + R"(\\] | "\\" ( [)" + delim + R"(\\/ bfnrt] | "u" [0-9a-fA-F]{4} ) )*)" ; 1709 }else if constexpr (std::is_same_v < T ,common_peg_until_parser > ) { 1710if (p .delimiters .empty ()) { 1711return ".*" ; 1712 } 1713return gbnf_excluding_grammar (builder ,"until-" + std::to_string (id ),p .delimiters ); 1714 }else if constexpr (std::is_same_v < T ,common_peg_schema_parser > ) { 1715if (schema_delegates (p )) { 1716return to_gbnf (p .child ); 1717 } 1718return builder .add_schema (p .name ,* p .node ); 1719 }else if constexpr (std::is_same_v < T ,common_peg_rule_parser > ) { 1720return p .name ; 1721 }else if constexpr (std::is_same_v < T ,common_peg_ref_parser > ) { 1722// Refs should not exist after flattening, but kept just in case 1723return p .name ; 1724 }else if constexpr (std::is_same_v < T ,common_peg_tag_parser > ) { 1725return to_gbnf (p .child ); 1726 }else if constexpr (std::is_same_v < T ,common_peg_atomic_parser > ) { 1727return to_gbnf (p .child ); 1728 }else if constexpr (std::is_same_v < T ,common_peg_gbnf_parser > ) { 1729return p .grammar ; 1730 }else if constexpr (std::is_same_v < T ,common_peg_ac_parser > ) { 1731return gbnf_including_grammar (builder ,"ac-" + std::to_string (id ),p .delimiters ); 1732 }else { 1733 static_assert(is_always_false_v < T > ); 1734 } 1735 },parser ); 1736 }; 1737 1738// Collect reachable rules 1739 std::set < std::string > reachable_rules ; 1740 1741if (lazy ) { 1742// Collect rules reachable from trigger rules 1743for (const auto & [name ,id ] :rules_ ) { 1744const auto & parser = parsers_ .at (id ); 1745if (auto rule = std::get_if < common_peg_rule_parser > (& parser )) { 1746if (rule -> trigger ) { 1747// Mark trigger as reachable and visit it 1748reachable_rules .insert (name ); 1749auto add_rules = collect_reachable_rules (* this ,id ); 1750reachable_rules .insert (add_rules .begin (),add_rules .end ()); 1751 } 1752 } 1753 } 1754 }else { 1755// Collect rules reachable from root 1756reachable_rules = collect_reachable_rules (* this ,root_ ); 1757 } 1758 1759// Create GBNF rules for all reachable rules 1760for (const auto & [name ,rule_id ] :rules_ ) { 1761if (reachable_rules .find (name )== reachable_rules .end ()) { 1762continue ; 1763 } 1764 1765const auto & parser = parsers_ .at (rule_id ); 1766if (auto rule = std::get_if < common_peg_rule_parser > (& parser )) { 1767builder .add_rule (rule -> name ,to_gbnf (rule -> child )); 1768 } 1769 } 1770 1771if (lazy ) { 1772// Generate root rule from trigger rules only 1773 std::vector < std::string > trigger_names ; 1774for (const auto & [name ,rule_id ] :rules_ ) { 1775const auto & parser = parsers_ .at (rule_id ); 1776if (auto rule = std::get_if < common_peg_rule_parser > (& parser )) { 1777if (rule -> trigger ) { 1778trigger_names .push_back (rule -> name ); 1779 } 1780 } 1781 } 1782 1783// Sort for predictable order 1784 std::sort (trigger_names .begin (),trigger_names .end ()); 1785builder .add_rule ("root" ,string_join (trigger_names ," | " )); 1786 }else if (root_ != COMMON_PEG_INVALID_PARSER_ID ) { 1787builder .add_rule ("root" ,to_gbnf (root_ )); 1788 } 1789} 1790 1791static common_json serialize_parser_variant (const common_peg_parser_variant & variant ) { 1792using json = common_json ; 1793 1794return std::visit ([](const auto & p )-> json { 1795using T = std::decay_t < decltype(p )> ; 1796 1797if constexpr (std::is_same_v < T ,common_peg_epsilon_parser > ) { 1798return json {{"type" ,"epsilon" }}; 1799 }else if constexpr (std::is_same_v < T ,common_peg_start_parser > ) { 1800return json {{"type" ,"start" }}; 1801 }else if constexpr (std::is_same_v < T ,common_peg_end_parser > ) { 1802return json {{"type" ,"end" }}; 1803 }else if constexpr (std::is_same_v < T ,common_peg_literal_parser > ) { 1804return json {{"type" ,"literal" }, {"literal" ,p .literal }}; 1805 }else if constexpr (std::is_same_v < T ,common_peg_sequence_parser > ) { 1806return json {{"type" ,"sequence" }, {"children" ,p .children }}; 1807 }else if constexpr (std::is_same_v < T ,common_peg_choice_parser > ) { 1808return json {{"type" ,"choice" }, {"children" ,p .children }}; 1809 }else if constexpr (std::is_same_v < T ,common_peg_repetition_parser > ) { 1810return json { 1811 {"type" ,"repetition" }, 1812 {"child" ,p .child }, 1813 {"min_count" ,p .min_count }, 1814 {"max_count" ,p .max_count } 1815 }; 1816 }else if constexpr (std::is_same_v < T ,common_peg_and_parser > ) { 1817return json {{"type" ,"and" }, {"child" ,p .child }}; 1818 }else if constexpr (std::is_same_v < T ,common_peg_not_parser > ) { 1819return json {{"type" ,"not" }, {"child" ,p .child }}; 1820 }else if constexpr (std::is_same_v < T ,common_peg_any_parser > ) { 1821return json {{"type" ,"any" }}; 1822 }else if constexpr (std::is_same_v < T ,common_peg_space_parser > ) { 1823return json {{"type" ,"space" }}; 1824 }else if constexpr (std::is_same_v < T ,common_peg_chars_parser > ) { 1825json ranges = json::array (); 1826for (const auto & range :p .ranges ) { 1827ranges .push_back ({{"start" ,range .start }, {"end" ,range .end }}); 1828 } 1829return json { 1830 {"type" ,"chars" }, 1831 {"pattern" ,p .pattern }, 1832 {"ranges" ,ranges }, 1833 {"negated" ,p .negated }, 1834 {"min_count" ,p .min_count }, 1835 {"max_count" ,p .max_count } 1836 }; 1837 }else if constexpr (std::is_same_v < T ,common_peg_string_parser > ) { 1838return json {{"type" ,"string" }, {"delimiter" , std::string (1 ,p .delimiter )}}; 1839 }else if constexpr (std::is_same_v < T ,common_peg_until_parser > ) { 1840return json {{"type" ,"until" }, {"delimiters" ,p .delimiters }}; 1841 }else if constexpr (std::is_same_v < T ,common_peg_schema_parser > ) { 1842return json { 1843 {"type" ,"schema" }, 1844 {"child" ,p .child }, 1845 {"name" ,p .name }, 1846 {"raw" ,p .raw } 1847 }; 1848 }else if constexpr (std::is_same_v < T ,common_peg_rule_parser > ) { 1849return json { 1850 {"type" ,"rule" }, 1851 {"name" ,p .name }, 1852 {"child" ,p .child }, 1853 {"trigger" ,p .trigger } 1854 }; 1855 }else if constexpr (std::is_same_v < T ,common_peg_ref_parser > ) { 1856return json {{"type" ,"ref" }, {"name" ,p .name }}; 1857 }else if constexpr (std::is_same_v < T ,common_peg_atomic_parser > ) { 1858return json {{"type" ,"atomic" }, {"child" ,p .child }}; 1859 }else if constexpr (std::is_same_v < T ,common_peg_tag_parser > ) { 1860return json { 1861 {"type" ,"tag" }, 1862 {"child" ,p .child }, 1863 {"tag" ,p .tag } 1864 }; 1865 }else if constexpr (std::is_same_v < T ,common_peg_gbnf_parser > ) { 1866return json {{"type" ,"gbnf" }, {"child" ,p .child }, {"grammar" ,p .grammar }}; 1867 }else if constexpr (std::is_same_v < T ,common_peg_ac_parser > ) { 1868return json {{"type" ,"ac" }, {"child" ,p .child }, {"delimiters" ,p .delimiters }}; 1869 } 1870 },variant ); 1871} 1872 1873common_json common_peg_arena::to_json ()const { 1874auto parsers = common_json::array (); 1875for (const auto & parser :parsers_ ) { 1876parsers .push_back (serialize_parser_variant (parser )); 1877 } 1878return common_json { 1879 {"parsers" ,parsers }, 1880 {"rules" ,rules_ }, 1881 {"root" ,root_ } 1882 }; 1883} 1884 1885static common_peg_parser_variant deserialize_parser_variant (const common_json & j ) { 1886if (!j .contains ("type" )|| !j ["type" ].is_string ()) { 1887throw std::runtime_error ("Parser variant JSON missing or invalid 'type' field" ); 1888 } 1889 1890 std::string type = j ["type" ]; 1891 1892if (type == "epsilon" ) { 1893return common_peg_epsilon_parser {}; 1894 } 1895if (type == "start" ) { 1896return common_peg_start_parser {}; 1897 } 1898if (type == "end" ) { 1899return common_peg_end_parser {}; 1900 } 1901if (type == "literal" ) { 1902if (!j .contains ("literal" )|| !j ["literal" ].is_string ()) { 1903throw std::runtime_error ("literal parser missing or invalid 'literal' field" ); 1904 } 1905return common_peg_literal_parser {j ["literal" ]}; 1906 } 1907if (type == "sequence" ) { 1908if (!j .contains ("children" )|| !j ["children" ].is_array ()) { 1909throw std::runtime_error ("sequence parser missing or invalid 'children' field" ); 1910 } 1911return common_peg_sequence_parser {j ["children" ].get < std::vector < common_peg_parser_id >> ()}; 1912 } 1913if (type == "choice" ) { 1914if (!j .contains ("children" )|| !j ["children" ].is_array ()) { 1915throw std::runtime_error ("choice parser missing or invalid 'children' field" ); 1916 } 1917return common_peg_choice_parser {j ["children" ].get < std::vector < common_peg_parser_id >> ()}; 1918 } 1919if (type == "repetition" ) { 1920if (!j .contains ("child" )|| !j .contains ("min_count" )|| !j .contains ("max_count" )) { 1921throw std::runtime_error ("repetition parser missing required fields" ); 1922 } 1923return common_peg_repetition_parser { 1924j ["child" ].get < common_peg_parser_id > (), 1925j ["min_count" ].get < int > (), 1926j ["max_count" ].get < int > () 1927 }; 1928 } 1929if (type == "and" ) { 1930if (!j .contains ("child" )) { 1931throw std::runtime_error ("and parser missing 'child' field" ); 1932 } 1933return common_peg_and_parser {j ["child" ].get < common_peg_parser_id > ()}; 1934 } 1935if (type == "not" ) { 1936if (!j .contains ("child" )) { 1937throw std::runtime_error ("not parser missing 'child' field" ); 1938 } 1939return common_peg_not_parser {j ["child" ].get < common_peg_parser_id > ()}; 1940 } 1941if (type == "any" ) { 1942return common_peg_any_parser {}; 1943 } 1944if (type == "space" ) { 1945return common_peg_space_parser {}; 1946 } 1947if (type == "chars" ) { 1948if (!j .contains ("pattern" )|| !j .contains ("ranges" )|| !j .contains ("negated" )|| 1949 !j .contains ("min_count" )|| !j .contains ("max_count" )) { 1950throw std::runtime_error ("chars parser missing required fields" ); 1951 } 1952common_peg_chars_parser parser ; 1953parser .pattern = j ["pattern" ]; 1954parser .negated = j ["negated" ].get < bool > (); 1955parser .min_count = j ["min_count" ].get < int > (); 1956parser .max_count = j ["max_count" ].get < int > (); 1957for (const auto & range_json :j ["ranges" ]) { 1958if (!range_json .contains ("start" )|| !range_json .contains ("end" )) { 1959throw std::runtime_error ("char_range missing 'start' or 'end' field" ); 1960 } 1961parser .ranges .push_back ({ 1962range_json ["start" ].get < uint32_t > (), 1963range_json ["end" ].get < uint32_t > () 1964 }); 1965 } 1966return parser ; 1967 } 1968if (type == "string" ) { 1969if (!j .contains ("delimiter" )) { 1970throw std::runtime_error ("string parser missing delimiter field." ); 1971 } 1972 std::string delimiter = j ["delimiter" ]; 1973if (delimiter .empty ()) { 1974throw std::runtime_error ("string parser delimiter is empty." ); 1975 } 1976return common_peg_string_parser {delimiter [0 ]}; 1977 } 1978if (type == "until" ) { 1979if (!j .contains ("delimiters" )|| !j ["delimiters" ].is_array ()) { 1980throw std::runtime_error ("until parser missing or invalid 'delimiters' field" ); 1981 } 1982return common_peg_until_parser {j ["delimiters" ].get < std::vector < std::string >> ()}; 1983 } 1984if (type == "schema" ) { 1985if (!j .contains ("child" )|| !j .contains ("name" )|| !j .contains ("raw" )) { 1986throw std::runtime_error ("schema parser missing required fields" ); 1987 } 1988common_peg_schema_parser parser ; 1989parser .child = j ["child" ].get < common_peg_parser_id > (); 1990parser .name = j ["name" ]; 1991parser .raw = j ["raw" ].get < bool > (); 1992return parser ; 1993 } 1994if (type == "rule" ) { 1995if (!j .contains ("name" )|| !j .contains ("child" )|| !j .contains ("trigger" )) { 1996throw std::runtime_error ("rule parser missing required fields" ); 1997 } 1998return common_peg_rule_parser { 1999j ["name" ].get < std::string > (), 2000j ["child" ].get < common_peg_parser_id > (), 2001j ["trigger" ].get < bool > () 2002 }; 2003 } 2004if (type == "ref" ) { 2005if (!j .contains ("name" )|| !j ["name" ].is_string ()) { 2006throw std::runtime_error ("ref parser missing or invalid 'name' field" ); 2007 } 2008return common_peg_ref_parser {j ["name" ]}; 2009 } 2010if (type == "atomic" ) { 2011if (!j .contains ("child" )) { 2012throw std::runtime_error ("tag parser missing required fields" ); 2013 } 2014return common_peg_atomic_parser { 2015j ["child" ].get < common_peg_parser_id > (), 2016 }; 2017 } 2018if (type == "tag" ) { 2019if (!j .contains ("child" )|| !j .contains ("tag" )) { 2020throw std::runtime_error ("tag parser missing required fields" ); 2021 } 2022return common_peg_tag_parser { 2023j ["child" ].get < common_peg_parser_id > (), 2024j ["tag" ].get < std::string > (), 2025 }; 2026 } 2027 2028if (type == "gbnf" ) { 2029if (!j .contains ("child" )|| !j .contains ("grammar" )) { 2030throw std::runtime_error ("gbnf parser missing required fields" ); 2031 } 2032return common_peg_gbnf_parser { 2033j ["child" ].get < common_peg_parser_id > (), 2034j ["grammar" ].get < std::string > (), 2035 }; 2036 } 2037 2038if (type == "ac" ) { 2039if (!j .contains ("child" )|| !j .contains ("delimiters" )|| !j ["delimiters" ].is_array ()|| j ["delimiters" ].empty ()) { 2040throw std::runtime_error ("ac parser requires 'child' and a non-empty 'delimiters' array" ); 2041 } 2042return common_peg_ac_parser { 2043j ["child" ].get < common_peg_parser_id > (), 2044j ["delimiters" ].get < std::vector < std::string >> (), 2045 }; 2046 } 2047 2048throw std::runtime_error ("Unknown parser type: " + type ); 2049} 2050 2051common_peg_arena common_peg_arena::from_json (const common_json & j ) { 2052if (!j .contains ("parsers" )|| !j ["parsers" ].is_array ()) { 2053throw std::runtime_error ("JSON missing or invalid 'parsers' array" ); 2054 } 2055if (!j .contains ("rules" )|| !j ["rules" ].is_object ()) { 2056throw std::runtime_error ("JSON missing or invalid 'rules' object" ); 2057 } 2058if (!j .contains ("root" )) { 2059throw std::runtime_error ("JSON missing 'root' field" ); 2060 } 2061 2062common_peg_arena arena ; 2063 2064const auto & parsers_json = j ["parsers" ]; 2065arena .parsers_ .reserve (parsers_json .size ()); 2066for (const auto & parser_json :parsers_json ) { 2067arena .parsers_ .push_back (deserialize_parser_variant (parser_json )); 2068 } 2069 2070arena .rules_ = j ["rules" ].get < std::unordered_map < std::string ,common_peg_parser_id >> (); 2071 2072for (const auto & [name ,id ] :arena .rules_ ) { 2073if (id >=arena .parsers_ .size ()) { 2074throw std::runtime_error ("Rule '" + name + "' references invalid parser ID: " + std::to_string (id )); 2075 } 2076 } 2077 2078arena .root_ = j ["root" ].get < common_peg_parser_id > (); 2079if (arena .root_ != COMMON_PEG_INVALID_PARSER_ID && arena .root_ >=arena .parsers_ .size ()) { 2080throw std::runtime_error ("Root references invalid parser ID: " + std::to_string (arena .root_ )); 2081 } 2082 2083return arena ; 2084} 2085 2086std::string common_peg_arena::save ()const { 2087return to_json ().dump (); 2088} 2089 2090void common_peg_arena::load (const std::string & data ) { 2091* this = from_json (common_json::parse (data )); 2092} 2093 2094common_peg_arena build_peg_parser (const std::function < common_peg_parser (common_peg_parser_builder & builder )> & fn ) { 2095common_peg_parser_builder builder ; 2096builder .set_root (fn (builder )); 2097return builder .build (); 2098}