Related sites: | site map |

# aiju.de Home of aiju

- › about me/
- › b/
- » code/
- - » RatJS
  - › homework/
  - › k/
  - › misc/
  - › pdp11/
- › donate
- › electronics/
- › legal
- › misc/
- › plan 9/

# RatJS

RatJS (Rational Javascript) is a Javascript preprocessor (the name is a reference to ratfor) designed to minimise mental anguish for C programmers that find themselves writing Javascript for one reason or another. It's designed to be fairly minimal and to translate to Javascript in a straightforward manner.

Source (Plan 9 C)

## Overview

Expression and statement syntax and semantics is mostly the same as Javascript, but variables and functions can optionally be defined with types, e.g.

    int
    sum(int a[])
    {
        int i, s;

        s = 0;
        for(i = 0; i < a.length; i++)
            s += a[i];
        return s;
    }

Types are checked at compile-time and relatively strong typing is enforced, e.g. there are no implicit casts between numbers and strings. Explicit casts can be added with C syntax and the var type shares Javascript's weak typing semantics.

The available types are

- `var` (`function` is a synonym with `var` to support Javascript function syntax for compatibility),
- `bool`,
- `string`,
- `int` (should maybe be called double. The name was chosen to reduce anxiety caused by lack of a true integer type.),
- `void` (accepted elsewhere but only really useful for return values; can also be used to denote an empty argument list to minimise frustration from old C habits),
- array types, using type`[]` syntax,
- `struct` types,
- map types,
- enum types.

Trailing comma is supported in lists; it is not included in the output to minimise interoperability issues.

## Struct types

`Struct` types are defined using C-like syntax

    struct Foo {
        int x, y, z;
        string w;
    };

Again the name was chosen for mental comfort and it should be remembered these are passed by reference and thus more like pointers to C structures, in particular

    Foo f;

    f.x = 42;

would be incorrect, as `f` needs to be initialised first.

Currently a constructor has to be defined manually using

    void
    Foo(int x)
    {
        this.x = 42;
        this.y = 0;
        this.z = 0;
        this.w = "";
    }

Instances can then be created using C++-like syntax `f = new Foo(42);`.

Methods can be defined using the syntax

    void
    Foo.bar(int z)
    {
        this.x += z;
    }

`Struct` literals use the syntax

    Foo{x: 0, y: 3, w: "foo"}

There is no support for inheritance at this time.

## Map types

Map types provide a different way to think about Javascript objects, i.e. as associative arrays. The syntax is

    int foo[string] = {one: 1, two: 2, three: 3};

    int z;
    string a;
    z = foo[a];

Instead of `string` an enumeration type can be used and `[string]` and `[EnumType]` maps can be implicitly interconverted at this time. The use of other types is discouraged.

## Enum types

Enum types are true strongly typed enumerations (unlike C) that are implemented using strings, e.g.

    enum Color { CRED, CGREEN, CBLUE };
    Color c;
    c = CRED;

compiles to

    var c;
    c = "CRED";

Note that unlike some "modern" languages the enum values live in the scope of the enum declaration (like C).

The following are also valid:

    enum { CRED, CGREEN, CBLUE } c;
    enum Color { CRED, CGREEN, CBLUE } c;

## Prototypes

All input files are effectively concatenated and parsed as one unit. The compiler looks ahead for functions (but not variables or types), so, unlike C, function prototypes are unnecessary. They can be used to refer to extern code (including Javascript builtins), e.g.

    int string.length;
    string string.substr(int, ... int);
    extern var undefined;

(`...` specifies that all further parameters are optional, it's also supported for "native" methods, with the usual Javascript semantics of using `undefined` as the default). The `extern` keyword inhibits the generation of a `var` declaration in the Javascript output.

A declaration of the form

    struct Foo;

can be used to support mutually referencing structs.

## Closures

Anonymous functions/closures can be expressed using the syntax

    abs = int(int x){
        if(x < 0)
            return -x;
        else
            return x;
    };

There is a shorter syntax

    square = int(int x) return x*x;

which I may at some point extend to allow control statements, such as `if`.

Javascript arrow syntax is not currently supported but I may add support for that if I add type inference.

## Type safety

There is limited type safety as type conversion code is generated only for `int`, `string` and enumeration types at this time and the enumeration conversion does not verify that the value is in the correct range.

    Foo f;
    int i[];
    Color c;
    string s;

    c = (var) f;
    i = (var) f;
    s = (var) f;

compiles happily to

    c = f;
    i = String(f);
    s = String(f);

which leaves `c` and `i` with invalid values.

Consider `var` to be a "danger type" like `void *` in C.

## Known bugs

- Array methods are not checked
- Closures and struct literals may to be parenthesized if used as part of an expression (the parser gets confused sometimes).
- `goto` does not exist and Duff's Device does not compile.
- Struct literals of the form `Foo{...}` do not compile quite correctly (Javascript doesn't know about their methods). I mainly use them for the idiom `new Foo(Foo{...})` which I may change to something else to resolve this.
- The compiler sometimes produces `has no return statement` errors incorrectly since it doesn't recognise infinite loops other than `for(;;)`.

## Planned features

- Tuples
- Some weak form of generics (maybe)
- Set/used analysis

## Unsupported Javascript constructs

(Non-comprehensive list)

- variable declarations in `for` statements (you'll need a RatJS'99 compiler for that)
- anything modern (classes etc.)
- semicolon insertion
- regular expression syntax