Style tweaked a bit

I've been fixing some small issues with the current style, leading to a more or less complete rewrite of the CSS stylesheet. It should work fine now with Firefox 1.5.0.4 (and most likely older versions, too) and IE7 Beta 3 (basic layout should work in IE6 too). Thanks to Philipp for pointing me at some problem cases. The logo has been updated a bit, too, and should look a bit more fancy. As usual, report any problems in the comments.

New style

Finally switched to a new style, looking better than the old one ;) and giving even more space to the entries. Thanks go to the Hemingway/Japanese Cherry Blossom style designers. Thanks also to Philipp (who has also a web page ;) ) for testing. Please report any problem you encounter in the comments.

Gameplay scripting

For my engine, I want to use a scripting language. The primary purpose for employing a scripting language is to simplify the development of gameplay code and leverage the power of multi-core systems. I've been lately a bit more serious about it (and yes, the packages are still in development, good stuff takes time) and did some more research. Read on for design goals, parser generators and general rambling on programming languages. By the way, this is the 100th entry in my blog :) Hooray!

Design goals

The scripting language should first and foremost allow designers and artists to write gameplay code, not more, not less. It does not have to be a fully features scripting language like Python. The focus is on event-driven, mostly parallel gameplay code. This brings several requirements with it:

  • Event-driven code has to be supported natively. Basically, there has to be some keyword for events as everything in niven is going to be event-driven.
  • Parallel execution. The resulting code should run well on a parallel ScriptVM.

Of course, if most of your code is event-driven, parallel execution comes for free as long as your objects are independent of each other. The most simple solution is to stack up all events for an object and then process the objects in parallel. This is completely transparent to the user and does not even require special language support. This means also that event raising will be asynchronous, but that seems rather logical to me. More design goals will probably emerge as soon as I get a prototype working, but these are the primary ones for now.

Syntax

A word on syntax, what kind of syntax do you prefer given the following choices?

  • function int a (int b)

  • function a (b: int) : int

    or a slight variation, with a more mathematic syntax:

    function (a:int, b:int) -> int
    { ... }
    
  • function name:a params:{a:int, b:int} return:int

    More verbose, but very friendly to annotations. Imagine if you could add other "attributes" to a function like function name:qsort implements:sort-algorithm complexity:nlogn ... and get it via sort-algorithm.get("complexity","nlogn")?

A note on the last one: I have some idea of something I call a "Rich metadata engine" which would allow adding attributes to each parameter, variable or function. For example, const and reference would become attributes and passed over to the compiler. This would allow compilers to support new attributes (say, checks like [>10]) which could lead to better optimization and better compile-time checks. Image the example function a (q:array [const,ref], i:int [const,=size(q)]).

Parser generators

To make all this stuff happen, I have to write a powerful script VM and a good compiler, and both tasks are not simple.

Pyl

For the compiler, I was playing around with the idea to write it in Python, but unfortunately parser generators for Python are not very powerful (the best I've found was Pyl, a yacc port to Python) and transforming ASTs in Python is painful because Python does not know call-by-reference. Anyway, for quick prototyping it's really good, I managed to get a compiler with constant-folding up & running in 2 hours for a simple test "language" (which understood assignment to variables and basic maths).

Boost.Spirit

Next try was Boost.Spirit, truly impressive, took me also around 2 hours to get a sample running (this time not written from scratch though) and write a simple compiler. Spirit is probably better suited for simpler parsing tasks, although I've seen some impressive parsers written with it. I wouldn't do it because although there is something beautiful about embedding EBNF in C++ I still see the advantage of writing real EBNF and transforming to ugly C++ ;) which leads me to the last tool I've tried, ANTLR.

ANTLR

It comes with a truly amazing IDE (yeah, you read right. It really has an IDE for writing parsers), it supports LL(*) grammars (no left-recursion though, but the IDE has a built-in function to refactor left-recursive rules) and it generates ASTs if you want it to. Unfortunately, the current version is under heavy development and not finished yet, meaning I didn't have the chance to play with the C++ AST yet. Anyway, I've been able to implement a rather large grammar already in no time, and I'll stick with ANTLR until something better pops up which is kinda unlikely.

Unit testing

I've lately switched my unit testing suite from Boost.Test over to UnitTest++ (written by the friendly guys at Games from within). Compared to Boost.Test, it's much easier to use and works fine out of the box.

UnitTest++

Unlike Boost.Test, UnitTest++ does not require manual setup of test suites. It's enough to put each test into a TEST block and it will be added automagically to the global suite. On the mailing list there has been recently some discussion about added real test suites to UnitTest++, but the current system is already very useful. Actually, I don't get the point about test suites, but somehow many developers are stuck into trees and such and are willing to sacrifice development speed just for pretty output. A note output UnitTest++'s output, it's very similar to the compiler output and allows you to jump directly to a failed test (it jumps even directly to the failed check and not the full test!). There's also XML based output and more, but the basic output is fully sufficent for me. Moreover, with the basic output, the test suite runs really fast (currently 0.00 secs for my small 11 test ;) ). I'm about to integrate the test suite directly into the build process so that a failed test will show up directly. Needs a bit polish on the build side at the moment (the test suite is currently totally separated from the rest of niven), but I'm pretty confident I'll be done with it this weekend.

Lambda functions in C++

While rewriting the niven configuration manager, I had to write lots of functions that walk over a tree and perform rather simple stuff. Unfortunately, the std::for_each function is ill-suited for such tasks as you have to write a functor class for each thing you want to do, and this really adds a lot of clutter to the code. Searching the web a bit, I've found this excellent proposal: C++ Lambda Expressions. I hope it'll make it into the next C++ standard, would really save me a lot of time.