Source code for gavo.adql.tree

"""
Trees of ADQL expressions and operations on them.
"""

#c Copyright 2008-2020, the GAVO project
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


from gavo import utils
from gavo.adql import grammar
from gavo.adql import nodes

_grammarCache = None


_additionalNodes = []
[docs]def registerNode(node): """registers a node class or a symbolAction from a module other than node. This is a bit of magic -- some module can call this to register a node class that is then bound to some parse action as if it were in nodes. I'd expect this to be messy in the presence of chaotic imports (when classes are not necessarily singletons and a single module can be imported more than once. For now, I ignore this potential bomb. """ _additionalNodes.append(node)
[docs]def getTreeBuildingGrammar(): """returns a pyparsing symbol that can parse ADQL expressions into simple trees of ADQLNodes. This symbol is shared, so don't change anything on it. """ # To do the bindings, we iterate over the names in the node module, look for # all children classes derived from nodes.ADQLNode (but not ADQLNode itself) and # first check for a bindings attribute and then their type attribute. These # are then used to add actions to the corresponding symbols. global _grammarCache if _grammarCache: return _grammarCache syms, root = grammar.getADQLGrammarCopy() def bind(symName, nodeClass): try: if getattr(nodeClass, "collapsible", False): syms[symName].addParseAction(lambda s, pos, toks: nodes.autocollapse(nodeClass, toks)) else: syms[symName].addParseAction(lambda s, pos, toks: nodeClass.fromParseResult(toks)) except KeyError: # pragma: no cover raise utils.logOldExc( KeyError("%s asks for non-existing symbol %s"%( nodeClass.__name__ , symName))) def bindObject(ob): if isinstance(ob, type) and issubclass(ob, nodes.ADQLNode): for binding in getattr(ob, "bindings", [ob.type]): if binding: bind(binding, ob) if hasattr(ob, "parseActionFor"): for sym in ob.parseActionFor: bind(sym, ob) for name in dir(nodes): bindObject(getattr(nodes, name)) for ob in _additionalNodes: bindObject(ob) _grammarCache = syms, root return syms, root
if __name__=="__main__": # pragma: no cover print(getTreeBuildingGrammar()[1].parseString( "select UCDCOL('phys.mass') from misc" )[0].asTree())