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