Skip to content

Commit 7ec40b0

Browse files
committed
Implement single-char state transitions using a static array and for loop
This reduces compile time, compared to generating many individual if statements.
1 parent 3210c7e commit 7ec40b0

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

cli/src/generate/render.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,44 @@ impl Generator {
704704
let mut large_set = CharacterSet::empty();
705705
let mut ruled_out_chars = CharacterSet::empty();
706706

707-
for (chars, action) in state.advance_actions {
707+
// The transitions in a lex state are sorted with the single-character
708+
// transitions first. If there are many single-character transitions,
709+
// then implement them using an array of (lookahead character, state)
710+
// pairs, instead of individual if statements, in order to reduce compile
711+
// time.
712+
let mut leading_simple_transition_count = 0;
713+
let mut leading_simple_transition_character_count = 0;
714+
for (chars, action) in &state.advance_actions {
715+
if action.in_main_token
716+
&& chars
717+
.ranges()
718+
.all(|r| r.start() == r.end() && *r.start() as u32 <= u16::MAX as u32)
719+
{
720+
leading_simple_transition_count += 1;
721+
leading_simple_transition_character_count += chars.range_count();
722+
} else {
723+
break;
724+
}
725+
}
726+
727+
if leading_simple_transition_character_count >= 8 {
728+
add_line!(self, "ADVANCE_MAP(");
729+
indent!(self);
730+
for (chars, action) in &state.advance_actions[0..leading_simple_transition_count] {
731+
for range in chars.ranges() {
732+
add_whitespace!(self);
733+
self.add_character(*range.start());
734+
add!(self, ", {},\n", action.state);
735+
}
736+
ruled_out_chars = ruled_out_chars.add(chars);
737+
}
738+
dedent!(self);
739+
add_line!(self, ");");
740+
} else {
741+
leading_simple_transition_count = 0;
742+
}
743+
744+
for (chars, action) in &state.advance_actions[leading_simple_transition_count..] {
708745
add_whitespace!(self);
709746

710747
// The lex state's advance actions are represented with disjoint
@@ -749,7 +786,7 @@ impl Generator {
749786

750787
// Add this transition's character set to the set of ruled out characters,
751788
// which don't need to be checked for subsequent transitions in this state.
752-
ruled_out_chars = ruled_out_chars.add(&chars);
789+
ruled_out_chars = ruled_out_chars.add(chars);
753790

754791
let mut large_char_set_ix = None;
755792
let mut asserted_chars = simplified_chars;
@@ -823,7 +860,7 @@ impl Generator {
823860
add!(self, ") ");
824861
}
825862

826-
self.add_advance_action(&action);
863+
self.add_advance_action(action);
827864
add!(self, "\n");
828865
}
829866

lib/src/parser.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t
177177
goto next_state; \
178178
}
179179

180+
#define ADVANCE_MAP(...) \
181+
{ \
182+
static const uint16_t map[] = { __VA_ARGS__ }; \
183+
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
184+
if (map[i] == lookahead) { \
185+
state = map[i + 1]; \
186+
goto next_state; \
187+
} \
188+
} \
189+
}
190+
180191
#define SKIP(state_value) \
181192
{ \
182193
skip = true; \

0 commit comments

Comments
 (0)