Vassal 4:Design Blog 3
29-Aug-17 Scripting Language Requirements in Vassal 4
There are actually two decisions to be made, the choice of language, and the choice of the implementation of the Scripting Language (SL). Most potential SL’s have at least 2 different implementations to choose from, each offering different advantages and Disadvantages.
The Scripting Language Implementation (SLI) we choose needs to meet the following requirements, not necessarily in order of importance.
The SLI needs to be available on all platforms we choose to support and must run predictably on all platforms.
Portability can usually be achieved in 2 ways:-
- The SLI is available as a pre-built library for all Vassal supported platforms.
- The SLI is available as source code that Vassal can incorporate and compile on supported platforms
It may be possible to use different implementations of the same language on different platforms, but raises issues of predictability – will different implementations behave exactly the same in all circumstances on different platforms?
Disable access to Global Variables within the language
If Global Variables can be created in the language and used to communicate between different scripts, then this must be disabled, and preferably generate a script error if there is an attempt to use Global Variables in a script.
The reason for this is that data in Global Variables within the scripting language represent Game State that Vassal does not know about and cannot save in the Game History or save games.
When a saved game is loaded, the Global Variable state in the Scripting environment cannot be reliably re-created and so Game behaviour cannot be guaranteed to be the same after a save and load of a save game as it would have been if the game had not been saved.
Ideally, any attempt to write to or read from a Global Variable should generate a script error.
If the Vassal design requires scripts to have access to generic Global Variables, then we can implement a mechanism for scripts to read and write to a Global Variables that are managed by Vassal.
The SLI must support scripts calling other scripts which will require the SLI code to be re-entered to execute a new script before a previous script has completed.
This must be transparent to the user and there must be no unexpected interactions between the two scripts.
Vassal needs to monitor and control the depth of re-entrancy to report infinite loops.
Sandboxing means controlling the behaviour of scripts running in the Scripting Environment to prevent rogue or intentionally malicious scripts from:
- Accessing Vassal Game Objects or properties to which they are not entitled.
- Accessing resources outside of the scripting environment (e.g. read or write access to the hosting computer).
- Degrading the user experience by using large amounts of CPU or Memory (e.g. infinite loops).
The process of Sandboxing a SLI environment usually attempts to limit the access of scripts to 'dangerous' language and library elements and to try and monitor the CPU and memory used by scripts. However, some languages are intrinsically introspective and extremely difficult, if not impossible, to effectively sandbox.
How will bugs in the SLI be handled?
Is the SLI actively supported with timely bug fixes? Or will we dependent on waiting for years for bug fixes from a non-responsive organisation?
Is the SLI Open Source and understandable so that we can branch our own version and fix our own bugs?
Lightweight, Efficient, Fast
The purpose of the SL is to support Vassal, not the other way around, so the SLI needs to be light on resources, and run fast.
We need a scripting language, not a complete development environment. A high proportion of scripts will be just expression evaluation or a few simple lines. We don't need extensive libraries, mostly we will be calling back into Vassal to get and manipulate game objects.
Many SLI’s have a large amount of ‘baggage’ that comes along for the ride when you use them, bloating the Vassal install package and using run-time resource for functionality Vassal will never use.
The early design is for a large amount of the functionality of Vassal 4 to be provided by scripts, even routine operations, so any start-up overhead to initiate a new script running needs to be minimal.
Fast is better for a SL. Many SLI's now provide Just in Time (JiT) compilers that compile the SL down to machine language and are extremely fast. However, there are portability and maintainability issues involved in choosing a JiT. For our purposes, a fast, efficient bytecode Virtual Machine (VM) interpreter would be a better choice.
Embeddable in and Extensible by C++
The SLI must be able to be fully integrated with C++.
The SLI will be embedded within the Vassal C++ framework (i.e. Vassal can run scripts), but the SLI must also be able to call back to the Vassal C++ framework to access and manipulate Vassal Game Objects.
Scripts should be able to access and manipulate Vassal Game Objects using the native syntax of the language without the need for ungainly ‘hacks’ or ‘add-ons’.
Consistent error handling
Errors that occur while running a user script are of two basic types:
- Script Errors that are a result of some error in the script and can be fixed by the script author.
- Interface errors or Vassal errors that are a result of bugs in the SLI to Vassal interface or within Vassal itself.
There must be a way of consistently handling and reporting errors, preferably identifying the script and line number where the error occurred.
The error mechanism must handle the fact that errors that may be generated deep within a nested sequence of script calls.
Ability to syntax check/compile scripts without running them
We need to be able to check the syntax of a script and report errors to the module developer without running the script.