Hello Charles, Iâm glad to hear youâve found a way to get this working for you.
What follows is a more complete examination of some of the issues involved and an example script structure that may be helpful to others who would like to do something similar to implement a recovery and retry mechanism for their tests.
There are a couple of things to look at here: the do command, and the way youâre going about repeating the test.
About the Do Command
First, there is rarely a need to use the do command. The main reason one would use it is to execute some code that is constructed by the script at runtime. While do is potentially very powerful and can sometimes achieve things that couldnât be done any other way, its power also comes at a cost. It calls the SenseTalk compiler at runtime, making it slightly slower to execute, and also (as I think youâve found) incurring an extra level in the call stack as a result.
Usually, there are other ways to achieve the same result. Iâm not sure if what youâve shown is your actual code (Iâm guessing not) but using the do statements youâve shown as an example, you should be able to get the same results without âdoâ like this.
Instead of
do something
you could simply say
something
This will work if something is the actual name of the script you want to run. If (as Iâm guessing is the case here) something is a variable name containing the name of the script, then you could use the run command, like this:
run something
Your second use of do is more complex:
do ("run" && scriptName &"."& functionName && playerType & "," & loopLocation)
Here, you are actually constructing a command in text and executing it with do, which is exactly what do is good for. But itâs probably not necessary in this case either.
The run command, as shown in the previous example, will run a script whose name is stored in a variable (and does it without costing you anything extra in call depth). So the first part of the line above could become:
run scriptName
However, since youâre calling a specific handler in the script identified by scriptName, what youâll really need is:
get scriptName.(functionName)(playerType,loopLocation)
Iâve changed this to use the get command which treats functionName as a function call rather than a command message (the run command currently has some limitations that keep it from providing a similar solution). If the handler for that message is implemented as a âtoâ handler this will work fine, since a âtoâ handler will handle either command or function messages. If it was implemented as an âonâ handler youâll have to change it to either a âtoâ or âfunctionâ handler for this solution to work.
By putting functionName in parentheses here, it will be interpreted as an expression (a variable name in this case, although it could also be a more complex expression) that yields the name of the function to call. Without parentheses, it would try to call a function named âfunctionNameâ which isnât what you want. The playerType and loopLocation values are passed as parameters to the function named by functionName.
By switching your code to use run and get instead of do, you can save one level on the call stack in each case.
One Approach to Recovering and Retrying a Failed Test
The second issue to look at is the way you are going about repeating a test after a failure. You can save some frames on your call stack here as well, by letting your LogError handler return and using another repeat loop to try the test again. Hereâs what it might look like:
repeat with each item testname in testList
Log "Running Test " & testname
repeat 2 times -- maximum number of times to try
try
run testname
Log "Completed Test " & testname
exit repeat -- test ran successfully, don't repeat again
catch error
LogAnError testname, error
end try
end repeat
end repeat
to LogAnError testname, error
LogError "Test " & testname & " got an error: " & error
-- other important stuff to prepare for running test again
end LogAnError
Here, LogAnError reports the error and performs any necessary cleanup or recovery prior to attempting the test again, but doesnât re-run the test itself. This way it can return (without adding to the call depth) and allow the calling script to repeat the test. The main test loop makes 2 attempts to run the test (this number could be increased if you like) and stops trying after the test completes successfully.
By making these changes, it should be possible to run any number of tests, repeating each test as many times as needed, without running into the call depth (recursion) limit.