// Package lexer provides basic helpers to implement parsers package lexer import "io" // Lexer adds Accept and AcceptAll support to a // [io.RuneScanner] type Lexer struct { io.RuneScanner } // Accept consumes a rune from the source if it meets the condition. // it returns true if the condition was met and false if it wasn't. func (p Lexer) Accept(cond func(rune) bool) bool { return Accept(p, cond) } // AcceptAll consumes runes from the source as long as they meet the // condition. it returns true if the condition was met for at least one rune, // and false if it wasn't. func (p Lexer) AcceptAll(cond func(rune) bool) bool { return AcceptAll(p, cond) } // NewLexer extends a [io.RuneScanner] with Accept()/AcceptAll() // functionality func NewLexer(src io.RuneScanner) *Lexer { if src == nil { return nil } return &Lexer{src} } // StateFn is a State Function of the parser type StateFn func() (StateFn, error) // Run runs a state machine until the state function either // returns nil or an error func Run(fn StateFn) error { var err error for fn != nil && err == nil { fn, err = fn() } return err } // Accept consumes a rune from the source if it meets the condition. // it returns true if the condition was met and false if it wasn't. func Accept(src io.RuneScanner, cond func(r rune) bool) bool { r, _, err := src.ReadRune() switch { case err != nil: return false case cond(r): return true default: _ = src.UnreadRune() return false } } // AcceptAll consumes runes from the source as long as they meet the // condition. it returns true if the condition was met for at least one rune, // and false if it wasn't. func AcceptAll(src io.RuneScanner, cond func(r rune) bool) bool { var accepted bool for { r, _, err := src.ReadRune() switch { case err != nil: return accepted case cond(r): accepted = true default: _ = src.UnreadRune() return accepted } } }