From d83b128c30087bed68d8c940c463d9994462eb38 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Mon, 28 Aug 2023 22:35:30 +0000 Subject: [PATCH 1/2] lexer: introduce Reader.Accept()/AcceptAll() Signed-off-by: Alejandro Mery --- lexer/reader.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lexer/reader.go b/lexer/reader.go index 7c0aaa3..6ab8c6b 100644 --- a/lexer/reader.go +++ b/lexer/reader.go @@ -198,6 +198,41 @@ func (b *Reader) PeekRune() (rune, int, error) { return r, l, 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 (b *Reader) Accept(cond func(r rune) bool) bool { + r, _, err := b.ReadRune() + switch { + case err != nil: + return false + case cond(r): + return true + default: + _ = b.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 (b *Reader) AcceptAll(cond func(r rune) bool) bool { + var accepted bool + + for { + r, _, err := b.ReadRune() + switch { + case err != nil: + return accepted + case cond(r): + accepted = true + default: + _ = b.UnreadRune() + return accepted + } + } +} + // NewReader creates a new runes [Reader] using the given [io.Reader] func NewReader(r io.Reader) *Reader { if r == nil { From 1d62857e14d89b4846d9dd8f15c9fae0e99467f0 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Mon, 28 Aug 2023 22:14:45 +0000 Subject: [PATCH 2/2] lexer: introduce StateFn and the basic state machine loop v2: make the error break more explicit Signed-off-by: Alejandro Mery --- lexer/lexer.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lexer/lexer.go b/lexer/lexer.go index 33b17b6..e23ecad 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -1,2 +1,22 @@ // Package lexer provides basic helpers to implement parsers package lexer + +// 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 { + for fn != nil { + var err error + + fn, err = fn() + if err != nil { + // failed + return err + } + } + + // ended + return nil +}