build-a-regex-engine / lesson-27.md
Lesson 27 · Search, captures & the public API

Compile and error handling

A real regex library compiles a pattern once into a reusable object and reports bad patterns instead of crashing. Today you introduce the Regexp type and turn parse failures into errors.

The goal

Add Compile, returning a reusable Regexp for a valid pattern or an error for an invalid one.

Start here - the target
TO DO
Scenario: Compile validates a pattern and returns a reusable object
Giventhe pattern "(" with an unbalanced parenthesis
WhenCompile is called on it
Thenit returns a non-nil error
AndCompile on "ab" returns a Regexp and no error
Andthat Regexp matches "zabz" (contains "ab")
Background

Until now every call re-parsed the pattern, and a malformed pattern like ( would misbehave silently or panic. A library needs to do better on both counts. Compile parses the pattern once into a Regexp value you can reuse across many matches, and it returns an error when the pattern is invalid - an unbalanced ( or [, or a dangling backslash. This is the entry point real callers use, and it mirrors how Go’s own regexp.Compile works. (You can tighten up other cases, like a malformed {n,m}, on a later lesson - keep today to the two or three unmistakable errors.)

The work is mostly in the parser: instead of assuming well-formed input, each place that expects a closing ) or ] now reports an error if it hits the end of the pattern first. Thread those errors up and out of Compile. Your existing Match becomes a thin convenience wrapper - compile, then match - while Regexp.MatchString runs an already-compiled pattern. With a stable compiled object in hand, the rest of the chapter hangs richer queries off it: where a match is, and what its groups captured.

Make it work
type Regexp struct{ /* parsed AST, compiled NFA, group info */ }
func Compile(pat string) (*Regexp, error) {
// parser now RETURNS an error instead of assuming valid input:
// an unbalanced ( or [, or a trailing backslash.
}
func (re *Regexp) MatchString(s string) bool { /* reuse Match */ }
CheckpointDONE
Compile returns a reusable Regexp or a clear error, and MatchString runs it. Commit and stop here.