-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbasic.go
134 lines (114 loc) · 3.19 KB
/
basic.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
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
package chomp
import (
"strings"
)
// Tag must match a series of characters at the beginning of the input text
// in the exact order and case provided.
//
// chomp.Tag("Hello")("Hello, World!")
// // (", World!", "Hello", nil)
func Tag(str string) Combinator[string] {
return func(s string) (string, string, error) {
if strings.HasPrefix(s, str) {
return s[len(str):], str, nil
}
return s, "", CombinatorParseError{Input: str, Text: s, Type: "tag"}
}
}
// Any must match at least one character from the provided sequence at the
// beginning of the input text. Parsing stops upon the first unmatched character.
//
// chomp.Any("eH")("Hello, World!")
// // ("llo, World!", "He", nil)
func Any(str string) Combinator[string] {
return func(s string) (string, string, error) {
pos := 0
match:
for _, sc := range s {
for _, strc := range str {
if sc == strc {
pos = pos + len(string(strc))
continue match
}
}
break match
}
if pos == 0 {
return s, "", CombinatorParseError{Input: str, Text: s, Type: "any"}
}
return s[pos:], s[:pos], nil
}
}
// Not must not match at least one character at the beginning of the input text
// from the provided sequence. Parsing stops upon the first matched character.
//
// chomp.Not("ol")("Hello, World!")
// // ("llo, World!", "He", nil)
func Not(str string) Combinator[string] {
return func(s string) (string, string, error) {
pos := 0
match:
for _, sc := range s {
for _, strc := range str {
if sc == strc {
break match
}
}
pos = pos + len(string(sc))
}
if pos == 0 {
return s, "", CombinatorParseError{Input: str, Text: s, Type: "not"}
}
return s[pos:], s[:pos], nil
}
}
// OneOf must match a single character at the beginning of the text from
// the provided sequence.
//
// chomp.OneOf("!,eH")("Hello, World!")
// // ("ello, World!", "H", nil)
func OneOf(str string) Combinator[string] {
return func(s string) (string, string, error) {
if txt := []rune(s); len(txt) > 0 {
for _, strc := range str {
if txt[0] == strc {
pos := len(string(txt[0]))
return s[pos:], s[:pos], nil
}
}
}
return s, "", CombinatorParseError{Input: str, Text: s, Type: "one_of"}
}
}
// NoneOf must not match a single character at the beginning of the text
// from the provided sequence.
//
// chomp.NoneOf("loWrd!e")("Hello, World!")
// // ("ello, World!", "H", nil)
func NoneOf(str string) Combinator[string] {
return func(s string) (string, string, error) {
if txt := []rune(s); len(txt) > 0 {
for _, strc := range str {
if txt[0] == strc {
break
}
}
pos := len(string(txt[0]))
return s[pos:], s[:pos], nil
}
return s, "", CombinatorParseError{Input: str, Text: s, Type: "none_of"}
}
}
// Until will scan the input text for the first occurrence of the provided series
// of characters. Everything until that point in the text will be matched.
//
// chomp.Until("World")("Hello, World!")
// // ("World!", "Hello, ", nil)
func Until(str string) Combinator[string] {
return func(s string) (string, string, error) {
if idx := strings.Index(s, str); idx != -1 {
return s[idx:], s[:idx], nil
}
return s, "", CombinatorParseError{Input: str, Text: s, Type: "until"}
}
}