Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/rdflib/plugins/sparql/parserutils.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
comparison
equal
deleted
inserted
replaced
1:75ca89e9b81c | 2:6af9afd405e9 |
---|---|
1 | |
2 from types import MethodType | |
3 | |
4 from rdflib.plugins.sparql.compat import OrderedDict | |
5 | |
6 from pyparsing import TokenConverter, ParseResults | |
7 | |
8 from rdflib import BNode, Variable, URIRef | |
9 | |
10 DEBUG = True | |
11 DEBUG = False | |
12 if DEBUG: | |
13 import traceback | |
14 | |
15 """ | |
16 | |
17 NOTE: PyParsing setResultName/__call__ provides a very similar solution to this | |
18 I didn't realise at the time of writing and I will remove a | |
19 lot of this code at some point | |
20 | |
21 Utility classes for creating an abstract-syntax tree out with pyparsing actions | |
22 | |
23 Lets you label and group parts of parser production rules | |
24 | |
25 For example: | |
26 | |
27 # [5] BaseDecl ::= 'BASE' IRIREF | |
28 BaseDecl = Comp('Base', Keyword('BASE') + Param('iri',IRIREF)) | |
29 | |
30 After parsing, this gives you back an CompValue object, | |
31 which is a dict/object with the paramters specified. | |
32 So you can access the parameters are attributes or as keys: | |
33 | |
34 baseDecl.iri | |
35 | |
36 Comp lets you set an evalFn that is bound to the eval method of | |
37 the resulting CompValue | |
38 | |
39 | |
40 """ | |
41 | |
42 | |
43 # This is an alternative | |
44 | |
45 # Comp('Sum')( Param('x')(Number) + '+' + Param('y')(Number) ) | |
46 | |
47 def value(ctx, val, variables=False, errors=False): | |
48 | |
49 """ | |
50 utility function for evaluating something... | |
51 | |
52 Variables will be looked up in the context | |
53 Normally, non-bound vars is an error, | |
54 set variables=True to return unbound vars | |
55 | |
56 Normally, an error raises the error, | |
57 set errors=True to return error | |
58 | |
59 """ | |
60 | |
61 if isinstance(val, Expr): | |
62 return val.eval(ctx) # recurse? | |
63 elif isinstance(val, CompValue): | |
64 raise Exception("What do I do with this CompValue? %s" % val) | |
65 | |
66 elif isinstance(val, list): | |
67 return [value(ctx, x, variables, errors) for x in val] | |
68 | |
69 elif isinstance(val, (BNode, Variable)): | |
70 r = ctx.get(val) | |
71 if isinstance(r, SPARQLError) and not errors: | |
72 raise r | |
73 if r is not None: | |
74 return r | |
75 | |
76 # not bound | |
77 if variables: | |
78 return val | |
79 else: | |
80 raise NotBoundError | |
81 | |
82 elif isinstance(val, ParseResults) and len(val) == 1: | |
83 return value(ctx, val[0], variables, errors) | |
84 else: | |
85 return val | |
86 | |
87 | |
88 class ParamValue(object): | |
89 """ | |
90 The result of parsing a Param | |
91 This just keeps the name/value | |
92 All cleverness is in the CompValue | |
93 """ | |
94 def __init__(self, name, tokenList, isList): | |
95 self.isList = isList | |
96 self.name = name | |
97 if isinstance(tokenList, (list, ParseResults)) and len(tokenList) == 1: | |
98 tokenList = tokenList[0] | |
99 | |
100 self.tokenList = tokenList | |
101 | |
102 def __str__(self): | |
103 return "Param(%s, %s)" % (self.name, self.tokenList) | |
104 | |
105 | |
106 class Param(TokenConverter): | |
107 """ | |
108 A pyparsing token for labelling a part of the parse-tree | |
109 if isList is true repeat occurrences of ParamList have | |
110 their values merged in a list | |
111 """ | |
112 def __init__(self, name, expr, isList=False): | |
113 self.name = name | |
114 self.isList = isList | |
115 TokenConverter.__init__(self, expr) | |
116 self.addParseAction(self.postParse2) | |
117 | |
118 def postParse2(self, tokenList): | |
119 return ParamValue(self.name, tokenList, self.isList) | |
120 | |
121 | |
122 class ParamList(Param): | |
123 """ | |
124 A shortcut for a Param with isList=True | |
125 """ | |
126 def __init__(self, name, expr): | |
127 Param.__init__(self, name, expr, True) | |
128 | |
129 | |
130 class plist(list): | |
131 """this is just a list, but we want our own type to check for""" | |
132 | |
133 pass | |
134 | |
135 | |
136 class CompValue(OrderedDict): | |
137 | |
138 """ | |
139 The result of parsing a Comp | |
140 Any included Params are avaiable as Dict keys | |
141 or as attributes | |
142 | |
143 """ | |
144 | |
145 def __init__(self, name, **values): | |
146 OrderedDict.__init__(self) | |
147 self.name = name | |
148 self.update(values) | |
149 | |
150 def clone(self): | |
151 return CompValue(self.name, **self) | |
152 | |
153 def __str__(self): | |
154 return self.name + "_" + OrderedDict.__str__(self) | |
155 | |
156 def __repr__(self): | |
157 return self.name + "_" + dict.__repr__(self) | |
158 | |
159 def _value(self, val, variables=False, errors=False): | |
160 if self.ctx is not None: | |
161 return value(self.ctx, val, variables) | |
162 else: | |
163 return val | |
164 | |
165 def __getitem__(self, a): | |
166 return self._value(OrderedDict.__getitem__(self, a)) | |
167 | |
168 def get(self, a, variables=False, errors=False): | |
169 return self._value(OrderedDict.get(self, a, a), variables, errors) | |
170 | |
171 def __getattr__(self, a): | |
172 # Hack hack: OrderedDict relies on this | |
173 if a in ('_OrderedDict__root', '_OrderedDict__end'): | |
174 raise AttributeError | |
175 try: | |
176 return self[a] | |
177 except KeyError: | |
178 # raise AttributeError('no such attribute '+a) | |
179 return None | |
180 | |
181 | |
182 class Expr(CompValue): | |
183 """ | |
184 A CompValue that is evaluatable | |
185 """ | |
186 | |
187 def __init__(self, name, evalfn=None, **values): | |
188 super(Expr, self).__init__(name, **values) | |
189 | |
190 self._evalfn = None | |
191 if evalfn: | |
192 self._evalfn = MethodType(evalfn, self) | |
193 | |
194 def eval(self, ctx={}): | |
195 try: | |
196 self.ctx = ctx | |
197 return self._evalfn(ctx) | |
198 except SPARQLError as e: | |
199 return e | |
200 finally: | |
201 self.ctx = None | |
202 | |
203 | |
204 class Comp(TokenConverter): | |
205 | |
206 """ | |
207 A pyparsing token for grouping together things with a label | |
208 Any sub-tokens that are not Params will be ignored. | |
209 | |
210 Returns CompValue / Expr objects - depending on whether evalFn is set. | |
211 """ | |
212 | |
213 def __init__(self, name, expr): | |
214 TokenConverter.__init__(self, expr) | |
215 self.name = name | |
216 self.evalfn = None | |
217 | |
218 def postParse(self, instring, loc, tokenList): | |
219 | |
220 if self.evalfn: | |
221 res = Expr(self.name) | |
222 res._evalfn = MethodType(self.evalfn, res) | |
223 else: | |
224 res = CompValue(self.name) | |
225 | |
226 for t in tokenList: | |
227 if isinstance(t, ParamValue): | |
228 if t.isList: | |
229 if not t.name in res: | |
230 res[t.name] = plist() | |
231 res[t.name].append(t.tokenList) | |
232 else: | |
233 res[t.name] = t.tokenList | |
234 # res.append(t.tokenList) | |
235 # if isinstance(t,CompValue): | |
236 # res.update(t) | |
237 return res | |
238 | |
239 def setEvalFn(self, evalfn): | |
240 self.evalfn = evalfn | |
241 return self | |
242 | |
243 | |
244 def prettify_parsetree(t, indent='', depth=0): | |
245 out = [] | |
246 if isinstance(t, ParseResults): | |
247 for e in t.asList(): | |
248 out.append(prettify_parsetree(e, indent, depth + 1)) | |
249 for k, v in sorted(t.items()): | |
250 out.append("%s%s- %s:\n" % (indent, ' ' * depth, k)) | |
251 out.append(prettify_parsetree(v, indent, depth + 1)) | |
252 elif isinstance(t, CompValue): | |
253 out.append("%s%s> %s:\n" % (indent, ' ' * depth, t.name)) | |
254 for k, v in list(t.items()): | |
255 out.append("%s%s- %s:\n" % (indent, ' ' * (depth + 1), k)) | |
256 out.append(prettify_parsetree(v, indent, depth + 2)) | |
257 elif isinstance(t, dict): | |
258 for k, v in list(t.items()): | |
259 out.append("%s%s- %s:\n" % (indent, ' ' * (depth + 1), k)) | |
260 out.append(prettify_parsetree(v, indent, depth + 2)) | |
261 elif isinstance(t, list): | |
262 for e in t: | |
263 out.append(prettify_parsetree(e, indent, depth + 1)) | |
264 else: | |
265 out.append("%s%s- %r\n" % (indent, ' ' * depth, t)) | |
266 return "".join(out) | |
267 | |
268 | |
269 if __name__ == '__main__': | |
270 from pyparsing import Word, nums | |
271 import sys | |
272 | |
273 Number = Word(nums) | |
274 Number.setParseAction(lambda x: int(x[0])) | |
275 Plus = Comp('plus', Param('a', Number) + '+' + Param('b', Number)) | |
276 Plus.setEvalFn(lambda self, ctx: self.a + self.b) | |
277 | |
278 r = Plus.parseString(sys.argv[1]) | |
279 print(r) | |
280 print(r[0].eval({})) | |
281 | |
282 # hurrah for circular imports | |
283 from rdflib.plugins.sparql.sparql import SPARQLError, NotBoundError |