Rawr overview
This document is intended for programmers who want a quick overview of Rawr and are already familiar with system programming languages like C.
Hello world
Create a file called hello.rawr
containing the following:
#start {
std.print("Rawr!\n")
}
You can run it directly with the rawr run
command by specifying the path to the hello.rawr
file.
$ rawr run hello.rawr
Rawr!
The rawr build
command creates an executable that can be run later.
$ rawr build hello.rawr
$ ./hello.exe
Rawr!
Comments
There are two forms of comments:
- Single-line comments start with the sequence
//
and stop at the end of the line. - Multi-line comments start with a
/*
and stop with a paring sequence*/
. They can be nested.
// This is a line comment.
/* This is
a multiline comment. */
/* /* Nested comments are allowed. */ */
Variable
The syntax for a variable declaration is name : type
. It means we declare a variable named name
of type type
.
a: i32 // a i32
b: ^i32 // a pointer to a i32
c: [5]f32 // an array of five f32
We write types just like we read them, from left to right. A “pointer to a pointer to an array of five i32
” is written ^^[5]i32
.
If the type is omited, it will be inferred from the type of the expression.
a := 123 // a i32
b := 3.14 // a f32
c := false // a bool
Function
Function declaration syntax is name fn(arguments) -> return_type
. The arrow and the return type can be omitted if the function returns nothing.
This function is named sum
, accepts two i32
as parameters and returns an i32
. Its type is fn(i32, i32) -> i32
.
sum fn(left: i32, right: i32) -> i32 {
return left + right
}
You can call a function with the ()
operator.
sum(1 , 3) // Returns 4
Type
Name Description
-----------------------------------
u8 Unsigned 8-bit integer
u16 Unsigned 16-bit integer
u32 Unsigned 32-bit integer
u64 Unsigned 64-bit integer
i8 Signed 8-bit integer
i16 Signed 16-bit integer
i32 Signed 32-bit integer
i64 Signed 64-bit integer
f32 32-bit floating point number
f64 64-bit floating point number
bool Boolean value
You can get the type of a variable with the .type
field, who returns a Type
.
a: i32
type : Type = a.type
#assert type == i32
Operators
Arithmetic
Name Syntax
-----------------------------
Sum a + b
Difference a - b
Product a * b
Quotient a / b
Modulo a mod b
Comparison
Name Syntax
-----------------------------
Equal a == b
Not equal a != b
Less a < b
Less or equal a <= b
Greater a > b
Greater or equal a <= b
Logical
Name Syntax
------------------------------
Logical and a and b
Logical or a or b
Logical negation not a
Assignment
Name Syntax
----------------------------------
Assignment a = b
Addition assignment a += b
Subtraction assignment a -= b
Multiplication assignment a *= b
Division assignment a /= b
Increment a++
Decrement a--
Assignments are statements, not expression. They cannnot be used where an expression is expected, like in an array subscript.
a[i++] = 1 // Error
while a = next() { // Error
}
Address-of and dereference
The operator ^
takes the address of a variable and returns a pointer. The operator @
dereferences a pointer.
a: i32 = 1
pointer: ^32 = a^ // Take the address of 'a'
pointer@ = 2 // Dereference 'pointer'
#assert a == 2
#assert a == pointer@
Optional
The optional type represents an optional value, there might be something or nothing in it. It is denoted with the ?
symbol and can be applied to any types.
a: ?i32 // an optional i32
b: ?^f32 // an optional pointer to a f32
c: ?Vec3 // an optional Vec3 (a structure)
You can assign something to an optional variable or set it to nothing with None
.
a : ?i32
a = 1 // There is something in the optional, the value 1
a = None // There is nothing in the optional, it is empty
Since an optinal value may be empty you always have to explicity check it and unwrap its value if there is one.
TODO
You cannot assign None
to a pointer, there is no NULL
pointers like in C. You should use an optional pointer instead.
a : ^i32 = None // Illegal
b : ?^i32 = None // Legal
Array
Arrays begin at 1
and are bound checked by default.
a: [3]i8 = [1, 2, 3]
#assert a[0] = 1 // Error, arrays start at 1
#assert a[1] = 1
#assert a[2] = 2
#assert a[3] = 3
Arrays can have multiple dimensions.
b: [2][2] = [[1, 2], [3, 4]]
#assert b[2][1] = 3
You can access the length of an array with the .length
field.
array : [20]i32
#assert array.length == 20
Slice
Arrays or only a part of them can be sliced. Slicing is bound checked by default.
array: [4]i32 = [1, 3, 4, 5]
slice1: []i32 = array[2..3] // Slice from the second element to the third element included.
slice2: []i32 = array[..2] // Slice from the first element to the second element included.
slice3: []i32 = array[1..] // Slice from the first element to the last element included.
slice4: []i32 = array[..] // Slice the whole array.
slice1[1] = 42 // Changes the second element of the array to 42. The array is now equal to [1, 42, 3, 4]
You can access the length of a slice with the .length
field.
array : [20]i32
slice : []i32 = array[5..10]
#assert slice.length == 5
Conversion
There is no implicit conversion between unsigned and signed integer, between integer and float or between integer and boolean. Theses operations need to be done explicitly with the cast operator as
.
a: f32 = 1.0
b: i32 = 2
a + b // Error, mismatch type
a + b as f32 // OK
Condition
The control flow of the program can be manipuled with the if
and else
statements.
if foo {
std.print("foo is true")
} else if bar {
std.print("foo is false and bar is true")
} else {
std.print("Neither foo or bar are true")
}
The parenthesis around the condition can be ommited but the brace is mandatory.
Loops
While
while foo() {
std.print("Still looping\n")
}
Do While
do {
std.print("Still looping\n")
} while foo()
For
for i := 1; i <= 5; i++ {
std.print("Still looping\n")
}
Short For
for
has a short form to loop on every elements of an array or a slice. Two variables will be implicity declared in the scope: it
who contain the current element and it_index
who is the current index of the loop.
array := [10, 20, 30]
for array {
// it and it_index are accessible in this scope.
}
Constant
Constants are values that will never change so they can be inlined at compile time.
a const = 1
b const = 2.0
c const = "hello"
Structure
Structure declarations look like that:
Vec3 struct {
x: f32
y: f32
z: f32
}
Structure’s members can be acceded with the dot operator .
. The operator works on structure and pointer to structures.
v: Vec3 = {1.0, 2.0, 3.0}
#assert ptr.x == 1.0
ptr : ^Vec3 = v^ // We take a pointer of v
#assert ptr.y == 2.0
Enumeration
An enum declaration:
Fruit enum {
Banana
Apple
Cherry
}
Enumeration variants are typed and have their own namespace.
a: Fruit = Fruit.Banana
Alias
Aliases create an additional name for a type.
GLint alias_of i32
Module
Scope
A module in Rawr is just a directory. Every .rawr
files in the same directory are implicitly part of the same namespace and can reference each other without importing anything.
For exemple, with a hierarchy like this:
my_module
├── a.rawr
└── b.rawr
a.rawr
has access to b.rawr
’s declarations…
// my_module/a.rawr
#start {
b()
}
a fn() {
std.print("This is a.rawr\n")
}
…and b.rawr
to a.rawr
’s declarations
// my_module/b.rawr
b fn() {
a()
std.print("This is b.rawr\n")
}
Compiling
To compile a module, its path need to be provided to the compiler.
$ rawr run my_module
This is a.rawr
This is b.rawr
If no path if provided, the compiler will compile the current working directory.
$ cd my_module
$ rawr run
This is a.rawr
This is b.rawr
Foreign interface
C types are available since their sizes and signedness can vary depending of the architecture and operating system.
Name C Equivalent
-----------------------------------
c_char char
c_uchar unsigned char
c_schar signed char
c_short short
c_ushort unsigned short
c_int int
c_uint unsigned int
c_long long
c_ulong unsigned long
f32 float
f64 double
cstring char*
To call a C function, its prototype must first be declared with the #extern
keyword.
puts fn(str: cstring) -> c_int #extern
Precedence table
Category Operator
---------------------------------
Postfix () [] [..] . ^ @ as
Unary - not
Multiplicative / *
Additive + -
Comparison == != >= < <=
Logical and and
Logical or or