Overview
TODO
This is an example of a program:
def fib(n: u16): u16 {
if n < 2 {
return n;
} else {
return fib(n - 1) + fib(n - 2);
}
}
fib(20); # 6765
Programs
A program is a sequence of:
- function declarations
- statements
- TODO: if-else, for, for-in, etc; with no semicolon
Statements are delimited with semicolons (;
), and are one of:
- expression (e.g.
1+2
) - function call
- lambda definition
- variable
- variable declaration
- return statement
XXX: do we really want expressions without effects?
TODO: entry point; main
to be C compatible?
Modules
A Micro file must start with the module name.
# our main module (this is a comment)
module main
The module name is used by the linker.
TODO: "import" and use modules.
Variables
Variable declaration:
var a: u8 = 123;
Group declaration:
var (
a: u8 = 123,
b: u16 = 1234
);
Variables must be initialized, there are not default values, with the exception of structures that is optional.
Variables can refer to a memory address with @
operator:
var p: u8 = @0x8000;
p; # whatever byte is in address 0x8000 (peek)
p = 0; # byte at 0x8000 is now 0 (poke)
Global variables are exported by default, unless they are defined as private:
private val local: u8 = 123;
Constants
Constant are immutable values and may not have memory allocated to them:
# won't allocate memory
const K: u8 = 10;
# will allocate 10 bytes
const V: [10]u8 = 255;
Group declaration:
const (
A: u8 = 128,
B: u16 = 4096
);
Must be resolved at compilation time.
var a: u8 = 1;
const A: u8 = a + 1; # error: unresolved value
Built-in types
Integers
Type | Description | Samples |
---|---|---|
u8 | unsigned 8-bit | 123; 0xce; 0b10000; |
s8 | signed 8-bit | -123; |
u16 | unsigned 16-bit | 65535; 0xffff; |
s16 | signed 16-bit | -4096; |
Built-in functions:
Function | Description | Samples |
---|---|---|
hi | Get the MSB on a 16-bit number | hi(0xaabb); # 0xaa |
lo | Get the LSB on a 16-bit number | lo(0xaabb); # 0xbb |
hi
and lo
can also be used with references (functions, structures and arrays):
def fn() { return; }
hi(fn); # MSB of fn address
Type conversion is explicit:
var a: u8 = 10;
var b: u16 = 10;
a + b; # error: type mismatch
u16(a) + b; # 20: u16
Booleans
Logic operators result on a boolean type.
Type | Description | Samples |
---|---|---|
bool | boolean | true; false; 1 == 1; |
Functions
Type | Description | Samples |
---|---|---|
([parameters]) -> [return] | function | (a: u8): u8 { return a + 1; } |
([parameters]) | function (no return value) | () { return; } |
Functions can be declared with def
when they have a name, or as anonymous using the lambda syntax.
def add(a: u8, b: u8): u8 {
return a + b;
}
add(2, 8); # 10
Anonymous function:
# increment the value passed as argument
(a: u8): u8 {
return a + 1;
}(10); # 11
Function are higher order functions:
def apply(fn: (u8): u8, a: u8, b: u8): u8 {
return fn(a, b);
}
apply(add, 2, 10); # 8
# using a lambda
apply((a: u8, b: u8): u8 {
return a + b;
},
2, 8); # 10
# lambdas can be assigned to variables
var double: (u8): u8 = (a: u8): u8 {
return a + a;
};
double(10); # 20
Anonymous functions can only access local variables (closures aren't supported):
def closure(a: u8): (): u8 {
return (): u8 {
return a; # invalid return, undefined a
};
}
Functions are exported by default, unless they are defined as private:
# not exported (exported is the default)
private def dec(a: u8): u8 {
return a - 1;
}
Variables of type function use references:
def fn() { return; }
# fn and fn2 refer to the same function
var fn2: () = fn;
Special value: nil
nil
is a reference not pointing to a value, used for example on variables with type function or structure.
Using a nil reference will result in a runtime error.
# fn doesn't hold a reference
var fn: (u8): u8 = nil;
fn(10); # runtime error
Structures
Structures can be used to group data and functions.
Structure can be declared with def
and provide values for the grouped data. Those values will be used when allocating an instance.
Any variable or function declared in the structure can be accessed like a local variable inside the structure, and in the instances using the dot (.
) operator.
def A {
# constants can be part of an structure as well
const INC: u8 = 1;
var (
n: u8 = 100,
m: bool = false,
dec: (u8): u8 = nil
);
# it is possible to define functions local
# to a structure
def inc(): u8 {
n = n + INC;
return n;
}
}
# allocate memory for structure A
var a: A;
a.n; # 100
a.m; # false
a.dec; # nil
a.inc(); # 101
a.inc(); # 102
a.n; # 102
Variables of type structure handle a reference:
var b: A = a;
# b points to the same data as a
b.inc(); # 103
a.n; # 103
# c doesn't hold a reference to an instance of A
var c: A = nil;
Recursive structures are not supported and local structures can't be used as return value in a function.
XXX: how do we implement e.g. linked lists?
Arrays
Arrays are zero based and are supported for all types.
XXX: including arrays? e.g. [10][10]u8
.
Array size is a numeric literal or a constant expression (must be known at compilation type), and all the elements on an array must be of the same type.
Arrays are initialised to literals with [
and ]
providing a list of values.
# array of 5 u8
var arr: [5]u8 = [0, 0, 0, 0, 0];
It is possible so initialize the array providing one single value that will be used for all the elements:
# this is equivalent to the previous example using [ and ]
var arr: [5]u8 = 0;
The array size is optional when initializing using literals:
var xs: []bool = [true, true, false];
len(xs); # 3
var xs2: []bool = true; # error: missing array size
Array elements can be accessed using []
:
var arr: [5]u8 = 0;
arr[0]; # 0
arr[0] = 100;
arr[0]; # 100
Variables of type array handle a reference.
# arr and arr2 refer to the same array
var arr2: [5]u8 = arr;
Local arrays can't be used as return value in a function.
def fn(): [5]u8 {
var local [5]u8 = 0;
return local; # error: returning a local value of type array
}
Built-in functions:
Function | Description | Samples |
---|---|---|
len | get the length of an array as u16 | len(arr); # 5 |
incbin | include a binary file as []u8 | const f: []u8 = incbin("file.bin"); |
Strings
TODO: a zero ended array of u8 with special initializers
Operators
Micro uses the same operators and almost the same operator precedence as C, from more to less priority:
! - ~
/ * %
&
- +
<< >> | ^
> >= < <=
|| &&
!= ==
=
Arithmetic operators only apply to integers.
Comparison operators only apply to integers, with the exception of ==
and !=
that also apply to other types (if both operands are of the same type).
Logic operators apply to booleans and they are lazy operators (e.g. in a && b
, b
won't be evaluated if a
is false).
Flow control
TODO
- if-else
- loops (while-like, infinite, break, continue)
- for-in
External functions
TODO
- is this "import"?
- calling conventions?
- namespace support?
In-line ASM
TODO