Thursday, December 1, 2011

Crack 0.6 released

I'm pleased to announce the release of Crack version 0.6.  This will almost certainly be the last major release prior to 1.0 (we will release a 0.6.1 version shortly that builds against LLVM 3.0 and may contain bug fixes)

From the release notes:

  • Implemented const folding for integer and float operations.
  • Added support for injecting crack function body code from an extension.
  • Added the foundations of support for module caching.
  • Added functors.
  • Added an 'ascii' module supporting functionality specific to ASCII data.
  • Added a module for dealing with numeric arrays.
  • Migrated modules out of crack.exp, removed obsolete modules.
  • Implemented "const" variables.
  • Implemented access protection.
  •  Implemented abstract methods.
  • Converted all unit tests to "screen"
  • Lots of bug fixes and small enhancements.
So download, compile and enjoy!

Wednesday, August 24, 2011

screen: a new test suite for crack

In the current trunk, and due for inclusion in the next release, is our new test suite "screen".

It replaces the original system built on a simple bash script. The new test suite offers several advantages:

  1. It is template based, and individual tests all have their own templates
  2. It can skip tests based on functionality available on the host system (e.g. skip SDL tests if you don't have that extension)
  3. It runs multiple tests concurrently (see the -j option). The default concurrency is 4.
  4. It can test one or more builders. Currently this means it can run the tests through JIT, Native AOT, or both.
  5. It can compare expected results literally or to a regex
  6. It can test for explicit stderr output (e.g. parse errors)
  7. It can stop on test failure, and show expected vs actual results
  8. It can run a single test template, or recursively import a directory of them
  9. It's written in crack :)

The main test suite is run via "make check", as usual. You can find the source to screen, as well as the test templates themselves, in the screen/ directory. For more advanced testing (including running individual tests), run crack screen.crk --help

Monday, July 18, 2011

Crack 0.5 Released

We're pleased to announce the release of Crack 0.5. 

The main new feature of 0.5 is Generics.  Generics in Crack are somewhere between Java generics and C++ templates.  Like C++ templates, they are essentially generated by re-compiling the original code with parameter substitution.  Unlike C++ templates, parameters are limited to types.  Also, only generic classes are supported at this time.

Other notable changes in 0.5:

  • Support for first class functions and basic functors.  Functions now have types, and user defined classed may now implement an "oper call" method in order to make instances of the class callable using function-call syntax.
  • Implemented Platform Dependent Numeric Types (see and reworked the numeric type system to conform to the specification.
  • Added a command line parsing module.
  • Converted all of the containers to generics, and added a HashMap generic.
  • Added some date manipulation code.
  • Refactored the cmake build.
  • Added the "typeof()" operator.
  • Added full support for "oper to" conversions.
  • Enhancements to extension generation for class methods, constructors,  and C function name specification.
This might be the last release before 1.0.  If you're interested in the language, we encourage you to download it, try it out and give us feedback.  Once 1.0 is out, all changes will have to be backwards compatible until 2.0.

Tuesday, May 3, 2011

Crack 0.4 Released

We are pleased to announce the release of Crack 0.4.  The two major changes for this version are Exceptions (ala C++, Java and Python) and Ahead-of-time compiling (so you can now run "crackc" on your script and produce a nice, ready to run executable in addition to the traditional scripty mode).

There are also a few new smaller features:
  • Sequence initializers ("array[int] a = [1, 2, 3]" or "array[int]![1, 2, 3]")
  • Improved string interpolation (added calls to enter() and leave() methods at the beginning and ending of each expression, allowing us to do things like "String s = FStr() `this is $var`;")
  • Byte and integer string constants ("b'A' == 65", "i'\001\0' == 256")
  • A no-op @encoding annotation allowing scripts to identify their encoding for other tools.
This release has been a long time coming, we hope you like it. 

Friday, April 1, 2011

Exciting New Changes

During the time that we have been developing Crack, we have gotten a lot of
really good constructive criticism on the language.  This criticism has not
fallen upon deaf ears, and I am happy to announce some exciting changes coming
to the next version of Crack.

For one thing, it has been pointed out that naming the language after an
illicit drug that ruins people's lives may not have been the best decision. 
It's also hard to find information on the language by doing a search for
"crack" and the name is already overloaded in software technology to refer to
password cracking tools.

In response, we are changing the name of the language to "MINARA`"  This is an
enormously clever abbreviation of "Minara Is Not A Recursive Acronym`" 
Unfortunately, this name is already in use by an open-source vector drawing
tool (see so we have added the back-tick
character to the end of our name for purposes of disambiguation.

Another long-standing criticism of Crack (excuse me, MINARA`) has been that
there are already an abundance of C-like languages.  We acknowledge this, and
as such we are changing the entire syntax of the language.  As of the next
release, the language will instead adopt a Lisp-like syntax.

Unfortunately, Lisp is impossible for humans to read and is also more targeted
towards interpretation than compilation.  So MINARA` will adopt the following
syntactic and semantic conventions:

  • The basic lisp form of a function followed by its arguments will be preserved.  A MINARA` script will be a a list of such functional forms.
  • The resulting data structure is a nested list that can be thought of as the Abstract Syntax Tree for a MINARA` module.
  • Similar to Lisp, there are macros that are forms executed at compile time.  These are free to interpret any of the special types of lists any way they want, but they are applied after the processing of the comma and semicolon syntactic sugar defined below.  All of the basic statements (if/else, while, for, class...) are implemented as macros.
  • The following special syntactic conventions apply:
    • Unlike Lisp, which has a single parenthesized list type, MINARA` has four types of lists: a-lists, b-lists, c-lists and p-lists.
    • p-lists are the normal parenthesized Lisp function calls
    • A list enclosed in curly braces is like a quoted list in Lisp: it is not evaluated, it is a value.  Example: (print {1 2 3}). A macro may choose to compile the contents of a c-list, which makes them very suitable for statement blocks.  This is a c-list (a curly bracketed list).
    • The semicolon is syntactic sugar that is equivalent to enclosing all elements to the last semicolon or the beginning of the enclosing list in parenthesis.  For example, {print "hello"; print "world";}  is equivalent to {(print "hello") (print "world")}  The terminating semicolon is optional: if at least one semicolon is in the enclosing list, the entire enclosing list is split up into p-lists.
    • The square brackets are equivalent to a call of the "expr" function in the current context.  "expr" defaults to a macro that converts its arguments from a more traditional, infix style to the canonical, prefix list style.  Example: [a = b * 2 + 3] is equivalent to (expr b * 2 + 3) which would normally be transformed at compile time to (= a ((* b 2) 3))  This is a b-list (a "bracketed list")
    • The comma is similar to the semicolon.  The comma aggregates all elements up to the previous comma with the exception of the first element in the enclosing list into a b-list.  For example, (print 'value is', 1 + 2) is equivalant to (print ['value is'] [1 + 2]) or (print (expr 'value is') (expr 1 + 2)) or (print 'value is' (+ 1 2)) 
    • an element followed by a period and an identifier is equivalent to a call of the "attrex" function with the items before and after the period passed as arguments (like "expr", "attrex" is normally implemented as a macro which expands to various kinds of low-level attribute and member function access).  So (foo.setBar 'test') would be equivalent to ((attrex foo setBar) 'test').  This is an a-list ("attribute list")

All of syntactic constructs in MINARA` will be implemented as macros.  Here's an example of a class definition with some instance variables and methods:

    # Defined using a "class" macro, note that the base classes 
    # (Object and Named) must be specified in a list
    class Person : (Object Named) {
        # instance variable definitions.  Since we have to start
        # these with the name "var" we adopt pascal style
        var name : String, favorite_color : Color =;
        # the "duh" keyword in oper init indicates that arguments 
        # map trivially to their corresponding attributes.
        oper init(name; favorite_flavor) duh;
        # a couple of explicit implementation of abstract 
        # functions from Named
        implement setName(name: String) { name = newName; };
        implement getName() returns String { return name; };
        def isCompatibleWith(other: Person) returns bool {
            if [other.favorite_color == favorite_color] {
                return true;
            } else {
                return false;
        def clone() returns Person {
            return ( name favorite_color);

We think that everyone will appreciate these new changes to the language, and
apologize for our earlier mistakes.

Sunday, March 13, 2011

Platform Dependent Versus Universal Numeric Types

Implementing numeric types in a programming language is surprisingly difficult.  At this time, Crack supports Universal Numeric Types (UNTs - for example int32, uint64, byte) and Platform Dependant Numeric Types (PDNTs - int, uint, float).  The PDNT names are just aliases for the corresponding UNTs in the target compiler - so for example, if the C++ compiler you use to build crack has a 32 bit int, Crack's "int" will be an alias for "int32".  Additionally, the philosophy behind implicit type conversions is to allow them only if they do not result in loss of precision.

This overall approach is not without its problems:

  • It makes Crack code platform-dependent because there are expressions that will work on one platform but will result in a compile-time error on another platform.  For example, "int32 i = int(v);" works on platforms with 32 bit integers, but breaks on platforms with 64 bit integers.
  • You end up writing a lot of explicit type conversions in places where you really don't care that much (like when using a signed integer value for a function argument of type "uint").  For a scripting language valuing terse syntax, this is kind of lame.
So after some discussion on IRC, we've decided to change our approach a little bit.  The general philosophy now is that you should use a PDNT in situations where you care about performance or interoperability with C/C++ code and you should use a UNT in situations where you care about precision.  The manifestations of this decision are:

  • PDNTs will be promiscuous: any numeric type will implicitly convert to any PDNT type.  So "int i = float64(v);" will be perfectly legal on any platform.
  • There will be max-size, min-size assumptions about PDNTs.  In particular, they will all be at least 32 bits but no more than 64 bits in size.  Like everything else in the language, these assumptions are subject to change across major versions of the language.
  • UNTs will continue to apply the strict conversion rules.  However, because of the min-size/max-size assumptions, certain conversions from PDNTs will always be legal.  An example of this is "int64 i = int(v)".
There's still a platform dependency problem here because expressions like "int i = int64(v);" will vary in behavior at runtime depending on the size of an integer on the platform.  So we've essentially converted a compile-time portability issue to a runtime portability issue :-/.

To mitigate this effect, there will be a warning flag that allows you to identify the places where you could potentially lose precision with something like this.  We are also considering allowing the generation of a runtime check that would throw an exception if specific values will be truncated.

This change will probably go into the language in Crack 0.5.  For anyone interested, the formal proposal is at

Tuesday, March 8, 2011

AOT for Crack 0.4

One of the trademarks of a scripting language is of course: instant results. You edit your script and execute it immediately, skipping the traditional compile step with its associated build files, etc.

True to scripting language ideals, Crack executes scripts immediately using LLVM's excellent Just In Time (JIT) compiler to handle the heavywork of converting the compiled crack code to native instructions so that it can run both immediately and as fast as possible.

weyrick@mozek:~/crack$ cat hello.crk 
import cout;
cout `hello JIT\n`;
weyrick@mozek:~/crack$ crack hello.crk 
hello JIT

But what if you find yourself wishing for a native binary, just this once? You know, something like this instead:

weyrick@mozek:~/crack$ crackc hello.crk 
weyrick@mozek:~/crack$ ./hello 
hello JIT

What's a scripter to do? Well with Crack at least, you'll be in luck. Crack 0.4 will include an Ahead Of Time (AOT) mode which will create native binaries just like the example above. All imported crack modules will be included in the binary (something like a static link of the crack modules, although the binary itself is not statically linked). The annotation system (and macros) work for AOT binaries. We also have plans for full DWARF debugging information, which will allow source level debugging with tools like gdb.

Crack 0.4 is tentatively scheduled for release about the same time as LLVM 2.9 (beginning of April).

Friday, January 14, 2011

Crack 0.3 released

We are pleased to announce the release of crack 0.3.  The new version features the following enhancements:

  • Added support for extensions
    • Added a module to that can generate bindings for many C APIs
    • converted the runtime, GTK and PCRE modules to use the extension API
    • added (undocumented) support for SDL and OpenGL
  • Added the annotations subsystem
    • Used annotations to implement macros
    • Added the @static, @final, @FILE and @LINE built-in annotations
  • Added the math module
  • Added macro based generic containers.
  • Added the "for" statement (both C and iterator styles, so "for (x :in collection)" now works)
  • Aggregate type variables now default to null if no initializer is given.
That last item means that if you actually have written some crack code, we've probably broken it.  See the appendix of the manual for info on how to deal :-)

Dig in and send us feedback!