@@ -598,12 +598,46 @@ def _set_up_rule_memoization(self, node: Rule, result_type: str) -> None:
598598 def _should_memoize (self , node : Rule ) -> bool :
599599 return "memo" in node .flags and not node .left_recursive
600600
601+ # Rules that are pure entry points into the expression precedence tower:
602+ # when the current token is a bare NAME/NUMBER atom and the next token
603+ # cannot start or continue a binary/postfix expression, the whole tower
604+ # would provably consume exactly one token, so a two-token fast path is
605+ # emitted that builds the atom directly.
606+ ATOM_FAST_PATH_RULES = frozenset ({"disjunction" , "inversion" })
607+
608+ def _emit_atom_fast_path (self ) -> None :
609+ # Only look one token ahead when the current token is NAME/NUMBER:
610+ # the tower fills it too in that case, so error reporting (which
611+ # keys off p->fill) is unperturbed.
612+ self .print ("if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) {" )
613+ with self .indent ():
614+ self .print ("p->error_indicator = 1;" )
615+ self .add_return ("NULL" )
616+ self .print ("}" )
617+ self .print ("Token *_fast_tok = p->tokens[p->mark];" )
618+ self .print ("if (_fast_tok->type == NAME || _fast_tok->type == NUMBER) {" )
619+ with self .indent ():
620+ self .print ("if (p->mark + 1 == p->fill && _PyPegen_fill_token(p) < 0) {" )
621+ with self .indent ():
622+ self .print ("p->error_indicator = 1;" )
623+ self .add_return ("NULL" )
624+ self .print ("}" )
625+ self .print ("if (_PyPegen_atom_follow_token(p->tokens[p->mark + 1]->type)) {" )
626+ with self .indent ():
627+ self .print ("expr_ty _fast_res = (_fast_tok->type == NAME)" )
628+ self .print (" ? _PyPegen_name_token(p) : _PyPegen_number_token(p);" )
629+ self .add_return ("_fast_res" )
630+ self .print ("}" )
631+ self .print ("}" )
632+
601633 def _handle_default_rule_body (self , node : Rule , rhs : Rhs , result_type : str ) -> None :
602634 memoize = self ._should_memoize (node )
603635
604636 with self .indent ():
605637 self .add_level ()
606638 self ._check_for_errors ()
639+ if node .name in self .ATOM_FAST_PATH_RULES :
640+ self ._emit_atom_fast_path ()
607641 self .print (f"{ result_type } _res = NULL;" )
608642 if memoize :
609643 self .print (f"if (_PyPegen_is_memoized(p, { node .name } _type, &_res)) {{" )
0 commit comments