+ }
+ }
+
+ func tag(t string) parser[string] {
+ b := []byte(t)
+ return func(input []byte) (rest []byte, value string, err error) {
+ if bytes.HasPrefix(input, b) {
+ return input[len(b):], t, nil
+ } else {
+ return input, "", fmt.Errorf("not found: %q", t)
+ }
+ }
+ }
+
+ func value[T, U any](val T, p parser[U]) parser[T] {
+ return func(input []byte) (rest []byte, value T, err error) {
+ rest, _, err = p(input)
+ if err != nil {
+ return input, value, err
+ }
+ return rest, val, nil
+ }
+ }
+
+ // takeAny returns the longest input slice (if any) that contains only
+ // characters found in set.
+ func takeAny(set string) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest = bytes.TrimLeft(input, set)
+ return rest, input[:len(input)-len(rest)], nil
+ }
+ }
+
+ // takeAny1 returns the longest input slice that contains only
+ // characters found in set. If it doesn't find at least one byte that matches,
+ // it returns an error.
+ func takeAny1(set string) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest = bytes.TrimLeft(input, set)
+ if len(rest) == len(input) {
+ return input, nil, fmt.Errorf("nothing matching %q was found", set)
+ }
+ return rest, input[:len(input)-len(rest)], nil
+ }
+ }
+
+ func positiveInt(input []byte) (rest []byte, value int, err error) {
+ return mapWithError(
+ takeAny1("0123456789"),
+ func(b []byte) (int, error) {
+ return strconv.Atoi(string(b))
+ },
+ )(input)
+ }
+
+ func delimited[T, U, V any](left parser[T], inner parser[U], right parser[V]) parser[U] {
+ return func(input []byte) (rest []byte, value U, err error) {
+ rest, _, err = left(input)
+ if err != nil {
+ return
+ }
+ rest, value, err = inner(rest)
+ if err != nil {
+ return
+ }
+ rest, _, err = right(rest)
+ return
+ }
+ }
+
+ func terminated[T, U any](first parser[T], second parser[U]) parser[T] {
+ return func(input []byte) (rest []byte, value T, err error) {
+ rest, value, err = first(input)
+ if err != nil {
+ return
+ }
+ rest, _, err = second(rest)
+ return
+ }
+ }
+
+ func preceded[T, U any](first parser[T], second parser[U]) parser[U] {
+ return func(input []byte) (rest []byte, value U, err error) {
+ rest, _, err = first(input)
+ if err != nil {
+ return
+ }
+ rest, value, err = second(rest)
+ return
+ }
+ }
+
+ func space0(input []byte) (rest []byte, value []byte, err error) {
+ return takeAny(" \t")(input)
+ }
+
+ func multispace0(input []byte) (rest []byte, value []byte, err error) {
+ return takeAny(" \t\r\n")(input)
+ }
+
+ func lineEnding(input []byte) (rest []byte, value string, err error) {
+ return alt(tag("\n"), tag("\r\n"))(input)
+ }
+
+ func takeWhile(f func(byte) bool) parser[[]byte] {
+ return func(input []byte) ([]byte, []byte, error) {
+ i := 0
+ for i < len(input) && f(input[i]) {
+ i++
+ }
+ return input[i:], input[:i], nil
+ }
+ }
+
+ func recognize[T any](p parser[T]) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest, _, err = p(input)
+ if err != nil {
+ return
+ }
+ return rest, input[:len(input)-len(rest)], nil
+ }
+ }
+
+ func recognize2[T, U any](p1 parser[T], p2 parser[U]) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest, _, err = p1(input)
+ if err != nil {
+ return
+ }
+ rest, _, err = p2(rest)
+ if err != nil {
+ return
+ }
+ return rest, input[:len(input)-len(rest)], nil
+ }
+ }
+
+ func recognize3[T, U, V any](p1 parser[T], p2 parser[U], p3 parser[V]) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest, _, err = p1(input)
+ if err != nil {
+ return
+ }
+ rest, _, err = p2(rest)
+ if err != nil {
+ return
+ }
+ rest, _, err = p3(rest)
+ if err != nil {
+ return
+ }
+ return rest, input[:len(input)-len(rest)], nil
+ }
+ }
+
+ func recognize4[T, U, V, W any](p1 parser[T], p2 parser[U], p3 parser[V], p4 parser[W]) parser[[]byte] {
+ return func(input []byte) (rest []byte, value []byte, err error) {
+ rest, _, err = p1(input)
+ if err != nil {
+ return
+ }
+ rest, _, err = p2(rest)
+ if err != nil {
+ return
+ }
+ rest, _, err = p3(rest)
+ if err != nil {
+ return
+ }
+ rest, _, err = p4(rest)
+ if err != nil {
+ return
+ }
+ return rest, input[:len(input)-len(rest)], nil