Skip to content

Instantly share code, notes, and snippets.

@AstraLuma
Created April 18, 2024 01:52
Show Gist options
  • Save AstraLuma/51f4bcc8dbb6903d7f5ab4f2dc933e43 to your computer and use it in GitHub Desktop.
Save AstraLuma/51f4bcc8dbb6903d7f5ab4f2dc933e43 to your computer and use it in GitHub Desktop.
KDL for Misbehave
Import MoveForward="my_actions.MoveForward" Rotate="my_actions.Rotate"
Tree "foo" {
Sequence {
IncreaseValue "behavior_tree_runs"
MoveForward 10
Rotate 90
}
}
import kdl
from . import action, decorator, selector
def load(text:str):
namespace = {
'CheckValue': action.CheckValue,
'SetCurrentTime': action.SetCurrentTime,
'SetValue': action.SetValue,
'Wait': action.Wait,
'Idle': action.Idle,
'IncreaseValue': action.IncreaseValue,
'Inverter': decorator.Inverter,
'Debounce': decorator.Debounce,
'Concurrent': selector.Concurrent,
'Priority': selector.Priority,
'Sequence': selector.Sequence,
}
doc = kdl.parse(text)
retnames = {}
for node in (_handle_node(namespace, n) for n in doc.nodes):
match node:
case None:
pass
case [name, tree]:
retnames[name] = tree
case _:
raise Exception(f"Invalid top-level node {node!r}")
return retnames
def _handle_node(namespace, node):
def _recurse(children):
for child in children:
n = _handle_node(namespace.copy(), child)
if n is not None:
yield n
match node:
case kdl.Node(name='Import'):
assert not node.nodes
namespace |= {
key: resolve(value)
for key, value in node.props.items()
}
case kdl.Node(name='Tree'):
kids = list(_recurse(node.nodes))
assert len(kids) == 1
return node.args[0], kids[0]
case _:
ctor = namespace[node.name]
return ctor(*node.args, *_recurse(node.nodes), **node.props)
# Stolen from zope.dottedname
def resolve(name, module=None):
"""Resolve ``name`` to a Python object via imports / attribute lookups.
If ``module`` is None, ``name`` must be "absolute" (no leading dots).
If ``module`` is not None, and ``name`` is "relative" (has leading dots),
the object will be found by navigating relative to ``module``.
Returns the object, if found. If not, propagates the error.
"""
name = name.split('.')
if not name[0]:
if module is None:
raise ValueError("relative name without base module")
module = module.split('.')
name.pop(0)
while not name[0]:
module.pop()
name.pop(0)
name = module + name
used = name.pop(0)
found = __import__(used)
for n in name:
used += '.' + n
try:
found = getattr(found, n)
except AttributeError:
__import__(used)
found = getattr(found, n)
return found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment