Translating declarative DSLs to nested function calls

I have a python library that builds special iterators (behavior tree) from nested function calls . Although the API has pretty good and easy syntax (due to the fact that it is python), it really can use declarative DSL.

Here is a rough sketch of what I am guessing:

DSL (using YAML):

tree: - sequence: - do_action1 - do_action2 - select: - do_action3 - sequence: - do_action4 - do_action5 - do_action6 

will result in the following nested function calls:

 visit( sequence( do_action1(), do_action2(), select( do_action3(), sequence( do_action4(), do_action5(), ), do_action6(), ) ) ) 

I'm having trouble visualizing how to do this. Since DSL should represent a tree, a simple depth intersection seems appropriate. But in order to build nested function calls, I have to somehow turn this inside out. This is probably due to something clever with an intermediate stack or some, but I cannot fully understand it. What is the correct way to perform this conversion?

+4
source share
1 answer

I think you could let python keep track of function calls and parameters instead of doing it yourself with the stack.

Suppose you have a YAML parsing tree in which each node represents a function call, and each child of that node is a parameter (which is also a function call, so it could potentially have its own parameters).

Then define the evaluate function, which evaluates the node of this tree, as follows (pseudo-code):

 def evaluate(node): # evaluate parameters of the call params = [] for child in node: params.append(evaluate(child)) # now make the call to whatever function this node represents, # passing the parameters return node.function.call(*params) 

Finally, call evaluate , passing the root of the YAML tree as a parameter, and you should get the desired behavior.


A slightly different structure using eval-apply

 def evaluate(node): # evaluate parameters of the call params = [ evaluate(child) for child in node ] # apply whatever function this node represents return node.function.call(*params) 
+3
source

All Articles