diff planemo/lib/python3.7/site-packages/rdflib/plugins/sparql/parserutils.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/planemo/lib/python3.7/site-packages/rdflib/plugins/sparql/parserutils.py	Fri Jul 31 00:32:28 2020 -0400
@@ -0,0 +1,283 @@
+
+from types import MethodType
+
+from rdflib.plugins.sparql.compat import OrderedDict
+
+from pyparsing import TokenConverter, ParseResults
+
+from rdflib import BNode, Variable, URIRef
+
+DEBUG = True
+DEBUG = False
+if DEBUG:
+    import traceback
+
+"""
+
+NOTE: PyParsing setResultName/__call__ provides a very similar solution to this
+I didn't realise at the time of writing and I will remove a
+lot of this code at some point
+
+Utility classes for creating an abstract-syntax tree out with pyparsing actions
+
+Lets you label and group parts of parser production rules
+
+For example:
+
+# [5] BaseDecl ::= 'BASE' IRIREF
+BaseDecl = Comp('Base', Keyword('BASE') + Param('iri',IRIREF))
+
+After parsing, this gives you back an CompValue object,
+which is a dict/object with the paramters specified.
+So you can access the parameters are attributes or as keys:
+
+baseDecl.iri
+
+Comp lets you set an evalFn that is bound to the eval method of
+the resulting CompValue
+
+
+"""
+
+
+# This is an alternative
+
+# Comp('Sum')( Param('x')(Number) + '+' + Param('y')(Number) )
+
+def value(ctx, val, variables=False, errors=False):
+
+    """
+    utility function for evaluating something...
+
+    Variables will be looked up in the context
+    Normally, non-bound vars is an error,
+    set variables=True to return unbound vars
+
+    Normally, an error raises the error,
+    set errors=True to return error
+
+    """
+
+    if isinstance(val, Expr):
+        return val.eval(ctx)  # recurse?
+    elif isinstance(val, CompValue):
+        raise Exception("What do I do with this CompValue? %s" % val)
+
+    elif isinstance(val, list):
+        return [value(ctx, x, variables, errors) for x in val]
+
+    elif isinstance(val, (BNode, Variable)):
+        r = ctx.get(val)
+        if isinstance(r, SPARQLError) and not errors:
+            raise r
+        if r is not None:
+            return r
+
+        # not bound
+        if variables:
+            return val
+        else:
+            raise NotBoundError
+
+    elif isinstance(val, ParseResults) and len(val) == 1:
+        return value(ctx, val[0], variables, errors)
+    else:
+        return val
+
+
+class ParamValue(object):
+    """
+    The result of parsing a Param
+    This just keeps the name/value
+    All cleverness is in the CompValue
+    """
+    def __init__(self, name, tokenList, isList):
+        self.isList = isList
+        self.name = name
+        if isinstance(tokenList, (list, ParseResults)) and len(tokenList) == 1:
+            tokenList = tokenList[0]
+
+        self.tokenList = tokenList
+
+    def __str__(self):
+        return "Param(%s, %s)" % (self.name, self.tokenList)
+
+
+class Param(TokenConverter):
+    """
+    A pyparsing token for labelling a part of the parse-tree
+    if isList is true repeat occurrences of ParamList have
+    their values merged in a list
+    """
+    def __init__(self, name, expr, isList=False):
+        self.name = name
+        self.isList = isList
+        TokenConverter.__init__(self, expr)
+        self.addParseAction(self.postParse2)
+
+    def postParse2(self, tokenList):
+        return ParamValue(self.name, tokenList, self.isList)
+
+
+class ParamList(Param):
+    """
+    A shortcut for a Param with isList=True
+    """
+    def __init__(self, name, expr):
+        Param.__init__(self, name, expr, True)
+
+
+class plist(list):
+    """this is just a list, but we want our own type to check for"""
+
+    pass
+
+
+class CompValue(OrderedDict):
+
+    """
+    The result of parsing a Comp
+    Any included Params are avaiable as Dict keys
+    or as attributes
+
+    """
+
+    def __init__(self, name, **values):
+        OrderedDict.__init__(self)
+        self.name = name
+        self.update(values)
+
+    def clone(self):
+        return CompValue(self.name, **self)
+
+    def __str__(self):
+        return self.name + "_" + OrderedDict.__str__(self)
+
+    def __repr__(self):
+        return self.name + "_" + dict.__repr__(self)
+
+    def _value(self, val, variables=False, errors=False):
+        if self.ctx is not None:
+            return value(self.ctx, val, variables)
+        else:
+            return val
+
+    def __getitem__(self, a):
+        return self._value(OrderedDict.__getitem__(self, a))
+
+    def get(self, a, variables=False, errors=False):
+        return self._value(OrderedDict.get(self, a, a), variables, errors)
+
+    def __getattr__(self, a):
+        # Hack hack: OrderedDict relies on this
+        if a in ('_OrderedDict__root', '_OrderedDict__end'):
+            raise AttributeError
+        try:
+            return self[a]
+        except KeyError:
+            # raise AttributeError('no such attribute '+a)
+            return None
+
+
+class Expr(CompValue):
+    """
+    A CompValue that is evaluatable
+    """
+
+    def __init__(self, name, evalfn=None, **values):
+        super(Expr, self).__init__(name, **values)
+
+        self._evalfn = None
+        if evalfn:
+            self._evalfn = MethodType(evalfn, self)
+
+    def eval(self, ctx={}):
+        try:
+            self.ctx = ctx
+            return self._evalfn(ctx)
+        except SPARQLError as e:
+            return e
+        finally:
+            self.ctx = None
+
+
+class Comp(TokenConverter):
+
+    """
+    A pyparsing token for grouping together things with a label
+    Any sub-tokens that are not Params will be ignored.
+
+    Returns CompValue / Expr objects - depending on whether evalFn is set.
+    """
+
+    def __init__(self, name, expr):
+        TokenConverter.__init__(self, expr)
+        self.name = name
+        self.evalfn = None
+
+    def postParse(self, instring, loc, tokenList):
+
+        if self.evalfn:
+            res = Expr(self.name)
+            res._evalfn = MethodType(self.evalfn, res)
+        else:
+            res = CompValue(self.name)
+
+        for t in tokenList:
+            if isinstance(t, ParamValue):
+                if t.isList:
+                    if not t.name in res:
+                        res[t.name] = plist()
+                    res[t.name].append(t.tokenList)
+                else:
+                    res[t.name] = t.tokenList
+                # res.append(t.tokenList)
+            # if isinstance(t,CompValue):
+            #    res.update(t)
+        return res
+
+    def setEvalFn(self, evalfn):
+        self.evalfn = evalfn
+        return self
+
+
+def prettify_parsetree(t, indent='', depth=0):
+        out = []
+        if isinstance(t, ParseResults):
+            for e in t.asList():
+                out.append(prettify_parsetree(e, indent, depth + 1))
+            for k, v in sorted(t.items()):
+                out.append("%s%s- %s:\n" % (indent, '  ' * depth, k))
+                out.append(prettify_parsetree(v, indent, depth + 1))
+        elif isinstance(t, CompValue):
+            out.append("%s%s> %s:\n" % (indent, '  ' * depth, t.name))
+            for k, v in list(t.items()):
+                out.append("%s%s- %s:\n" % (indent, '  ' * (depth + 1), k))
+                out.append(prettify_parsetree(v, indent, depth + 2))
+        elif isinstance(t, dict):
+            for k, v in list(t.items()):
+                out.append("%s%s- %s:\n" % (indent, '  ' * (depth + 1), k))
+                out.append(prettify_parsetree(v, indent, depth + 2))
+        elif isinstance(t, list):
+            for e in t:
+                out.append(prettify_parsetree(e, indent, depth + 1))
+        else:
+            out.append("%s%s- %r\n" % (indent, '  ' * depth, t))
+        return "".join(out)
+
+
+if __name__ == '__main__':
+    from pyparsing import Word, nums
+    import sys
+
+    Number = Word(nums)
+    Number.setParseAction(lambda x: int(x[0]))
+    Plus = Comp('plus', Param('a', Number) + '+' + Param('b', Number))
+    Plus.setEvalFn(lambda self, ctx: self.a + self.b)
+
+    r = Plus.parseString(sys.argv[1])
+    print(r)
+    print(r[0].eval({}))
+
+# hurrah for circular imports
+from rdflib.plugins.sparql.sparql import SPARQLError, NotBoundError