prof:variables(): Show all variables?
Query:
prof:variables(),
let $i := random:integer() return $i * $i
Expected:
No variable bindings, some random squared number.
Got:
Exception in thread "main" java.lang.NullPointerException
at org.basex.query.var.QueryStack.dump(QueryStack.java:135)
at org.basex.query.func.prof.ProfVariables.item(ProfVariables.java:20)
at org.basex.query.expr.ParseExpr.iter(ParseExpr.java:43)
at org.basex.query.QueryContext.iter(QueryContext.java:404)
at org.basex.query.expr.List$1.next(List.java:120)
at org.basex.query.MainModule$1.next(MainModule.java:118)
I would propose that prof:variables() is expanded after parsing, e.g. introducing a map from the names of in-scope variables to a VarRef.
The following query currently only outputs bindings of $a, even though it is not even actually in scope:
declare function local:foo($x) {
let $y := $x * $x
return
if($x gt 1) then (
for $i in 1 to $y
return $x
) else prof:variables()
};
for $a in 1 to 5
return local:foo($a)
This could be fixed by generating the following code after all variables are resolved but before optimizing:
declare function local:foo($x) {
let $y := $x * $x
return
if($x gt 1) then (
for $i in 1 to $y
return $x
) else prof:dump(
map {
'$x': $x,
'$y': $y
},
'Local Variables: '
)
};
for $a in 1 to 5
return local:foo($a)
Even though the function disappears and $y is inlined into the map, the output contains exactly the variables that the programmer would expect.
I didn't think of that.. Sounds like a good idea!
One interesting case are closures, should all potentially reachable variables be referenced or only the actually captured ones? The first option seems preferable, but the closure would potentially become much bigger without the programmer knowing why...
Good point. Option 2 sounds more attractive to me; I think the output of this function should be as intuitive as possible.
How about this?
for $i in 1 to 5,
$j in 1 to 5
let $f :=
function($k) {
prof:variables(),
$i * $k
}
return $f($j)
I would expect either $i and $j in the output or none of them. We could obviously have prof:variables([xs:boolean]) with an optional flag for all in-scope variables.
A flag may indeed be the best choice. As prof:variables is not supposed to be used in productive code, we can change or extend the function signature without too much hassle.
Do you know what's the most convenient way to access all potentially reachable variables? This is the current code... https://github.com/BaseXdb/basex/blob/master/basex-core/src/main/java/org/basex/query/var/QueryStack.java#L132-L141