Links

Categories

Tags


« | Main | »

JewelScript 1.2.3.80 changes log

By Jewe | May 14, 2014

This post lists all changes made to the project since it’s previous public release, version 1.1.3.32. The newest change is on top of the list.

New featues and changes

Added global scope operator

The global scope operator allows to solve a name conflict between a global function and a global class member function.

class Foo
{
    function Func() {}
}

function Func() {}

using Foo;

function main()
{
    Func();         // ERROR: Ambiguous access

    global::Func(); // Explicitly call Func()
    Foo::Func();    // Explicitly call Foo::Func()
}

In the above example, a name conflict is produced, because Func() is accessible from the global space, as well as class Foo, due to the using-statement. You can prefix the function name with the global scope operator global:: to explicitly call the global function.

The operator can also be used to explicitly specify an absolute type name, or to specify the full-qualified name of a global constant.

Lambda expressions

A lambda expression is a function literal with a minimal syntax. The expression originates from functional programming languages, but has probably gained most popularity since it’s inclusion in C#. An example for a lambda expression would look like this:

f = (x, y) => Sqrt(x * x + y * y)

where f is a delegate of type float F(float, float)

In JewelScript, a lambda expression can have two forms. The first and most common form specifies an argument list and an expression:

f = (args) => expr

This is syntactical sugar for the expression:

f = function(args) { return expr; }

The second form consists of an argument list and a block:

f = (args) => { statements }

Which is syntactical sugar for:

f = function(args) { statements }

If the lambda expression is used in an instance member function, JewelScript will automatically make the lambda expression an instance member function as well.

Ternary operator

Probably the niftiest thing C had to offer was the ternary operator. I mean, a complete if-else statement implemented as an expression, that’s just awesome. No serious C developer can live without it. I really missed the operator in JewelScript. It’s weird it took me so long to add it. Well, finally it’s there.

function dude(int areYouCool)
{
    println( areYouCool ? "Yes" : "No" );
}

Support for nested name spaces, classes and interfaces

The constantly growing collection of native classes I have written for JewelScript made it obvious that I needed to introduce name spaces into the language.

This feature required a vast amount of code changes all across the library. Even so, users of the library will be happy to know that their code will still work like it did. Meaning, updating your project to the new version of JewelScript will not immediately force you to change any code — neither on the native side, nor on the scripting side.

I have foreseen the need for name spaces for a long time. Even with JewelScript 1.0, it was already possible to create types inside the name space of a class. However, the compiler was not equipped with the means to directly access these member types. All you could do was define an alias for the member type, which kind of served as a “crutch” to come by this restriction.

In addition, global class member functions and constants were always protected by their class name space, so you had to specify their full-qualified name. To make this easier, I introduced the ‘using’ statement. But again, that was just a “crutch”, which worked only with global functions, but not with global constants.

JewelScript 1.0 was also already prepared for nested classes. But without proper means of accessing member types, that would have made no sense, so the feature didn’t make it into the release.

Introducing a proper concept of nested name spaces solved all those issues. I’m quite pleased how all the existing functionality somehow “fell into place” when I implemented the name space support. The alias- and using- statements are now actually useful and work in all cases where you would expect them to work.

Some people may worry that introducing name spaces will make coding in JewelScript less simple and straightforward, because now programmers have to deal with long names, or the question of which class is in which name space. However, I think it’s actually quite easy to use.

For the most part, the compiler will find the type you’re using automatically, so you don’t have to specify long names. In case the type is not found, or is ambiguous, you can declare aliases, employ the using-statement, or specify a partial name space to help the compiler determine the type you want to use.

I’ve started to move all my native bindings into a clean structure based on C# .NET’s model. And even though scripts now frequently employ ‘using’ to access these classes, I think it’s still easy enough to use. It also makes the list of available classes much clearer.

Of course the C++ binding code generator, as well as the HTML documentation generator, have been upgraded to support name spaces as well.

Changes to binding code generator

Aside from the name space support, a small change has been made to the C++ binding code generator. Instances of your C++ class are no longer allocated with C malloc() and freed with C free(). Instead, the binding code defaults to a direct call to operator new and operator delete. But of course this can be customized according to your personal needs afterwards.

New compiler option “default-float”

By default, JewelScript will try to automatically determine whether a numeric literal should be interpreted as float or integer value. The compiler will treat non-fractional literals as integer, unless the left-hand variable’s type is float.

However, there are applications where that’s unwanted. In certain cases, it would be beneficial if also non-fractional literals were interpreted as float values.

Calculators are such applications. In a calculator program, we want to enter “1 / 3” and get “0.333” and not “0”.

Therefore this option has been added. When set to “yes”, the compiler will interpret all numeric literals, fractional or non-fractional, as floats, unless the left-hand variable’s type is integer.

New API function for XML export

In former versions, the library would automatically export all types to an XML file when the HTML documentation generator was invoked. This has been changed. The HTML documenation generator no longer exports the XML file.

Instead, a dedicated API function JCLExportTypeInfo() has been added for this purpose.

Compile-time performance optimizations

Pre-compiling code

Any code passed to the compiler is now pre-compiled into an array of tokens before the compiler starts compiling it. This improves compile speed in all cases where complex expressions have to be analyzed and test-compiled multiple times.

Link-time register save / restore code generation

Every function in JewelScript must save the registers it uses to the stack at the beginning, and restore their contents before returning. But to know how many registers to save at the beginning, the function had to be fully compiled first — a hen / egg problem.

Therefore I compiled every function twice. I test-compiled it, discarded it, and compiled it again, this time with the correct register saving code. While this worked, it wasn’t exactly a brilliant solution.

I have finally cleaned this up. The compiler will generate the function “naked” now, meaning without register save / restore code. In the linking process, when the correct number of used registers is known, the linker will insert the proper save / restore code into the function.

I’m making this sound trivial, but in fact it isn’t. The linker inserts code at the top of the function that alters the state of the stack. So it has to trace all code paths of the function to find and correct offsets of stack variables that are affected by the change. Also, inserting code at every exit of the function may affect branches, which have to be found and corrected.

It took me a while to figure out this algorithm. Anyway, this change should more or less double compilation speed.

Dynamic run-time conversion to ‘string’

JewelScript can now convert any value to a string during run-time, provided the value’s class implements a string conversion method.

Normally this isn’t necessary, because the compiler can convert values between types automatically at compile-time.

However, if the source value is type-less, because it’s loaded from a container, like a list or table, then the compiler can’t do automatic type conversion.

And this is where dynamic conversion comes in. If a type-less value is assigned to a string-variable, then JewelScript now performs a dynamic conversion to string at run-time.

Native classes can now call a new API function NTLConvertToString() to convert any value to a string.

The built-in classes now use dynamic conversion as well. For example, the array::format() and string::format() functions, which were limited to ints, floats and strings before, can now write the string representation of any object into the formatted output.

Compiler option “log-garbage” improved

This option is useful if you want to hunt for memory-leaks due to reference cycles. In the old version, this option was just a yes | no flag. Now it has three modes: none, brief, all.

Setting brief will only log values directly freed by the garbage collector.

Setting all will log values directly and indirectly freed by GC. This list will become huge very fast, so brief is more useful in most cases. However, all may give you a better idea which object exactly caused the leak.

Change to multi-dimensional array constructor

When creating an array with a discrete number of elements, operator new automatically fills the new array with values. For the value types int and float, this value is 0.

For reference types this value is a null-reference. The old version made an exception if the array’s type was ‘string’ and filled the array with empty strings. This exception has been removed.

Additions to built-in types

The documentation of all built-in types has been revised.

table

method table(const list);
method array toArray();
method list toList();
function table merge(const table t1, const table t2, merger fn);

list

method list(const array);
method array toArray();

Other bug fixes and changes

Topics: docs | Comments Off on JewelScript 1.2.3.80 changes log

Comments are closed.