Created
April 18, 2024 01:52
-
-
Save AstraLuma/51f4bcc8dbb6903d7f5ab4f2dc933e43 to your computer and use it in GitHub Desktop.
KDL for Misbehave
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Import MoveForward="my_actions.MoveForward" Rotate="my_actions.Rotate" | |
Tree "foo" { | |
Sequence { | |
IncreaseValue "behavior_tree_runs" | |
MoveForward 10 | |
Rotate 90 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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