-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparsers.py
120 lines (107 loc) · 1.96 KB
/
parsers.py
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
from parser import parser
def strs(*ss):
@parser
def strs(s):
for p in ss:
if s.startswith(p):
yield p,s[len(p):]
return strs
def strip(p):
@parser
def strip(s):
yield from p(s.lstrip())
return strip
def alternate(*ps):
@parser
def alternate(s):
for i,p in enumerate(ps):
for data,s2 in p(s):
yield (i,data),s2
return alternate
def concat(*ps):
if len(ps)==0:
@parser
def concatinner(s):
yield (),s
return concatinner
p1=ps[0]
p2=concat(*ps[1:])
@parser
def concatinner(s):
for data1,s2 in p1(s):
for data2,s3 in p2(s2):
yield (data1,)+data2,s3
return concatinner
# def concat(p1,p2):
# @parser
# def concat(s):
# for data1,s2 in p1(s):
# for data2,s3 in p2(s2):
# yield (data1,data2),s3
# return concat
def star(p):
newparser=None
@parser
def star(s):
return newparser(s)
@transform(star)
def star(data):
if data is None:
return []
return [data[0],*data[1]]
newparser=optional(concat(p,star))
return star
# use as decorator
# @transform(concat(a,b))
def transform(p):
def transform(f):
@parser
def transform(s):
for data,s2 in p(s):
yield f(data),s2
return transform
return transform
# use as decorator
# function returning data,s pair
def parserify(f):
@parser
def parserified(s):
yield f(s)
return parserified
def optional(p,default=None):
@parser
def optional(s):
yield from p(s)
yield default,s
return optional
def errornone(p):
@parser
def errornone(s):
it=iter(p(s))
try:
yield next(it) # make sure there's at least one result
except StopIteration:
raise Exception('no choices')
yield from it
return errornone
def errorafter(p):
@parser
def errorafter(s):
yield from p(s)
raise Exception('ran out of choices')
return errorafter
def atomic(p): # return 0 or 1 results
@parser
def atomic(s):
it=iter(p(s))
yield next(it)
return atomic
def noneerror(p):
@parser
def noneerror(s):
try:
for x in p(s):
yield x
except:
pass
return noneerror