Adding Roo to a Xojo app
The prerequisites to using Roo as a scripting language for you own Xojo app are the same as for building the Roo command line tool from source, namely:
- The source code. Available on the GitHub releases page
- A valid Xojo console license
- A valid Monkeybread Software MBS Xojo plugin license
Roo module from the repo and paste it into your Xojo project. Roo has been tested on macOS, 64-bit Windows, 64-bit Linux and the Raspberry Pi (running Raspbian). I haven’t tested it in a Xojo Web project but it should work just fine. Roo will not work in iOS projects as it relies on the
String class and the MonkeyBread plugin (neither of which are compatible with iOS at present).
Remember that somewhere in your project you will need to register the MBS plugin otherwise Roo won’t compile.
The Roo standard library provides
input() global functions. You will need to provide an implementation for each of these in your app.
print() function takes a
String. Depending on your app you may wish to print this value to the console, display it in a message window or assign it to a variable within your Xojo app.
Create a method in your app (let’s say
MyPrintMethod()) and use
AddHandler to link
MyPrintMethod() with a Roo.Interpreter instance’s
' Assuming myInterpreter is an instance of Roo.Interpreter AddHandler myInterpreter.Print, AddressOf MyPrintMethod
input() function takes a
String (which may be empty) and returns a
String parameter is the optional prompt to display to the user. The
String returned by the function will be handed back to the running Roo script as a native Roo
' Again assuming myInterpreter is an instance of Roo.Interpreter AddHandler myInterpreter.Input, AddressOf MyInputMethod
Running Roo code within your app
Executing Roo code is reasonably straightforwards. Below is a comprehensive example of setting up a parser, resolver and interpreter including delegating custom error handling methods.
' We will assume `source` is a String containing the source code to interpret. ' Setup a parser. dim myParser as new Roo.Parser ' Tell our Parser to call our app's custom `ScanningError()` method ' if a scanning error occurs (optional). AddHandler myParser.ScanningError, AddressOf ScanningError ' Tell our Parser to call our app's custom `ParsingError()` method ' if a parsing error occurs (optional). AddHandler myParser.ParsingError, AddressOf ParsingError ' Parse the source code. dim ast() as Roo.Stmt = myParser.Parse(source) if self.parser.hasError then return ' Bail. ' Create a new interpreter and delegate the `Print()` and `Input()` methods. dim myInterpreter as new Roo.Interpreter AddHandler myInterpreter.Print, AddressOf MyPrintMethod AddHandler myInterpreter.Input, AddressOf MyInputMethod ' Perform static analysis and symbol resolution on the AST. dim myResolver as new Roo.Resolver(myInterpreter) myResolver.Resolve(ast) if myResolver.hasError then return ' Don't run if the resolver failed. ' Run the code. myInterpreter.Interpret(ast) ' Catch any errors. Remember that scanning and parsing errors will ' already call this app's custom ScanningError() or ParsingError() methods ' assigned above if they occur. exception err as Roo.ResolverError ' Handle this... exception err as Roo.RuntimeError ' Handle this... exception err as Roo.QuitReturn ' The user wants to quit the script. Handle this...
Although the above looks a little verbose, a lot of it only requires doing once per interpreter. Assuming you’ve called the code above, subsequent calls to run Roo code can be cut down to the following:
' Parse the source code. ast() = myParser.Parse(source) if not myParser.hasError then myInterpreter.Reset() myResolver.Resolve(ast) if not myResolver.hasError then myInterpreter.Interpret(ast) end if end if