-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbytes.go
99 lines (82 loc) · 2.87 KB
/
bytes.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package gomme
import (
"fmt"
"strings"
)
// Take returns a subset of the input of size `count`.
func Take[Input Bytes](count uint) Parser[Input, Input] {
return func(input Input) Result[Input, Input] {
if len(input) == 0 && count > 0 {
return Failure[Input, Input](NewError(input, "TakeUntil"), input)
}
if uint(len(input)) < count {
return Failure[Input, Input](NewError(input, "Take"), input)
}
return Success(input[:count], input[count:])
}
}
// TakeUntil parses any number of characters until the provided parser is successful.
// If the provided parser is not successful, the parser fails, and the entire input is
// returned as the Result's Remaining.
func TakeUntil[Input Bytes, Output any](parse Parser[Input, Output]) Parser[Input, Input] {
return func(input Input) Result[Input, Input] {
if len(input) == 0 {
return Failure[Input, Input](NewError(input, "TakeUntil"), input)
}
pos := 0
for ; pos < len(input); pos++ {
current := input[pos:]
res := parse(current)
if res.Err == nil {
return Success(input[:pos], input[pos:])
}
continue
}
return Failure[Input, Input](NewError(input, "TakeUntil"), input)
}
}
// TakeWhileMN returns the longest input subset that matches the predicates, within
// the boundaries of `atLeast` <= len(input) <= `atMost`.
//
// If the provided parser is not successful or the pattern is out of the
// `atLeast` <= len(input) <= `atMost` range, the parser fails, and the entire
// input is returned as the Result's Remaining.
func TakeWhileMN[Input Bytes](atLeast, atMost uint, predicate func(rune) bool) Parser[Input, Input] {
return func(input Input) Result[Input, Input] {
if len(input) == 0 {
return Failure[Input, Input](NewError(input, "TakeWhileMN"), input)
}
// Input is shorter than the minimum expected matching length,
// it is thus not possible to match it within the established
// constraints.
if uint(len(input)) < atLeast {
return Failure[Input, Input](NewError(input, "TakeWhileMN"), input)
}
lastValidPos := 0
for idx := 0; idx < len(input); idx++ {
if uint(idx) == atMost {
break
}
matched := predicate(rune(input[idx]))
if !matched {
if uint(idx) < atLeast {
return Failure[Input, Input](NewError(input, "TakeWhileMN"), input)
}
return Success(input[:idx], input[idx:])
}
lastValidPos++
}
return Success(input[:lastValidPos], input[lastValidPos:])
}
}
// Token parses a token from the input, and returns the part of the input that
// matched the token.
// If the token could not be found, the parser returns an error result.
func Token[Input Bytes](token string) Parser[Input, Input] {
return func(input Input) Result[Input, Input] {
if !strings.HasPrefix(string(input), token) {
return Failure[Input, Input](NewError(input, fmt.Sprintf("Token(%s)", token)), input)
}
return Success(input[:len(token)], input[len(token):])
}
}