char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
ead417f01
char/aliceai-t5-moe
1#include "lexer.h" 2#include "runtime.h" 3#include "parser.h" 4 5#include <algorithm> 6#include <memory> 7#include <stdexcept> 8#include <string> 9#include <vector> 10 11#define FILENAME "jinja-parser" 12 13namespace jinja { 14 15// Helper to check type without asserting (useful for logic) 16template < typename T > 17static bool is_type (const statement_ptr & ptr ) { 18return dynamic_cast < const T *> (ptr .get ())!= nullptr ; 19} 20 21class parser { 22const std::vector < token > & tokens ; 23size_t current = 0 ; 24 25 std::string source ;// for error reporting 26 27public : 28parser (const std::vector < token > & t ,const std::string & src ) :tokens (t ),source (src ) {} 29 30program parse () { 31statements body ; 32while (current < tokens .size ()) { 33body .push_back (parse_any ()); 34 } 35return program (std::move (body )); 36 } 37 38// NOTE: start_pos is the token index, used for error reporting 39template < typename T ,typename ...Args > 40 std::unique_ptr < T > mk_stmt (size_t start_pos ,Args && ...args ) { 41auto ptr = std::make_unique < T > (std::forward < Args > (args )...); 42assert (start_pos < tokens .size ()); 43ptr -> pos = tokens [start_pos ].pos ; 44return ptr ; 45 } 46 47private : 48const token & peek (size_t offset = 0 )const { 49if (current + offset >=tokens .size ()) { 50static const token end_token {token::eof ,"" ,0 }; 51return end_token ; 52 } 53return tokens [current + offset ]; 54 } 55 56const token & next () { 57if (current >=tokens .size ()) { 58throw parser_exception ("Parser Error: Unexpected EOF" ,source ,tokens .empty () ?0 :tokens .back ().pos ); 59 } 60return tokens [current ++ ]; 61 } 62 63token expect (token::type type ,const std::string & error ) { 64const auto & t = peek (); 65if (t .t != type ) { 66throw parser_exception ("Parser Error: " + error + " (Got " + t .value + ")" ,source ,t .pos ); 67 } 68current ++ ; 69return t ; 70 } 71 72void expect_identifier (const std::string & name ) { 73const auto & t = peek (); 74if (t .t != token::identifier || t .value != name ) { 75throw parser_exception ("Expected identifier: " + name ,source ,t .pos ); 76 } 77current ++ ; 78 } 79 80bool is (token::type type )const { 81return peek ().t == type ; 82 } 83 84bool is_identifier (const std::string & name )const { 85return peek ().t == token::identifier && peek ().value == name ; 86 } 87 88bool is_statement (const std::vector < std::string > & names )const { 89if (peek (0 ).t != token::open_statement || peek (1 ).t != token::identifier ) { 90return false; 91 } 92 std::string val = peek (1 ).value ; 93return std::find (names .begin (),names .end (),val )!= names .end (); 94 } 95 96statement_ptr parse_any () { 97size_t start_pos = current ; 98switch (peek ().t ) { 99case token::comment : 100return mk_stmt < comment_statement > (start_pos ,next ().value ); 101case token::text : 102return mk_stmt < string_literal > (start_pos ,next ().value ); 103case token::open_statement : 104return parse_jinja_statement (); 105case token::open_expression : 106return parse_jinja_expression (); 107default : 108throw std::runtime_error ("Unexpected token type" ); 109 } 110 } 111 112statement_ptr parse_jinja_expression () { 113// Consume {{ }} tokens 114expect (token::open_expression ,"Expected {{" ); 115auto result = parse_expression (); 116expect (token::close_expression ,"Expected }}" ); 117return result ; 118 } 119 120statement_ptr parse_jinja_statement () { 121// Consume {% token 122expect (token::open_statement ,"Expected {%" ); 123 124if (peek ().t != token::identifier ) { 125throw std::runtime_error ("Unknown statement" ); 126 } 127 128size_t start_pos = current ; 129 std::string name = next ().value ; 130 131statement_ptr result ; 132if (name == "set" ) { 133result = parse_set_statement (start_pos ); 134 135 }else if (name == "if" ) { 136result = parse_if_statement (start_pos ); 137// expect {% endif %} 138expect (token::open_statement ,"Expected {%" ); 139expect_identifier ("endif" ); 140expect (token::close_statement ,"Expected %}" ); 141 142 }else if (name == "macro" ) { 143result = parse_macro_statement (start_pos ); 144// expect {% endmacro %} 145expect (token::open_statement ,"Expected {%" ); 146expect_identifier ("endmacro" ); 147expect (token::close_statement ,"Expected %}" ); 148 149 }else if (name == "for" ) { 150result = parse_for_statement (start_pos ); 151// expect {% endfor %} 152expect (token::open_statement ,"Expected {%" ); 153expect_identifier ("endfor" ); 154expect (token::close_statement ,"Expected %}" ); 155 156 }else if (name == "break" ) { 157expect (token::close_statement ,"Expected %}" ); 158result = mk_stmt < break_statement > (start_pos ); 159 160 }else if (name == "continue" ) { 161expect (token::close_statement ,"Expected %}" ); 162result = mk_stmt < continue_statement > (start_pos ); 163 164 }else if (name == "call" ) { 165statements caller_args ; 166// bool has_caller_args = false; 167if (is (token::open_paren )) { 168// Optional caller arguments, e.g. {% call(user) dump_users(...) %} 169caller_args = parse_args (); 170// has_caller_args = true; 171 } 172auto callee = parse_primary_expression (); 173if (!is_type < identifier > (callee ))throw std::runtime_error ("Expected identifier" ); 174 175auto call_args = parse_args (); 176expect (token::close_statement ,"Expected %}" ); 177 178statements body ; 179while (!is_statement ({"endcall" })) { 180body .push_back (parse_any ()); 181 } 182 183expect (token::open_statement ,"Expected {%" ); 184expect_identifier ("endcall" ); 185expect (token::close_statement ,"Expected %}" ); 186 187auto call_expr = mk_stmt < call_expression > (start_pos , std::move (callee ), std::move (call_args )); 188result = mk_stmt < call_statement > (start_pos , std::move (call_expr ), std::move (caller_args ), std::move (body )); 189 190 }else if (name == "filter" ) { 191auto filter_node = parse_primary_expression (); 192if (is_type < identifier > (filter_node )&& is (token::open_paren )) { 193filter_node = parse_call_expression (std::move (filter_node )); 194 } 195expect (token::close_statement ,"Expected %}" ); 196 197statements body ; 198while (!is_statement ({"endfilter" })) { 199body .push_back (parse_any ()); 200 } 201 202expect (token::open_statement ,"Expected {%" ); 203expect_identifier ("endfilter" ); 204expect (token::close_statement ,"Expected %}" ); 205result = mk_stmt < filter_statement > (start_pos , std::move (filter_node ), std::move (body )); 206 207 }else if (name == "generation" || name == "endgeneration" ) { 208// Ignore generation blocks (transformers-specific) 209// See https://github.com/huggingface/transformers/pull/30650 for more information. 210result = mk_stmt < noop_statement > (start_pos ); 211++ current ; 212 213 }else { 214throw std::runtime_error ("Unknown statement: " + name ); 215 } 216return result ; 217 } 218 219statement_ptr parse_set_statement (size_t start_pos ) { 220// NOTE: `set` acts as both declaration statement and assignment expression 221auto left = parse_expression_sequence (); 222statement_ptr value = nullptr ; 223statements body ; 224 225if (is (token::equals )) { 226++ current ; 227value = parse_expression_sequence (); 228 }else { 229// parsing multiline set here 230expect (token::close_statement ,"Expected %}" ); 231while (!is_statement ({"endset" })) { 232body .push_back (parse_any ()); 233 } 234expect (token::open_statement ,"Expected {%" ); 235expect_identifier ("endset" ); 236 } 237expect (token::close_statement ,"Expected %}" ); 238return mk_stmt < set_statement > (start_pos , std::move (left ), std::move (value ), std::move (body )); 239 } 240 241statement_ptr parse_if_statement (size_t start_pos ) { 242auto test = parse_expression (); 243expect (token::close_statement ,"Expected %}" ); 244 245statements body ; 246statements alternate ; 247 248// Keep parsing 'if' body until we reach the first {% elif %} or {% else %} or {% endif %} 249while (!is_statement ({"elif" ,"else" ,"endif" })) { 250body .push_back (parse_any ()); 251 } 252 253if (is_statement ({"elif" })) { 254size_t pos0 = current ; 255++ current ;// consume {% 256++ current ;// consume 'elif' 257alternate .push_back (parse_if_statement (pos0 ));// nested If 258 }else if (is_statement ({"else" })) { 259++ current ;// consume {% 260++ current ;// consume 'else' 261expect (token::close_statement ,"Expected %}" ); 262 263// keep going until we hit {% endif %} 264while (!is_statement ({"endif" })) { 265alternate .push_back (parse_any ()); 266 } 267 } 268return mk_stmt < if_statement > (start_pos , std::move (test ), std::move (body ), std::move (alternate )); 269 } 270 271statement_ptr parse_macro_statement (size_t start_pos ) { 272auto name = parse_primary_expression (); 273auto args = parse_args (); 274expect (token::close_statement ,"Expected %}" ); 275statements body ; 276// Keep going until we hit {% endmacro 277while (!is_statement ({"endmacro" })) { 278body .push_back (parse_any ()); 279 } 280return mk_stmt < macro_statement > (start_pos , std::move (name ), std::move (args ), std::move (body )); 281 } 282 283statement_ptr parse_expression_sequence (bool primary = false) { 284size_t start_pos = current ; 285statements exprs ; 286exprs .push_back (primary ?parse_primary_expression () :parse_expression ()); 287bool is_tuple = is (token::comma ); 288while (is (token::comma )) { 289++ current ;// consume comma 290exprs .push_back (primary ?parse_primary_expression () :parse_expression ()); 291 } 292return is_tuple ?mk_stmt < tuple_literal > (start_pos , std::move (exprs )) : std::move (exprs [0 ]); 293 } 294 295statement_ptr parse_for_statement (size_t start_pos ) { 296// e.g., `message` in `for message in messages` 297auto loop_var = parse_expression_sequence (true);// should be an identifier/tuple 298if (!is_identifier ("in" ))throw std::runtime_error ("Expected 'in'" ); 299++ current ;// consume 'in' 300 301// `messages` in `for message in messages` 302auto iterable = parse_expression (); 303expect (token::close_statement ,"Expected %}" ); 304 305statements body ; 306statements alternate ; 307 308// Keep going until we hit {% endfor or {% else 309while (!is_statement ({"endfor" ,"else" })) { 310body .push_back (parse_any ()); 311 } 312 313if (is_statement ({"else" })) { 314++ current ;// consume {% 315++ current ;// consume 'else' 316expect (token::close_statement ,"Expected %}" ); 317while (!is_statement ({"endfor" })) { 318alternate .push_back (parse_any ()); 319 } 320 } 321return mk_stmt < for_statement > ( 322start_pos , 323 std::move (loop_var ), std::move (iterable ), 324 std::move (body ), std::move (alternate )); 325 } 326 327statement_ptr parse_expression () { 328// Choose parse function with lowest precedence 329return parse_if_expression (); 330 } 331 332statement_ptr parse_if_expression () { 333auto a = parse_logical_or_expression (); 334if (is_identifier ("if" )) { 335// Ternary expression 336size_t start_pos = current ; 337++ current ;// consume 'if' 338auto test = parse_logical_or_expression (); 339if (is_identifier ("else" )) { 340// Ternary expression with else 341size_t pos0 = current ; 342++ current ;// consume 'else' 343auto false_expr = parse_if_expression ();// recurse to support chained ternaries 344return mk_stmt < ternary_expression > (pos0 , std::move (test ), std::move (a ), std::move (false_expr )); 345 }else { 346// Select expression on iterable 347return mk_stmt < select_expression > (start_pos , std::move (a ), std::move (test )); 348 } 349 } 350return a ; 351 } 352 353statement_ptr parse_logical_or_expression () { 354auto left = parse_logical_and_expression (); 355while (is_identifier ("or" )) { 356size_t start_pos = current ; 357token op = next (); 358left = mk_stmt < binary_expression > (start_pos ,op , std::move (left ),parse_logical_and_expression ()); 359 } 360return left ; 361 } 362 363statement_ptr parse_logical_and_expression () { 364auto left = parse_logical_negation_expression (); 365while (is_identifier ("and" )) { 366size_t start_pos = current ; 367auto op = next (); 368left = mk_stmt < binary_expression > (start_pos ,op , std::move (left ),parse_logical_negation_expression ()); 369 } 370return left ; 371 } 372 373statement_ptr parse_logical_negation_expression () { 374// Try parse unary operators 375if (is_identifier ("not" )) { 376size_t start_pos = current ; 377auto op = next (); 378return mk_stmt < unary_expression > (start_pos ,op ,parse_logical_negation_expression ()); 379 } 380return parse_comparison_expression (); 381 } 382 383statement_ptr parse_comparison_expression () { 384// NOTE: membership has same precedence as comparison 385// e.g., ('a' in 'apple' == 'b' in 'banana') evaluates as ('a' in ('apple' == ('b' in 'banana'))) 386auto left = parse_additive_expression (); 387while (true) { 388token op ; 389size_t start_pos = current ; 390if (is_identifier ("not" )&& peek (1 ).t == token::identifier && peek (1 ).value == "in" ) { 391op = {token::identifier ,"not in" ,tokens [current ].pos }; 392++ current ;// consume 'not' 393++ current ;// consume 'in' 394 }else if (is_identifier ("in" )) { 395op = next (); 396 }else if (is (token::comparison_binary_operator )) { 397op = next (); 398 }else break ; 399left = mk_stmt < binary_expression > (start_pos ,op , std::move (left ),parse_additive_expression ()); 400 } 401return left ; 402 } 403 404statement_ptr parse_additive_expression () { 405auto left = parse_multiplicative_expression (); 406while (is (token::additive_binary_operator )) { 407size_t start_pos = current ; 408auto op = next (); 409left = mk_stmt < binary_expression > (start_pos ,op , std::move (left ),parse_multiplicative_expression ()); 410 } 411return left ; 412 } 413 414statement_ptr parse_multiplicative_expression () { 415auto left = parse_test_expression (); 416while (is (token::multiplicative_binary_operator )) { 417size_t start_pos = current ; 418auto op = next (); 419left = mk_stmt < binary_expression > (start_pos ,op , std::move (left ),parse_test_expression ()); 420 } 421return left ; 422 } 423 424statement_ptr parse_test_expression () { 425auto operand = parse_filter_expression (); 426while (is_identifier ("is" )) { 427size_t start_pos = current ; 428++ current ;// consume 'is' 429bool negate = false; 430if (is_identifier ("not" )) {++ current ;negate = true; } 431auto test_id = parse_primary_expression (); 432// FIXME: tests can also be expressed like this: if x is eq 3 433if (is (token::open_paren ))test_id = parse_call_expression (std::move (test_id )); 434operand = mk_stmt < test_expression > (start_pos , std::move (operand ),negate , std::move (test_id )); 435 } 436return operand ; 437 } 438 439statement_ptr parse_filter_expression () { 440auto operand = parse_call_member_expression (); 441while (is (token::pipe )) { 442size_t start_pos = current ; 443++ current ;// consume pipe 444auto filter = parse_primary_expression (); 445if (is (token::open_paren ))filter = parse_call_expression (std::move (filter )); 446operand = mk_stmt < filter_expression > (start_pos , std::move (operand ), std::move (filter )); 447 } 448return operand ; 449 } 450 451statement_ptr parse_call_member_expression () { 452// Handle member expressions recursively 453auto member = parse_member_expression (parse_primary_expression ()); 454return is (token::open_paren ) 455 ?parse_call_expression (std::move (member ))// foo.x() 456 : std::move (member ); 457 } 458 459statement_ptr parse_call_expression (statement_ptr callee ) { 460size_t start_pos = current ; 461auto expr = mk_stmt < call_expression > (start_pos , std::move (callee ),parse_args ()); 462auto member = parse_member_expression (std::move (expr ));// foo.x().y 463return is (token::open_paren ) 464 ?parse_call_expression (std::move (member ))// foo.x()() 465 : std::move (member ); 466 } 467 468statements parse_args () { 469// comma-separated arguments list 470expect (token::open_paren ,"Expected (" ); 471statements args ; 472while (!is (token::close_paren )) { 473statement_ptr arg ; 474// unpacking: *expr 475if (peek ().t == token::multiplicative_binary_operator && peek ().value == "*" ) { 476size_t start_pos = current ; 477++ current ;// consume * 478arg = mk_stmt < spread_expression > (start_pos ,parse_expression ()); 479 }else { 480arg = parse_expression (); 481if (is (token::equals )) { 482// keyword argument 483// e.g., func(x = 5, y = a or b) 484size_t start_pos = current ; 485++ current ;// consume equals 486arg = mk_stmt < keyword_argument_expression > (start_pos , std::move (arg ),parse_expression ()); 487 } 488 } 489args .push_back (std::move (arg )); 490if (is (token::comma )) { 491++ current ;// consume comma 492 } 493 } 494expect (token::close_paren ,"Expected )" ); 495return args ; 496 } 497 498statement_ptr parse_member_expression (statement_ptr object ) { 499size_t start_pos = current ; 500while (is (token::dot )|| is (token::open_square_bracket )) { 501auto op = next (); 502bool computed = op .t == token::open_square_bracket ; 503statement_ptr prop ; 504if (computed ) { 505prop = parse_member_expression_arguments (); 506expect (token::close_square_bracket ,"Expected ]" ); 507 }else { 508prop = parse_primary_expression (); 509 } 510object = mk_stmt < member_expression > (start_pos , std::move (object ), std::move (prop ),computed ); 511 } 512return object ; 513 } 514 515statement_ptr parse_member_expression_arguments () { 516// NOTE: This also handles slice expressions colon-separated arguments list 517// e.g., ['test'], [0], [:2], [1:], [1:2], [1:2:3] 518statements slices ; 519bool is_slice = false; 520size_t start_pos = current ; 521while (!is (token::close_square_bracket )) { 522if (is (token::colon )) { 523// A case where a default is used 524// e.g., [:2] will be parsed as [undefined, 2] 525slices .push_back (nullptr ); 526++ current ;// consume colon 527is_slice = true; 528 }else { 529slices .push_back (parse_expression ()); 530if (is (token::colon )) { 531++ current ;// consume colon after expression, if it exists 532is_slice = true; 533 } 534 } 535 } 536if (is_slice ) { 537statement_ptr start = slices .size ()> 0 ? std::move (slices [0 ]) :nullptr ; 538statement_ptr stop = slices .size ()> 1 ? std::move (slices [1 ]) :nullptr ; 539statement_ptr step = slices .size ()> 2 ? std::move (slices [2 ]) :nullptr ; 540return mk_stmt < slice_expression > (start_pos , std::move (start ), std::move (stop ), std::move (step )); 541 } 542if (slices .empty ()) { 543return mk_stmt < blank_expression > (start_pos ); 544 } 545return std::move (slices [0 ]); 546 } 547 548statement_ptr parse_primary_expression () { 549size_t start_pos = current ; 550auto t = next (); 551switch (t .t ) { 552case token::numeric_literal : 553if (t .value .find ('.' )!= std::string::npos ) { 554return mk_stmt < float_literal > (start_pos , std::stod (t .value )); 555 }else { 556return mk_stmt < integer_literal > (start_pos , std::stoll (t .value )); 557 } 558case token::string_literal : { 559 std::string val = t .value ; 560while (is (token::string_literal )) { 561val += next ().value ; 562 } 563return mk_stmt < string_literal > (start_pos ,val ); 564 } 565case token::identifier : 566return mk_stmt < identifier > (start_pos ,t .value ); 567case token::open_paren : { 568auto expr = parse_expression_sequence (); 569expect (token::close_paren ,"Expected )" ); 570return expr ; 571 } 572case token::open_square_bracket : { 573statements vals ; 574while (!is (token::close_square_bracket )) { 575vals .push_back (parse_expression ()); 576if (is (token::comma ))++ current ; 577 } 578++ current ; 579return mk_stmt < array_literal > (start_pos , std::move (vals )); 580 } 581case token::open_curly_bracket : { 582 std::vector < std::pair < statement_ptr ,statement_ptr >> pairs ; 583while (!is (token::close_curly_bracket )) { 584auto key = parse_expression (); 585expect (token::colon ,"Expected :" ); 586pairs .push_back ({std::move (key ),parse_expression ()}); 587if (is (token::comma ))++ current ; 588 } 589++ current ; 590return mk_stmt < object_literal > (start_pos , std::move (pairs )); 591 } 592default : 593throw std::runtime_error ("Unexpected token: " + t .value + " of type " + std::to_string (t .t )); 594 } 595 } 596}; 597 598program parse_from_tokens (const lexer_result & lexer_res ) { 599return parser (lexer_res .tokens ,lexer_res .source ).parse (); 600} 601 602}// namespace jinja