1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
package parse
import (
"errors"
"github.com/digitalocean/go-qemu/qapi-schema/internal/token"
)
var (
// ErrNoMatch indicates parsing failed against the token stream.
ErrNoMatch = errors.New("no match")
// ErrNonExhaustiveParse indicates parsing completed but there were
// still tokens remaining in the input stream.
ErrNonExhaustiveParse = errors.New("did not consume all tokens")
)
// Parse applies the given parser against the input stream.
func Parse[T any](parser Parser[T], input []token.Token) (T, error) {
initial := state{input: input}
val, next, err := parser(initial)
if err != nil {
return val, err
}
if len(next.remaining()) > 0 {
return val, ErrNonExhaustiveParse
}
return val, nil
}
// Parser is a Parser function that can read an input token stream
// and produce the specified type or an error.
type Parser[T any] func(state) (T, state, error)
// Empty is an empty type to return when a parser successfully parsed
// the input stream and nothing should be returned.
type Empty struct{}
// Exactly consumes the exact token from the input stream or fails.
func Exactly(tok token.Token) Parser[Empty] {
return func(initial state) (Empty, state, error) {
if len(initial.remaining()) >= 1 {
if initial.remaining()[0] == tok {
return Empty{}, initial.consume(1), nil
}
}
return Empty{}, initial, ErrNoMatch
}
}
// MatchesToken consumes the token from the input stream if matcher
// returns true.
func MatchesToken(matcher func(token.Token) bool) Parser[token.Token] {
return func(initial state) (token.Token, state, error) {
if len(initial.remaining()) > 0 {
if matcher(initial.remaining()[0]) {
return initial.remaining()[0], initial.consume(1), nil
}
}
return token.Token{}, initial, ErrNoMatch
}
}
// Map converts one parser to another parser.
func Map[T any, U any](parser Parser[T], mapper func(T) U) Parser[U] {
return func(initial state) (U, state, error) {
val, next, err := parser(initial)
if err != nil {
var zero U
return zero, initial, err
}
return mapper(val), next, nil
}
}
// OneOf tries a list of parsers and if one of them succeeds, returns
// that parser.
func OneOf[T any](parsers ...Parser[T]) Parser[T] {
return func(initial state) (T, state, error) {
for _, parser := range parsers {
val, next, err := parser(initial)
if err == nil {
return val, next, nil
}
}
var zero T
return zero, initial, ErrNoMatch
}
}
// ManyOf attempts to successfully parse 0 or more times.
func ManyOf[T any](parser Parser[T]) Parser[[]T] {
return func(initial state) ([]T, state, error) {
var successes []T
current := initial
for {
val, next, err := parser(current)
if err != nil {
break
}
successes = append(successes, val)
current = next
}
return successes, current, nil
}
}
// ConsumeAtLeastOne attempts to parse at least once with the given
// parser and then continues until it fails to parse.
func ConsumeAtLeastOne[T any](parser Parser[T]) Parser[[]T] {
return func(initial state) ([]T, state, error) {
val, next, err := parser(initial)
if err != nil {
return nil, initial, err
}
current := next
successes := []T{val}
for {
val, next, err = parser(current)
if err != nil {
break
}
current = next
successes = append(successes, val)
}
return successes, current, nil
}
}
// Seq2 is a tuple of two parsed objects.
type Seq2[A any, B any] struct {
First A
Second B
}
// All2 requires both parsers to succeed and it returns a tuple
// of the parsed objects.
func All2[A any, B any](first Parser[A], second Parser[B]) Parser[Seq2[A, B]] {
return func(initial state) (Seq2[A, B], state, error) {
var val Seq2[A, B]
v1, next, err := first(initial)
if err != nil {
return val, initial, err
}
v2, next, err := second(next)
if err != nil {
return val, initial, err
}
val.First = v1
val.Second = v2
return val, next, nil
}
}
// Seq3 is a tuple of three parsed objects.
type Seq3[A any, B any, C any] struct {
First A
Second B
Third C
}
// All3 requires all three parsers to succeed and it returns a
// tuple of the parsed objects.
func All3[A any, B any, C any](first Parser[A], second Parser[B], third Parser[C]) Parser[Seq3[A, B, C]] {
return func(initial state) (Seq3[A, B, C], state, error) {
var val Seq3[A, B, C]
v1, next, err := first(initial)
if err != nil {
return val, initial, err
}
v2, next, err := second(next)
if err != nil {
return val, initial, err
}
v3, next, err := third(next)
if err != nil {
return val, initial, err
}
val.First = v1
val.Second = v2
val.Third = v3
return val, next, nil
}
}
// Nothing is a parser that always succeeds and doesn't consume input.
func Nothing() Parser[Empty] {
return func(initial state) (Empty, state, error) {
return Empty{}, initial, nil
}
}
type state struct {
input []token.Token
offset int
}
func (s state) remaining() []token.Token {
return s.input[s.offset:]
}
func (s state) consume(n int) state {
s.offset += n
return s
}
|