Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/rdflib/plugins/sparql/parserutils.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
| author | shellac |
|---|---|
| date | Mon, 01 Jun 2020 08:59:25 -0400 |
| parents | 79f47841a781 |
| children |
comparison
equal
deleted
inserted
replaced
| 4:79f47841a781 | 5:9b1c78e6ba9c |
|---|---|
| 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 |
