Introduction
It's 2 am, you have been trying to run your 3-line command in order to solve the secrets of the universe for the past half an hour but you keep making syntax errors. Where does this curly bracket go? Should I have put a square bracket there? If only there was an easier way.
My project for the WSS19 was to create a basic Error Explorer function for the Wolfram Language, study syntactically wrong expressions and predict where missing square brackets should be added.
A new function was written that attempts to build a valid expression tree from an input string containing WL code. To do that, the expression's syntax is checked against the functions' definitions. In case, a function can accept a varying number of arguments, all paths are followed.
When given a syntactically incorrect expression as input, the function manages to output the correct answer for simple expressions. A number of suggestions are returned, one of which is the correct one.
The code for the function is publicly available in my git repository:
http://cern.ch/go/XF6Q
Recommended Function usage (Quick Start Guide)
Let's start with a simple function:
str = "Sin[Cos[a]"
It looks like someone forgot to add the second closing bracket in the expression. Let's see what we can do. We run the function errorExplorer. This will output an association with two entries: the changes made to the expression and the correspondent reconstructed tree.
simplecase = errorExplorer[str]
We can request the number of suggestion by running
suggestionsCount[simplecase]
In this trivial example, only one suggestion was generated. We can also have a peek at the associations that contain the tree structure:
suggestionsProperties[simplecase]
or plot the trees directly:
suggestionTrees[simplecase]
Finally, for the impatient people out there, there is a way to cross-check the suggestions against the initial string, and also attempt to interpret the expression:
suggestionsExplorer[str, simplecase]
More implementation examples
We can now attempt to find errors in more complicated expressions. Let's start with a conservative approach. Only the result of the suggestionsExplorer function will be shown here.
Missing bracket for single argument function
str = "ListPlot[Table[Prime[i,{i,50}]]";
Don't tell me that I'm missing a closing bracket here.
onearg = errorExplorer[str];
It looks like the function returned two suggestions. Adding a closing bracket at position 23 or 32. As can be seen, placing the bracket at position 23 corrects the expression. The function Prime only accepts one argument.
Missing bracket for function with two arguments
With enough confidence, we proceed to another example.
str = "Table[PDF[HoytDistribution[q,t,x],{q,{.05,.3,.9}}]";
HoytDistribution should be called with two arguments, but I accidentally called it with more. What better opportunity to test the errorExplorer function?
twoargs = errorExplorer[str];
suggestionsExplorer[str, twoargs]
As we check the different suggestions, we realise that the bracket should be placed at position 31.
Missing bracket for function with varied number of arguments
What about something harder? In the following expression, Directive[Orange,Specularity[White,40] is missing its closing bracket:
str = "Plot3D[Sin[x^2+y],{x,-2,2},{y,-2,2},PlotStyle\[Rule]Directive[\
Orange,Specularity[White,40],Mesh\[Rule]None,PlotPoints\[Rule]25]";
complicatedargs = errorExplorer[str];
Well, look at that! Most of the suggestions produce interpretable code. But which one is doing what I intended to? Specularity[White,40] shouldn't be split, while Mesh -> None is a different option. The correct expression is behind the curtain... excuse me... suggestion 3.
Other examples
The function is written in a way that allows it to ignore comments and strings. Also, a primitive implementation for correcting more than one missing brackets is present. Examples for those can be found in the repository referenced in the introduction.
Shortcomings
The function at its current stage is checking whether a closing bracket should be added to the code every time it encounters a comma. As a result, if a missing bracket is not followed by a comma or it's not at the end of the expression, it cannot be fixed. Furthermore, if an expression contains a list, for example {1,3,5}, the function will attempt to put a bracket before each comma.
Due to the fact that the expression is a string, mathematical operators do not get parsed. For example 1+3 will not get converted to Plus[1,3]. As a result, currently those operators are discarded, and the last part is used as the function argument.
example = errorExplorer["Sin[a+b]"];
suggestionTrees[example]
The function is not able to understand the two opening/closing brackets that indicate part. For example, it would not run correctly for an expression containing mylist[[5]] as it would faultily assume those brackets indicate the start of a new function.
Sum Up
The work contained in this notebook was produced within just a few days, and it is not under any circumstance considered a complete function ready to be used. Nevertheless, for simple enough expressions, the results are promising. It is my speculation that with just a few more days worth of work, a self sufficient function could be produced (and maybe become part of the Wolfram Function repository). That is, if some core functionality is added: understand the [[ ]] notation for part, keep track of lists and treat operators (like +, -, *, :> etc) especially.