forked from svelterust/vom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
combinator.v
119 lines (107 loc) · 3.25 KB
/
combinator.v
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
module vom
// Based on https://docs.rs/nom/7.1.3/nom/combinator/index.html
// all_consuming succeeds if all the input has been consumed by its child parser `f`.
pub fn all_consuming(f Fn) Fn {
return fn [f] (input string) !(string, string, int) {
rest, output, len := f(input)!
if rest.len == 0 {
return rest, output, len
} else {
return error('`all_consuming` failed because ${rest} is not empty')
}
}
}
// cond calls the parser `f` if the condition `b` is true.
pub fn cond(b bool, f Fn) Fn {
return fn [b, f] (input string) !(string, string, int) {
if b {
return f(input)
} else {
return input, '', 0
}
}
}
// eof returns its input if it is at the end of input data
pub fn eof(input string) !(string, string, int) {
if input.len == 0 {
return input, input, 0
} else {
return error('`eof` failed because ${input} is not empty')
}
}
// fail return fail.
pub fn fail(input string) !(string, string, int) {
return error('`fail` failed')
}
/*
// flat_map creates a new parser from the output of the first parser, then apply that parser over the rest of the input.
pub fn flat_map(parser Fn, applied_parser Fn) Fn {
return fn [parser, applied_parser] (input string) !(string, string) {
_, a := parser(input) !
return applied_parser(a) !
}
}
*/
// not succeeds if the child parser `f` returns an error.
pub fn not(f Fn) Fn {
return fn [f] (input string) !(string, string, int) {
f(input) or { return input, '', 0 }
return error('`not` failed because function succeded')
}
}
// opt Optional parser: Will return '' if not successful.
pub fn opt(f Fn) Fn {
return fn [f] (input string) !(string, string, int) {
rest, output, len := f(input) or { return input, '', 0 }
return rest, output, len
}
}
// peek tries to apply its parser `f` without consuming the input.
pub fn peek(f Fn) Fn {
return fn [f] (input string) !(string, string, int) {
_, output, len := f(input)!
return input, output, len
}
}
// recognize if the child parser `f` was successful, return the consumed input as produced value.
pub fn recognize(f Parser) Fn {
parsers := [f]
return fn [parsers] (input string) !(string, string, int) {
f := parsers[0]
match f {
Fn {
rest, _, len1 := f(input)!
return rest, input[..input.len - rest.len], len1
}
FnMany {
rest, _, len2 := f(input)!
return rest, input[..input.len - rest.len], len2
}
FnCount {
return error("`recognize` can't use with FnCount type.")
}
FnResult {
return error("`recognize` can't use with FnResult type.")
}
}
}
}
// value returns the provided value `val` if the child parser `f` succeeds.
pub fn value[T](val T, f Fn) fn (string) !T {
return fn [val, f] [T](input string) !T {
f(input) or { return error('`value` fail') }
return val
}
}
// verify returns the result of the child parser `first` if it satisfies a verification function `second`.
// The verification function `second` takes as argument a reference to the output of the parser `first`.
pub fn verify(first Fn, second fn (string) bool) fn (string) !string {
return fn [first, second] (input string) !string {
_, output, _ := first(input) or { return error('`verify` fail') }
if second(output) {
return output
} else {
return error('`verify` ${second} fail')
}
}
}