Documentation

Basic Use

Start a new Flash project. Put the ’scripting’ folder from the ZIP file in the same directory as your FLA.

Write the following in your Actionscript window:

import scripting.*;

var codestring:String = "var x = 10; var y = x + 20;" ;

var s:Scanner = new Scanner(codestring);
var p:Parser = new Parser(s);

var vm:VirtualMachine = new VirtualMachine();

try
{
	vm.setByteCode(p.parse());
}
// If an error occurs here, it is likely a syntax error in the source code.
catch (vme:VMSyntaxError)
{
	trace(vme.message);
}

var result = vm.execute();

Run the program, and inside the virtual machine, the variable ‘y’ will be set to 30.

However, this is useless if we can’t see it. Before you run vm.execute(), let’s hook up the VirtualMachine to the outside world by letting it use the trace statement;

import scripting.*;

var codestring:String = "var x = 10; var y = x + 20; trace(y)" ;

var s:Scanner = new Scanner(codestring);
var p:Parser = new Parser(s);

var vm:VirtualMachine = new VirtualMachine();

vm.getGlobalObject().trace = trace;

try
{
	vm.setByteCode(p.parse());
}
catch (vme:VMSyntaxError)
{
	trace(vme.message);
}

var result = vm.execute();

By attaching objects or functions to the properties of the VirtualMachine’s global object, you let the scripting engine make use of those objects or functions. Now, when you run this, the output window of your Flash will report ‘30′.

Objects, including library objects, can be attached as well:

vm.getGlobalObject().player = myplayerobject;
// This will enable Math.floor, Math.sin, etc.. for your scripting engine
vm.getGlobalObject().Math = Math;

What is result used for? Result contains the exit code of the scripting program being run. If vm.execute returns false, then the program ran to the end. If it returns true, then the program is still in progress, and was suspended (see below).

Language

The scripting language is a mostly faithful copy of ECMAScript from the ActionScript 2 era. It supports

Note that not all features are included; it does not implement

Note that while the new operator is not included, new arrays and objects can be created by the code:

var newarray = [];
var newobject = {};

New Features

The scripting language also includes some special language features.

The loop statement is a simple infinite loop. Note that by itself, that’s not a useful feature; but it’s meant to be combined with the other new language features, such as suspend.

loop
{
    updateGameScripting();
    suspend;
}

Suspend (or yield, which is a synonym) will pause the virtual machine and cause vm.execute() to exit with a return code of true. If vm.execute() is then called again, the program will pick up where it left off and continue to run.

Here is an example how you can use suspending to make routines that get further input from the player.

// Code in your Flash project
function askquestion(question)
{
	// Assume that these are custom movie clips being manipulated
	questiondialog.questionfield.text = question;
	questiondialog.visible = true;
	questiondialog.okbutton.addEventListener('click',onAnswerQuestion);
}

function onAnswerQuestion(e:Event)
{
	questiondialog.visible = false;
	vm.getGlobalObject()._engineanswer = questiondialog.answerfield.text;
}

vm.getGlobalObject()._engineaskquestion = askquestion;

// Scripting code
coroutine getinput(question)
{
	_engineaskquestion(question);
	suspend;

	// Now that we are back, onAnswerQuestion in the main Flash
	// has already set _engineanswer for us.

	return _engineanswer;
}

// Note the use of underscores in the "engine" functions and variables.
// This is mainly to disguise the inner workings of your scripting from modders;
// More seriously-written code would preparse what a modder writes, for instance to keep
// them from overwriting or redeclaring important variables, or using suspend when
// the engine wouldn't know how to resume the code.

// Of course, if the scripting engine is entirely for the programmer's use, they
// can name things how they please.


var playername = getinput("What is your name?");

There are some important limitations to when and where you can suspend a scripting program.

If the rules here are a bit too complex (for either you, or more importantly, for modders), just use coroutines exclusively instead of functions when writing code where you might need to stop for input. Alternately, use this command:

var s:Scanner = new Scanner(codestring);
var p:Parser = new Parser(s);
p.setForceCoroutine(true);

setForceCoroutine, when used, will cause any reference to a function to be compiled to a coroutine instead, simplifying the issue.

Reusing Compiled Code

Once the virtual machine has executed once, you can use the compiled code as a library of functions to call on freely.

If you want to call on a compiled function, simply access the global object and use that function’s name.

vm.getGlobalObject().mycompiledfunction(myarg,myarg2);

If you want to call on a coroutine, use runCoroutine instead, and pass it a string of the coroutine’s name, and an optional Array of arguments.

vm.runCoroutine("mycoroutinename",[myarg1,myarg2]);

Note that you should be sure to run execute first to be certain that these functions and coroutines are moved from the source code to the VM’s global object.

If your functions and coroutines change the values of variables at the global level of the code, those changes will be preserved from call to call.

Optimizing

It is possible to optimize the code you compile, by passing an optional argument to Parser.parse()- the virtual machine that you are targetting.

vm.setByteCode(p.parse(vm));

If you do this, the array of bytecodes that parse() produces cannot be used in any other virtual machine. However, the code will run with an estimated 40% speed boost.