// Regex compilation is deferred until the lexer is used. This is to avoid significant init() time costs.
Regex compilation is deferred until the lexer is used. This is to avoid significant init() time costs.
// Regex compilation is deferred until the lexer is used . This is to avoid significant init () time costs .
func (r *RegexLexer) maybeCompile() (err error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.compiled {
		return nil
	}
	for state, rules := range r.rules {
		for i, rule := range rules {
			if rule.Regexp == nil {
				pattern := "(?:" + rule.Pattern + ")"
				if rule.flags != "" {
					pattern = "(?" + rule.flags + ")" + pattern
				}
				pattern = `\G` + pattern
				rule.Regexp, err = regexp2.Compile(pattern, 0)
				if err != nil {
					return fmt.Errorf("failed to compile rule %s.%d: %s", state, i, err)
				}
			}
		}
	}
restart:
	seen := map[LexerMutator]bool{}
	for state := range r.rules {
		for i := 0; i < len(r.rules[state]); i++ {
			rule := r.rules[state][i]
			if compile, ok := rule.Mutator.(LexerMutator); ok {
				if seen[compile] {
					return fmt.Errorf("saw mutator %T twice; this should not happen", compile)
				}
				seen[compile] = true
				if err := compile.MutateLexer(r.rules, state, i); err != nil {
					return err
				}
				 This sounds bad, but shouldn't be significant in practice.
				goto restart
			}
		}
	}
	r.compiled = true
	return nil
}
func ( r * RegexLexer ) maybeCompile ( ) ( err error ) { r . mu . Lock ( ) defer r . mu . Unlock ( ) if r . compiled { return nil } for state , rules := range r . rules { for i , rule := range rules { if rule . Regexp == nil { pattern := " " + rule . Pattern + " " if rule . flags != " " { pattern = " " + rule . flags + " " + pattern } pattern = `\G` + pattern rule . Regexp , err = regexp2 . Compile ( pattern , 0 ) if err != nil { return fmt . Errorf ( " " , state , i , err ) } } } } restart : seen := map [ LexerMutator ] bool { } for state := range r . rules { for i := 0 ; i < len ( r . rules [ state ] ) ; i ++ { rule := r . rules [ state ] [ i ] if compile , ok := rule . Mutator . ( LexerMutator ) ; ok { if seen [ compile ] { return fmt . Errorf ( " " , compile ) } seen [ compile ] = true if err := compile . MutateLexer ( r . rules , state , i ) ; err != nil { return err } goto restart } } } r . compiled = true return nil }
Regex compilation is deferred until the lexer is used.
Regex compilation is deferred until the lexer is used .
// Process the rules again in case the mutator added/removed rules. // // This sounds bad, but shouldn't be significant in practice.