Scripting Events

Although QScript evaluates short expressions and algorithms with ease, sometimes you might have an algorithm that will take a very long time to run. In this case QScript can evaluate the script in a separate thread but then you have the problem of interacting with the script from your main application.

The default set of events are -

Event class Description
SyntaxErrorEvent This occurs when a syntax error is found during parsing.
EvaluationErrorEvent The script has been parsed but an error occured during evaluation.
TraceEvent These will only be fired if the trace mode has been enabled for the script. Read the Script API reference about the traceModeOn, traceModeOff and traceDelay methods.
HaltExecutionEvent Occurs if the script is halted before evaluation has finished. This may be that the script timed out or has been halted by the user.
ScriptFinishedEvent The script finished normally because evaluation was completed.
StoreUpdateEvent A variable has been updated.
OutputEvent Fired when the print or println methods are evaluated.
WaitEvent This event is fired when the WAIT function has requested a pause for a fixed time interval. The script will be restarted automatically after the pause.
ResumeEvent This is fired when the script is restarted after a timed pause caused by the WAIT function.
prime pattern

The following sketch demonstrates how to enable and process scripting events. The library import statements have been omitted for clarity.

It calculates all the prime numbers < 40,000 and displays them as bright blue spots on a dark background. It does this by listening for events fired by the script shown in lines 10 to 27.

The script object is created in line 29 and in line 33 the script is told that our sketch wants to listen for events. The eventhandler method is identified by preceding it with the @EventHandler annotation in line 41.

Notice that in line 31 we change the time limit for this sketch to 20 seconds, which means the script will be halted after 20 seconds even if all the primes have not ben calculated. This prevents scripts that might have got into an infinite loop or similar problem running forever.

In this example the event handler method has code to listen for all possible types of scripting events. This is done for demonstration purposes only, you only need to include if-statements for those events you want to catch.

For best performance only include traps for events you are interested in and place traps for the most likely events near the top and the least likely near the bottom. Parsing and evaluation events can definitely placed at the bottom since they will only occur once because they will terminate the script.

Script script;

public void setup() {
  size(400, 400);
  background(0, 0, 64);
  fill(0, 0, 255);
  noStroke();

  String[] lines = { 
    "# Prime number sieve", 
    "maxPrime = 40000", 
    "println('Prime numbers < ' + maxPrime)", 
    "lastPrime = 2", 
    "n = 3", 
    "REPEAT", 
    "  rootN = int(sqrt(n))", 
    "  notPrime = false;", 
    "  i = 3", 
    "  WHILE(i <= rootN && NOT(notPrime))", 
    "    notPrime = (n % i == 0)", 
    "    i = i + 1", 
    "  WEND", 
    "  IF(notPrime == false)", 
    "    lastPrime = n", 
    "  ENDIF", 
    "  n = n + 2", 
    "UNTIL(n >= maxPrime)"
  };

  script = new Script(lines);
  // Change the time limit from 5 (default value) to 20 seconds
  script.setTimeLimit(20);
  // Tell the script to send script events to this sketch
  script.addListener(this);
  // Evaluate the script
  Solver$.evaluate(script);
}

public void draw() {
}

@EventHandler
public void handleScriptEvents(ScriptEvent event) {
  if (event instanceof TraceEvent) {
    // This will not happen because tracing is not enabled
  } else if (event instanceof HaltExecutionEvent) {
    if (event.etype == ErrorType.MAX_TIME_EXCEEDED)
      println("Script timed out might want to give it more time");
  } else if (event instanceof ScriptFinishedEvent) {
    println("Time: " + script.getRunTime());
    println("=== DONE ===");
  } else if (event instanceof OutputEvent) {
    // no print or println functions so nothing to do
  } else if (event instanceof StoreUpdateEvent) {
    Variable var = (Variable) event.extra[0];
    if (var.getIdentifier().equals("lastPrime")) {
      int pn = var.toInteger();
      int x = (pn % 200) *2;
      int y = (pn / 200) * 2;
      rect(x, y, 2, 2);
    }
  } else if (event instanceof WaitEvent) {
    
  } else if (event instanceof ResumeEvent) {
    
  } else if (event instanceof SyntaxErrorEvent) {
    //Hopefully this won't be needed
  } else if (event instanceof EvaluationErrorEvent) {
    //Hopefully this won't be needed
  }
}

 

This sketch is included as an example with the library.