@@ -4710,17 +4710,24 @@ pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token
47104710 ((pm_integer_t) { 0 })
47114711 );
47124712
4713- pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4714- switch (base) {
4715- case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4716- case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4717- case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4718- case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4719- default: assert(false && "unreachable"); break;
4713+ if (parser->integer.lexed) {
4714+ // The value was already computed during lexing.
4715+ node->value.value = parser->integer.value;
4716+ parser->integer.lexed = false;
4717+ } else {
4718+ pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4719+ switch (base) {
4720+ case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4721+ case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4722+ case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4723+ case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4724+ default: assert(false && "unreachable"); break;
4725+ }
4726+
4727+ pm_integer_parse(&node->value, integer_base, token->start, token->end);
4728+ pm_integer_arena_move(parser->arena, &node->value);
47204729 }
47214730
4722- pm_integer_parse(&node->value, integer_base, token->start, token->end);
4723- pm_integer_arena_move(parser->arena, &node->value);
47244731 return node;
47254732}
47264733
@@ -8112,7 +8119,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81128119 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
81138120 }
81148121
8115- parser->integer_base = PM_INTEGER_BASE_FLAGS_BINARY;
8122+ parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
81168123 break;
81178124
81188125 // 0o1111 is an octal number
@@ -8126,7 +8133,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81268133 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
81278134 }
81288135
8129- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
8136+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
81308137 break;
81318138
81328139 // 01111 is an octal number
@@ -8140,7 +8147,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81408147 case '6':
81418148 case '7':
81428149 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8143- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
8150+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
81448151 break;
81458152
81468153 // 0x1111 is a hexadecimal number
@@ -8154,7 +8161,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81548161 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
81558162 }
81568163
8157- parser->integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8164+ parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
81588165 break;
81598166
81608167 // 0.xxx is a float
@@ -8172,11 +8179,53 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81728179 }
81738180 } else {
81748181 // If it didn't start with a 0, then we'll lex as far as we can into a
8175- // decimal number.
8176- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8182+ // decimal number. We compute the integer value inline to avoid
8183+ // re-scanning the digits later in pm_integer_parse.
8184+ {
8185+ const uint8_t *cursor = parser->current.end;
8186+ const uint8_t *end = parser->end;
8187+ uint64_t value = (uint64_t) (cursor[-1] - '0');
8188+
8189+ bool has_underscore = false;
8190+ bool prev_underscore = false;
8191+ const uint8_t *invalid = NULL;
8192+
8193+ while (cursor < end) {
8194+ uint8_t c = *cursor;
8195+ if (c >= '0' && c <= '9') {
8196+ if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c - '0');
8197+ prev_underscore = false;
8198+ cursor++;
8199+ } else if (c == '_') {
8200+ has_underscore = true;
8201+ if (prev_underscore && invalid == NULL) invalid = cursor;
8202+ prev_underscore = true;
8203+ cursor++;
8204+ } else {
8205+ break;
8206+ }
8207+ }
8208+
8209+ if (has_underscore) {
8210+ if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8211+ pm_strspn_number_validate(parser, parser->current.end, (size_t) (cursor - parser->current.end), invalid);
8212+ }
8213+
8214+ if (value <= UINT32_MAX) {
8215+ parser->integer.value = (uint32_t) value;
8216+ parser->integer.lexed = true;
8217+ }
8218+
8219+ parser->current.end = cursor;
8220+ }
81778221
81788222 // Afterward, we'll lex as far as we can into an optional float suffix.
81798223 type = lex_optional_float_suffix(parser, seen_e);
8224+
8225+ // If it turned out to be a float, the cached integer value is invalid.
8226+ if (type != PM_TOKEN_INTEGER) {
8227+ parser->integer.lexed = false;
8228+ }
81808229 }
81818230
81828231 // At this point we have a completed number, but we want to provide the user
@@ -8195,7 +8244,8 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
81958244static pm_token_type_t
81968245lex_numeric(pm_parser_t *parser) {
81978246 pm_token_type_t type = PM_TOKEN_INTEGER;
8198- parser->integer_base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8247+ parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8248+ parser->integer.lexed = false;
81998249
82008250 if (parser->current.end < parser->end) {
82018251 bool seen_e = false;
@@ -18302,22 +18352,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
1830218352 return node;
1830318353 }
1830418354 case PM_TOKEN_INTEGER: {
18305- pm_node_flags_t base = parser->integer_base ;
18355+ pm_node_flags_t base = parser->integer.base ;
1830618356 parser_lex(parser);
1830718357 return UP(pm_integer_node_create(parser, base, &parser->previous));
1830818358 }
1830918359 case PM_TOKEN_INTEGER_IMAGINARY: {
18310- pm_node_flags_t base = parser->integer_base ;
18360+ pm_node_flags_t base = parser->integer.base ;
1831118361 parser_lex(parser);
1831218362 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
1831318363 }
1831418364 case PM_TOKEN_INTEGER_RATIONAL: {
18315- pm_node_flags_t base = parser->integer_base ;
18365+ pm_node_flags_t base = parser->integer.base ;
1831618366 parser_lex(parser);
1831718367 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
1831818368 }
1831918369 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18320- pm_node_flags_t base = parser->integer_base ;
18370+ pm_node_flags_t base = parser->integer.base ;
1832118371 parser_lex(parser);
1832218372 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
1832318373 }
@@ -22154,7 +22204,7 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si
2215422204 .filepath = { 0 },
2215522205 .constant_pool = { 0 },
2215622206 .line_offsets = { 0 },
22157- .integer_base = 0 ,
22207+ .integer = { 0 } ,
2215822208 .current_string = PM_STRING_EMPTY,
2215922209 .start_line = 1,
2216022210 .explicit_encoding = NULL,
0 commit comments