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 withvar
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 idiomnew 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 thanfor(;;)
.
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