Thursday, March 22, 2012

Indented strings and struct annotations

I've just checked in support for two new features: indented strings and
struct annotations.

Indented strings allow you to write string constants across multiple lines
without breaking indentation:

    string_val := I'here is a document
                    embedded in a string definition
                        - this line will be indented in the output
                    but the rest will not.';

    cout.write(string_val);

This would produce the following output:

    here is a document
    embedded in a string definition
        - this line will be indented in the output
    but the rest will not.

In an indented string, the escaped newline also escapes all following
whitespace:

    # string_val = "this is a single line string!"
    string_val := I"this is a \
                    single line string!";

In an indented string (indicated with a capital "I" prefix) the tokenizer
strips all leading whitespace after a newline up to the minimum level of
indentation following a newline for the entire string. Whitespace after an
escaped newline, though ignored in the string itself, is considered in
determining the minimum indentation level. So if you wanted to define a string
containing a list of indented lines, you could do something like this:

    string_val := I'  a) item 1
                      b) item 2
                      c) item 3\
                    ';

The escaped newline and the whitespace before the final quote will be
ignored, but forces the minimum indentation to two characters before the start
of the previous lines.

This trick also works for i-strings:

    cout I`Hello!
           World!\n`;

Struct annotations essentially allow you to define a class consisting only of
instance variables with a constructor that allows you to initialize all of the
instance variables. So the Coord example from the manual (defining a two
dimensional coordinate) can now be written like this:

    @import crack.ann struct;

    @struct Coord {
        int x, y;
    }

    c := Coord(10, 20);  # create a Coord with x = 10, y = 20

The struct annotation is still very limited: you can't use inheritance or
define methods, and there are no auto-generated formatTo() or comparison
methods. These niceties will eventually be added. But it's still a worthwhile
convenience.

Thursday, March 15, 2012

Virtual Functions in Extensions!

This morning I checked in a big change to allow us to do a better job at wrapping C++ classes with virtual functions.  In summary, you can now create an extension class whose virtual methods call the underlying C++ function by default, but can be overriden in Crack as if they were normal Crack virtual methods.  This magic also works from C++: calling the virtual function on a Crack object from C++ transparently dispatches the call to the Crack override, cleanly solving the problem of C++ callbacks.  To top it all off, the interface is portable - it makes no assumptions about the C++ ABI.

You can read the original design doc at http://code.google.com/p/crack-language/wiki/ExtensionsVirtualFunctions.  At the time of this writing, this is not completely up-to-date, but test/testext.cc includes a complete example.

Happy wrapping!