Links

Categories

Tags

About

About JewelScript quick ‘n’ dirty.

What is JewelScript?

JewelScript is a scripting language for use in tools and applications. It uses a syntax similar to C, making it easy to use for a wide range of developers.

It’s most unique characteristics are probably it’s plug-in architecture for native bindings, allowing modular sharing of binding code between projects. And it’s in-language support for documentation, allowing to easily create HTML documentation from all classes and functions bound to the language.

Why should I use it?

Scripting languages generally provide more features than traditional high-level languages. Some things can be done easily in a script language that are much harder to achieve in C / C++. And some things aren’t possible at all — at least not without obscuring the code to a serious degree.

JewelScript is designed to be embedded into any application and allows using that application’s infrastructure and functionality in a scripting environment. This can make the application more powerful and easier to use. It also allows 3rd parties to extend and automate your application without needing the actual source code.

Can I use JewelScript in my hobby or commercial project?

Yes. JewelScript is released under the zlib/libpng license. You can do with it almost anything you wish.

What does script code look like?

There’s a ton of code examples on this site, but here’s a quick ‘n’ dirty snippet:

namespace Library::Console {

class OkCancelDialog extends Dialog
{
    method OkCancelDialog(const Location p, const SmallSize s)
        extends Dialog(p, s)
    {
        BtnOK = null;
        BtnCancel = null;
        Initialize();
    }

    private method Initialize()
    {
        Message.Size.Height -= 3;
        int by = Location.Y + Size.Height - 3;
        int bx = Location.X;
        CharColor lgr = new CharColor(LightGray, Red);
        CharColor blg = new CharColor(Black, LightGray);
        // OK button
        BtnOK = new TextField(new Location(bx + 2, by), "   OK   ", lgr);
        BtnOK.OnMouse = method { SetDialogResult(Dialog::Result::OK); };
        // Cancel button
        BtnCancel = new TextField(new Location(bx + Size.Width - 10, by), " Cancel ", blg);
        BtnCancel.OnMouse = method { SetDialogResult(Dialog::Result::Cancel); };
        AddControls({ BtnOK, BtnCancel });
    }

    TextField BtnOK;
    TextField BtnCancel;
}

} // end namespace

How do I bind a new function in C?

It is far more likely you want to bind an entire class or set of global functions to the script environment. JewelScript’s plug-in architecture makes adding native classes to the runtime a simple one-liner:

#include "jilapi.h"

JILEXTERN JILError bind_File_proc (NTLInstance*, JILLong, JILLong, JILUnknown*, JILUnknown**);

extern JILState* machine; // virtual machine instance

static void BindMyTypes()
{
    JILError err = JILRegisterNativeType( machine, bind_File_proc ); // class File
    if( err )
        printf("ERROR %d", err);
}

JewelScript doesn’t allow single functions to be bound to the runtime. Instead, you register whole native classes to it. This is far more efficient in the long run, because once created, it allows your binding code to be shared and reused across multiple projects. It also allows you to fully remove a type by commenting out a single line of code.

Upon registering, a native type receives an event, and may respond to it by registering any additional helper classes to the runtime as well.

The binding code required to interface with your C / C++ class or library of static functions can be generated in seconds by using JewelScript’s integrated binding code generator.

How easy is it to call a script function from C?

This C function tries to call script function ‘int Add(int, int)’. For simplicity, I’ve omitted checking for exceptions as a result of the call.

#include "jilapi.h"

extern JILState* machine;   // Virtual Machine instance

int AddTwoIntegers(int valueA, int valueB)
{
    int resultInt = 0;
    JILHandle* pResult = NULL;
    // get function 'Add'
    JILHandle* pFunc = JILGetFunction(machine, NULL, NULL, "Add");
    if (pFunc != NULL)
    {
        // call it
        pResult = JILCallFunction(machine, pFunc, 2, kArgInt, valueA, kArgInt, valueB);
        // get result as int
        resultInt = NTLHandleToInt(machine, pResult);
    }
    NTLFreeHandle(machine, pResult);
    NTLFreeHandle(machine, pFunc);
    return resultInt;
}

Note that this example is inefficient and misleading. I’m just demonstrating the working principle here.

In the real world, your application would obtain the handle for function “Add” only once, after you have compiled and linked script code. Then you could use that handle to call function “Add” as often as you want. When your application terminates, it would release the function handle.

What platforms are supported by JewelScript?

JewelScript is entirely written in ANSI C (C99 standard), so it should compile and run virtually on any platform where a C compiler is available. The target processor must support 32-bit or higher.

The choice of ANSI C also means JewelScript is not limited to C / C++ applications. Since most other languages can interface with C, JewelScript may also be used in applications written in other languages.

JewelScript has been successfully compiled and used in Windows, MacOS X and Linux applications.

Can I use multiple instances?

Yes. Although it is written in C, JewelScript is entirely written in an object-oriented manner. You can use as many instances of the runtime in your application in parallel as you wish.

However, instances of the runtime cannot share any runtime data. Meaning, at present there is no mechanism to efficiently share values between multiple instances. If you need such a mechanism, you would have to code it yourself. The simplest and safest way would be copying values over from one instance to the other.

Can it run in multiple threads?

Yes, every instance of the runtime may be run from it’s own thread. But again, if they should exchange data, you’d have to take care of synchronizing threads and copying values over from one instance to the other yourself. This is currently not part of the runtime, as there is no real ANSI C way of doing it.

An instance must never be run from more than one thread at the same time. If you need multiple threads to share the same instance for some reason, you must take care of mutexing the threads.

How fast is JewelScript?

Fast enough to render image filters and implement internet radio applications or full 2D games. I encourage you to analyze these applications to assess JewelScript’s potential.

The question “How fast is it?” is usually the first question any developer asks about a scripting language. Ironically, it is also the question that can’t be easily answered. Because the performance impact of scripting to any application depends on the application’s design. It depends on what the application actually wants to use scritping for, and what tools are offered by the application to achieve that goal.

As an example, the Invaders game rarely drops under 60 FPS or goes over 25% CPU on my machine. This is because I have chosen to leave all drawing to the native application. The script just creates native “Layer” objects and moves them around the screen, all drawing and collision checking is done on the native side. Had I chosen to draw every pixel of every “sprite” in script, the game would make less than one frame per second and take 100% CPU.

So the answer to the speed question should actually be “It’s as fast as you make it.” When adding any script runtime to your application, it’s your task to offer efficient native infrastructure and tools, so that script programmers can achieve goals with optimum performance.

That said, JewelScript has been designed with best performance in mind. It uses static typing and has less dynamic features than other scripting languages. Meaning the compiler is able to generate more efficient code. No ‘tables’ have to be traversed in order to find a variable or function at run-time. No parameter types need to be checked in native functions, since the compiler ensures type-safety.

In comparison, JewelScript’s performance is faster than SpiderMonkey and on par with most other scripting languages. It is excelled by Lua 5 of course, since Lua features JIT-compilation.

This also depends on what you’re actually doing in script. For example, Lua doesn’t support true classes, it ’emulates’ them by using hash-tables. So if your script heavily deals with access to nested objects, like this:

window.Views.Background.Tag.Application::SetParameter("openwindow", "0");

Then JewelScript may not only be faster, it will also most certainly use a much lighter memory footprint.

Just to throw in some meaningless figures: On my old Intel Q9550 at 2.83 GHz, a single thread running a benchmarking script that allocates and destroys 10,000,000 (ten million) script objects, takes 2.96 seconds to complete, averaging about 60 MVMIPS (million VM instructions per second).

I said these figures are meaningless, because on your machine they will be completely different, depending on your processor clock speed and cache size, your RAM speed, your operating system and which other applications are currently running in the background.

Where can I learn more?

There’s tons of info in this site. Here are some starting points: