OK, I *finally* got the last of the (known) bugs fixed over the
weekend, so it's time to make a new Nasal release.  Enough has changed
(all the advertised features are now present and working) that I think
this will be a 1.0 release.

I'm not finished doing the documentation and website work for the new
stuff yet, so while I get that done I figured I'd let you guys be lab
rats and test the new version before it goes out the door.  If I
release a buggy 1.0, it's all your fault. :) I'm going to check this
stuff into CVS (remember to update your SimGear too!) as soon as I
send this message.  Scream really loudly if something breaks and you
want this patch reverted.

Here's a quick overview of the changes (or at least all of the ones I
can remember at the moment):

I. Some changes are basically invisible to script writers...

Nasal is a whole lot faster, generally about 3x or so.  It's now
faster than perl on the short list of microbenchmarks I was using to
tune it.  (No, the benchmarks cover all possible cases, and perl isn't
the last word in language performance.  But since perl is generally
accepted as "fast enough" for most people, it made a good target for
when to stop working on performance.)

The interpreter is now properly tail-recursive, meaning that if the
last expression in a function is a call to another function
(e.g. "return foo()"), no extra space is used on the stack.  Lisp and
recursion junkies will like this, no one else will care.

The interpreter is now fully threadsafe.  FlightGear won't likely use
that capability in the near term, but it's there if we want it.

The code size has grown significantly, but Nasal is still small.
About 145k of source code now, up from 110k at the last release.

There is now a rand() function in Nasal's standard library, but
FlightGear already had one that uses a better algorithm (Mersenne
Twister) than the Nasal one (which just uses the C library's rand()
function).  The Nasal one gets overridden.

II. There is some new syntax available.

A function expression can now have named argument lists.  Where you
used to have to write "func { a = arg[0]; b = arg[1]; ... }", you can
now do simply: "func(a, b) { ... }".

These arguments can have default values a-la C++: func(a, b=123) {...}

If any extra arguments are passed to the function, they will appear in
the "arg" vector just like they used to.  You can even rename this
vector to something more appropriate with a "...":  func(a, flags...) {...}

Local variables can be qualified with "var foo = whatever", so you
don't have to worry about colliding with variable names higher up in
the lexical environment.  This forces the "foo" symbol used to be
created as a local symbol if it does not exist.  Note that is *not* a
variable "declaration", just a qualifier on the assignment; you can
use it anywhere the lvalue could appear originally.  It is also
optional.

III. There is lots of new library functionality...

The Nasal script compiler is now available at runtime as a function
(compile()) which takes a string and returns a callable function
object.

There is a new function, call(), which allows you to make
runtime-computed calls to other functions.  Build up an argument list
and invoke it: result = call(somefunction, arglist);

You can use call() to do exception handling.  If the (optional) third
argument is a vector, any runtime errors that occur during the call
get appended to the vector for inspection by the calling code.  There
is a die() function that you can use to throw the exception.

You can inspect the call stack at runtime with caller().  This
function takes an integer and returns a vector of four elements: the
function object being executed, the local variable hash table, the
file containing the function definition, and the current line number.
You can do fun stuff with this, like set and read local variables from
functions up the call stack (consider dynamic scoping, or an import()
function).

Similar to caller() is closure(), which inspects the lexical
environment of a function object.  Calling closure(0) returns a
reference to the local variable hash of the current function;
closure(1) is the hash of the function in the ouside scope, etc...

There is a sprintf() function which does what you think it does.  This
was inspired by Melchior's work with the GUI library, and basically
wraps the ANSI function after pre-validating the input string.  It
turned out pretty freakin' elegant, IMNSHO.

There are two new functions for doing character conversions: strc()
takes a string as its first argument and an integer as its second and
returns the value of that byte in the string.  chr() takes an integer
and returns a single-byte string containing that character.

Finally, there is a find() function which returns the position index
of the first string in the second, and a split() function which splits
a string into an array using a substring delimeter.

_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@flightgear.org
http://mail.flightgear.org/mailman/listinfo/flightgear-devel
2f585eeea02e2c79d7b1d8c4963bae2d

Reply via email to