1
0
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-12-03 08:30:03 +00:00

Adding tests of default args using lob evaulation.

This commit is contained in:
Dan Davison 2009-07-21 15:48:45 -04:00
parent ad7b17c393
commit 5d1ee80683

View File

@ -2281,6 +2281,244 @@ plot data using 1:2 with lines
* Bugs [24/36]
** TODO Fix nested evaluation
The current parser / evaluator fails with greater levels of nested
function block calls (example below).
*** Initial statement [ded]
If we want to overcome this I think we'd have to redesign some of
the evaluation mechanism. Seeing as we are also facing issues like
dealing with default argument values, and seeing as we now know
how we want the library of babel to behave in addition to the
source blocks, now might be a good time to think about this. It
would be nice to do the full thing at some point, but otoh we may
not consider it a massive priority.
AIui, there are two stages: (i) construct a parse tree, and (ii)
evaluate it and return the value at the root. In the parse tree
each node represents an unevaluated value (either a literal value
or a reference). Node v may have descendent nodes, which represent
values upon which node v's evaluation depends. Once that tree is
constructed, then we evaluate the nodes from the tips towards the
root (a post-order traversal).
[This would also provide a solution for concatenating the STDOUTs
of called blocks, which is a [[*allow%20output%20mode%20to%20return%20stdout%20as%20value][task below]]; we concatenate them in
whatever order the traversal is done in.]
In addition to the variable references (i.e. daughter nodes), each
node would contain the information needed to evaluate that node
(e.g. lang body). Then we would pass a function postorder over the
tree which would call o-b-execute-src-block at each node, finally
returning the value at the root.
Fwiw I made a very tentative small start at stubbing this out in
org-babel-call.el in the 'evaluation' branch. And I've made a start
at sketching a parsing algorithm below.
**** Parse tree algorithm
Seeing as we're just trying to parse a string like
f(a=1,b=g(c=2,d=3)) it shouldn't be too hard. But of course there
are 'proper' parsers written in elisp out there,
e.g. [[http://cedet.sourceforge.net/semantic.shtml][Semantic]]. Perhaps we can find what we need -- our syntax is
pretty much the same as python and R isn't it?
Or, a complete hack, but maybe it would be we easy to transform it
to XML and then parse that with some existing tool?
But if we're doing it ourselves, something very vaguely like this?
(I'm sure there're lots of problems with this)
#+srcname: org-babel-call-parse(call)
#+begin_src python
## we are currently reading a reference name: the name of the root function
whereami = "refname"
node = root = Node()
for c in call_string:
if c == '(':
varnum = 0
whereami = "varname" # now we're reading a variable name
if c == '=':
new = Node()
node.daughters = [node.daughters, new]
new.parent = node
node = new
whereami = "refname"
if c == ',':
whereami = "varname"
varnum += 1
elif c == ')':
node = node.parent
elif c == ' ':
pass
else:
if whereami = "varname":
node.varnames[varnum] += c
elif whereami = "refname":
node.name += c
#+end_src
***
*** discussion
I believe that this issue should be addressed as a bug rather than as
a point for new development. The code in [[file:lisp/org-babel-ref.el][org-babel-ref.el]] already
resolves variable references in a recursive manner which *should* work
in the same manner regardless of the depth of the number of nested
function calls. This recursive evaluation has the effect of
implicitly constructing the parse tree that your are thinking of
constructing explicitly.
Through using some of the commented out debugging statements in
[[file:lisp/org-babel-ref.el][org-babel-ref.el]] I have looked at what may be going wrong in the
current evaluation setup, and it seems that nested variables are being
set using the =:var= header argument, and these variables are being
overridden by the *default* variables which are being entered through
the new functional syntax (see the demonstration header below).
I believe that once this bug is fixed we should be back to fully
resolution of nested arguments. We should capture this functionality
in a test to ensure that we continue to test it as we move forward. I
can take a look at implementing this once I get a chance.
**** demonstration
After uncommenting the debugging statements located [[file:lisp/org-babel-ref.el::message%20format%20first%20second%20S%20S%20new%20refere%20new%20referent%20debugging][here]] and more
importantly [[file:lisp/org-babel-ref.el::message%20nested%20args%20S%20args%20debugging][here]], we can see that the current reference code does
evaluate the references correctly, and it uses the =:var= header
argument to set =a=8=, however the default variables specified using
the functional syntax in =adder(a=3, b=2)= is overriding this
specification.
#+srcname: adder-test(a=3, b=2)
#+begin_src python
a + b
#+end_src
#+resname: adder-test
: 5
#+srcname: after-adder(arg=adder-test(a=8))
#+begin_src python
arg
#+end_src
#+resname: after-adder
: []
*** Set of test cases
**** Both defaults provided in definition
#+srcname: adder1(a=10,b=20)
#+begin_src python
a+b
#+end_src
#+resname: adder1
: 30
****** DONE Rely on defaults
#+lob: adder1( )
#+resname: adder1( )
: 30
## should be 30
## OK, but
******* TODO empty parens () not recognised as lob call
E.g. remove spaces between parens above
****** TODO One supplied, one default
#+lob: adder1(a=0)
#+resname: adder1(a=0)
: 30
## should be 10
#+lob: adder1(b=0)
#+resname: adder1(b=0)
: 30
## should be 10
****** TODO Both supplied
#+lob: adder1(a=1,b=2)
#+resname: adder1(a=1,b=2)
: 30
## should be 3
**** One arg lacks default in definition
#+srcname: adder2(a=10,b)
#+begin_src python
a+b
#+end_src
****** TODO Rely on defaults (one of which is missing)
#+lob: adder2( )
[no output]
## should be error: b has no default
****** TODO Default over-ridden
#+lob: adder2(a=1)
[no output ]
## should be error: b has no default
****** DONE Missing default supplied
#+lob: adder2(b=1)
#+resname: adder2(b=1)
: 11
## should be 11
## OK
****** DONE One over-ridden, one supplied
#+lob: adder2(a=1,b=2)
#+resname: adder2(a=1,b=2)
: 3
## should be 3
*** Example that fails
#+srcname: adder(a=0, b=99)
#+begin_src python
a+b
#+end_src
#+resname: adder
: 99
#+srcname: one()
#+begin_src python :results silent
2
#+end_src
#+srcname: level-one-nesting
#+begin_src python :var arg=adder(a=one(),b=one())
arg
#+end_src
#+resname:
: 99
#+srcname: level-one-nesting
#+begin_src python :var arg=adder(a=adder(a=one(),b=one()),b=adder(a=one(),b=one()))
arg
#+end_src
#+resname:
: 99
** TODO allow srcname to omit function call parentheses
Someone needs to revisit those regexps. Is there an argument for
moving some of the regexps used to match function calls into