-
Notifications
You must be signed in to change notification settings - Fork 0
/
token.go
81 lines (66 loc) · 2.26 KB
/
token.go
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
package token
import (
"fmt"
"github.com/flier/gocombine/pkg/parser"
"github.com/flier/gocombine/pkg/stream"
"golang.org/x/exp/slices"
)
// Any parses any token.
func Any[T stream.Token]() parser.Func[T, T] {
return func(input []T) (T, []T, error) {
return stream.Uncons(input)
}
}
// Token parses a character and succeeds if the character is equal to `tok`.
func Token[T stream.Token](tok T) parser.Func[T, T] {
return func(input []T) (actual T, remaining []T, err error) {
if actual, remaining, err = stream.Uncons(input); err != nil {
// pass
} else if actual != tok {
err = parser.UnexpectedToken(actual, tok)
}
return
}
}
// Tokens parses multiple tokens.
//
// Consumes items from the input and compares them to the values from `tokens` using the
/// comparison function `cmp`. Succeeds if all the items from `tokens` are matched in the input
/// stream and fails otherwise with `expected` used as part of the error.
func Tokens[T stream.Token](cmp func(lhs, rhs T) bool, expected, tokens []T) parser.Func[T, []T] {
return func(input []T) (actual []T, remaining []T, err error) {
actual = make([]T, len(tokens))
remaining = input
for i, tok := range tokens {
if actual[i], remaining, err = stream.Uncons(remaining); err != nil {
actual = actual[:i]
break
}
if !cmp(actual[i], tok) {
actual = actual[:i+1]
err = parser.UnexpectedRange(expected, actual)
break
}
}
return
}
}
// OneOf extract one token and succeeds if it is part of `tokens`.
func OneOf[T stream.Token](tokens []T) parser.Func[T, T] {
return Satisfy(func(t T) bool { return slices.Contains(tokens, t) }).
Expected(fmt.Sprintf("one of %s", parser.FormatRange(tokens)))
}
// NoneOf extract one token and succeeds if it is not part of `tokens`.
func NoneOf[T stream.Token](tokens []T) parser.Func[T, T] {
return Satisfy(func(t T) bool { return !slices.Contains(tokens, t) }).
Expected(fmt.Sprintf("none of %s", parser.FormatRange(tokens)))
}
// EOF succeeds only if the stream is at end of input, fails otherwise.
func EOF[T stream.Token]() parser.Func[T, bool] {
return parser.Expected(func(input []T) (bool, []T, error) {
if stream.Empty(input) {
return true, input, nil
}
return false, input, parser.UnexpectedRange(nil, input)
}, "eof")
}