OpenBaseMovil
Welcome at » bmScript

I was writing an email for Richard Hull, explaining some of the basics of bmScript and how to use it, but after writing it, I thought that it was worth posting it instead of just sending the email.

So there it goes.

Introduction

The ant build file for openbasemovil-script creates various jar files for the engine, one of them contains just the runtime to execute compiled scripts, another one contains also the script compiler, and the other two are JavaSE tools to compile and run script files in a standard JavaSE environment. These tools can also be a good example of how to perform the same from a mobile device using JavaME.
Though bmScript is a scripting language, it is really compiled to a binary form for a couple of reasons. First to be able to compile the scripts on application build or a remote server and reduce application size by using the runtime-only jar, but most important to improve execution speed by spending time on interpretation just once.

Class loading

The engine provides the ScriptingClassLoader class, which searches for .bmc (compiled scripts) resources in the classpath under the folder “vm”. It also provides access to system defined classes and system or custom NativeClasses.
You can subclass the ScriptingClassLoader in order to provide other ways of finding classes. The compiler and runtime for JavaSE do it to find classes in standard folders, but you can extend it to download them from a remote server, for example.

Integration with non-scripting classes (Java classes)

The NativeClass provides an easy way to create proxy Java classes that can be injected in a ScriptingClassLoader to be able to access any other Java class from a script.
It could have been done a lot easier with reflection, but that is not available with JavaME, so we have to do it in another way.
The NativeClass provides all the “infrastructure” to define methods and properties and to find and check that they are properly invoked, so you can create proxy classes for Java classes easier by subclassing NativeClass.
A good example are the classes found in the bm.vm.sys package under the main src folder of openbasemovil-script: The Map class lets you create Hashtable objects from the script, though you call them “map” in the script.
The Map class declares the methods present in the class in a static block, and then just provides the implementation of the invoke method that is a switch to handle the different methods declared.
Let’s suppose that I have a NativeClass called List that will let me access java.util.Vector, and I want my scripts to access it as “list” (check the Map class, that is performed in the constructor).
Now I obviously want to run a script that will access this class, to do that all I have to do is add it to the class loader of a virtual machine (we’ll get later to the full process of creating and invoking a vm):

 
    vm.getClassLoader().addNativeClass(
        "list",
        new sample.List( vm )
    );
 

Compiling a script

The bmsc class in the tools folder of openbasemovil-script is a JavaSE command line tool to compile .bms (script files) to .bmc (compiled scripts), very much in the way you do with javac.
The source code shows how to create a custom class loader, how to create a virtual machine and how to invoke the script compiler from Java code.
It is JavaSE 1.5+, but it can be used in a very similar way from JavaME.

Running a script

The bms class in the tools folder is a command line runtime, this time like the java command line tool from the jre. It shows how to create a custom class loader, how to create a virtual machine and how to invoke a script.

Using the example of the List NativeClass above, we could do something like this:
My scripting class (foo.bms):

 
class foo
{
    method int main()
    {
        var list myList;
        set myList = new list();
        mylist.add( "hello world with list!" );
        system.println( mylist.get( 0 ) );
    }
}
 

The java code to invoke the script (once compiled into foo.bmc):

 
    final VirtualMachine vm = new VirtualMachine();
    vm.getClassLoader().addNativeClass(
        "list",
        new sample.List( vm )
    );
    vm.run( "foo" );
 

The run method is a shortcut to the one used in bms that uses no arguments, it will load the scripting class foo, search for a main method and invoke it with no arguments.

If you want to retrieve a return value from a script, the run method or the invoke method in the virtual machine will always return an Instance object.
The Instance object represents (obviously) an instance of an ScriptingClass object.
For native types (boolean, int, etc) they always have a property called “value” that you can retrieve with the get method.

For other types, the real java object might be in an attachment. The Map class does this, it uses an attachment called “map” to hold the real Hashtable object used.

In further articles we will try to get deeper in the possibilities of the language. It obviously can be used from JavaSE, it allows you to compile or just run scripts that are loaded dynamically, and through the NativeClass system it allows you to extend the runtime to access any Java class you want.

Please, feel free to comment your thoughts, and remember that bmScript is still v0.1, it works, but it has still to be thoroughly tested and performance tunned.

BlogLines del.icio.us Digg Facebook Google Google Reader Yahoo! MyWeb Newsgator Newsvine reddit SlashDot StumbleUpon Technorati

We have just released openbasemovil-script-0.1, this is the first revision that we have uploaded. There is still work to do, but the system is running fine and you can create your scripts and extend the script language (please, send your contributions to the project).

We have called the language bmScript, it is an object oriented scripting language, with a syntax very similar to Java, C++ or C#, but a lot easier.

While it is easy, we have designed it to be easily extensible, both the core language it self and the virtual machine interface to “the outer world”. That means that new keywords can be added very easily, and (that will be far more common) you can extend the reach of the language to whatever you want just by providing the appropriate proxy classes.

Lets see the famous Hello World! example with bmScript:

class HelloWorld
{
    method void main()
    {
        system.println( "Hello World!" );
    }

}

Unlike Java, bmScript supports multiple inheritance and has no notion of interfaces. You can extend a class from one or more super-classes, and in case of method conflict the one that belongs to the first declared super-class is used.

Like Java, each class must go in it’s own file with the same name and it is case-sensitive.

class foo
{
    method String sayHello()
    {
        return "hello ";
    }
}
class bar
{
    method int calc( int i1, int i2 )
    {
        return ( i1 + i2 );
    }
}
class foobar : foo, bar
{
    method void main()
    {
        // Will show: hello 25
        system.println( (sayHello() + calc( 10, 15 )) );
    }
}

The next article will be a more in depth look to the language and how can you extend it, with samples from the upcoming releases of OpenBaseMovil-db and OpenBaseMovil-ui libraries that allow the script to access the database engine and the ui toolkit, respectively.

Please, leave your comments. We have big plans for this engine (and the rest of the OpenBaseMovil project), such as running in other platforms like Android, Windows Mobile, Black Berry and Symbian (it actually works through the jvm, but we mean directly for better control and speed).

BlogLines del.icio.us Digg Facebook Google Google Reader Yahoo! MyWeb Newsgator Newsvine reddit SlashDot StumbleUpon Technorati