Documentation of LO language features.
This is WIP. Main goal is to document all features for now, better structuring and wording will come later.
For up-to-date code examples see examples directory.
- 🪂 Top level expressions
- 🧑💻 Code Expressions
- 🧱 Types
- 💬 Comments
- 🔨 Compiler usage
- 🧪 Compiler development
Top level expressions are only allowed at the top level of the file (not inside functions).
fn add(x: u32, y: u32): u32 {
return a + b;
};
Function can be exported from WASM module like this:
export fn main(): u32 {
return 0;
}
Functions are exported with their original names
include "./file.lo";
Include pathes are relative to the file they are included to.
Will not include the same file twice.
File paths are fully resolved before including.
Example:
include "./abc.lo"; // will include
include "./some-folder/../abc.lo"; // will skip
Code expressions are allowed inside function bodies.
123 // u32 literal
0x3F // u32 hex literal, uppercase letters only
Int literals are always fully typed, there is no generic "number" type that will get narrowed later.
Expression type: depends on the literal
return 123;
Expression type:
never
Binary operators require both operands to be of the same type.
1 + 2
+
, -
, *
, >>
Expression type: Same as operand type
<
Expression type:
bool
if x < 0 {
return 1;
};
Expression type:
void
NOTE: parens are not required around the condition
NOTE: semicolon is required after if expression, it not is optional like in C
Supports else if
and else
branches:
if x < 0 {
// negative
} else if x > 0 {
// positive
} else {
// zero
};
add(2, 2);
Expression type: same as function return type
Types lol.
LO Type | WASM |
---|---|
void |
- |
never |
- |
bool |
i32 |
u32 |
i32 |
never
type means that code execution will not reach this point.
Only //
comments are supported for now.
// this is a comment
fn main(): u32 {
// this is another comment
return 0;
};
Comments are allowed between any tokens, but they might get moved during formatting. See Pretty Printing for more info.
Compiler is shipped as a standalone WASM binary: lo.wasm
It uses WASI preview 1 APIs for communication. This allows it to be executed in any WASI compatible runtime.
Example of running the compiler using wasmtime:
wasmtime --dir=. lo.wasm
This should print something like the following:
Usage: lo <file> [<mode>]
Where <mode> is either:
--compile (default if not provided)
--inspect
--pretty-print
--eval (experimental)
--eval-wasm (experimental)
NOTE: following examples will be using
lo
"executable". This is OS dependent and is not shipped with the compiler.On Linux/MacOS you can alias it to
wasmtime --dir=. lo.wasm $@
Compiler errors are printed to <stderr>
using the following format:
<file-path>:<line>:<col> - <message>
lo input.lo
Compiles
input.lo
file into a WASM module
<stdout>
- WASM module in binary format
NOTE: any imported files will be automatically resolved. You don't need to provide them separately.
lo input.lo --inspect
Prints inspection info of
input.lo
file in JSON format. Useful for IDE integrations.
<stdout>
- JSON object with inspection results
Inspection object schema is defined as DiagnisticItem
in VSCode extension sources
NOTE: this formats a single file at a time, imported files are not formatted
Usage:
lo input.lo --pretty-print
Formats
input.lo
using non-configurable formatting style
<stdout>
- Formatted source
Usage:
lo input.lo --eval
Compiles
input.lo
and interprets the WASM module built (without producing any intermediate files). Supports a subset of WASI. Entrypoint is either_start
ormain
.
<stdout>
- Interpreted program output (if any). In case ofmain
entrypoint the function's result is printed.
Usage:
lo input.wasm --eval-wasm
Parses and interprets
input.wasm
. Supports a subset of WASI. Entrypoint is either_start
ormain
.
<stdout>
- Interpreted program output (if any). In case ofmain
entrypoint the function's result is printed.
Comments that are placed in "weird" places will be moved into closest "proper" places.
This keeps formatter quite simple and makes comment placing more consistent.
For example the following:
// this is a comment
fn main():
// this will be moved
u32 { // this will also be moved
// this is fine
return 0; // this will also be moved
};
Will get formatted as:
// this is a comment
fn main(): u32 {
// this will be moved
// this will also be moved
// this is fine
return 0;
// this will also be moved
};
-
Requirements:
- Install rustup
- Install nightly:
rustup toolchain install nightly
- Add WASM target:
rustup +nightly target add wasm32-unknown-unknown
- You can also find configs for GitHub Codespaces and GitPod in this repo
-
Run
./build.sh
This will build the compiler with cargo, putting resulting WASM binary into
lo.wasm
-
Requirements:
- Install Node.js for running tests
-
Run
./utils.mjs test
This runs tests defined in
utils.mjs
. Test programs are located inexamples/test
NOTE: there is currently no built-in testing solution in the compiler, existing test setup is good enough for now.