Skip to content

Latest commit

 

History

History
336 lines (233 loc) · 7.5 KB

README.md

File metadata and controls

336 lines (233 loc) · 7.5 KB

LO Docs

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

Top level expressions are only allowed at the top level of the file (not inside functions).

Function definition

fn add(x: u32, y: u32): u32 {
    return a + b;
};

Exporting functions

Function can be exported from WASM module like this:

export fn main(): u32 {
    return 0;
}

Functions are exported with their original names

Include

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

Code expressions are allowed inside function bodies.

Integer literals

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 expressions

return 123;

Expression type: never

Binary operators

Binary operators require both operands to be of the same type.

1 + 2

Numeric operators

+, -, *, >>

Expression type: Same as operand type

Comparision operators

<

Expression type: bool

If expressions

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
};

Function calls

add(2, 2);

Expression type: same as function return type

🧱 Types

Types lol.

LO Type WASM
void -
never -
bool i32
u32 i32

never type means that code execution will not reach this point.

💬 Comments

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 usage

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 $@

(info) Error reporting

Compiler errors are printed to <stderr> using the following format:

<file-path>:<line>:<col> - <message>

Compiling

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.

Inspecting code (IDE intergration)

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

Pretty Printing

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

(experimental) Interpreting source code

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 or main.

<stdout> - Interpreted program output (if any). In case of main entrypoint the function's result is printed.

(experimental) Interpreting WASM modules

Usage:

lo input.wasm --eval-wasm

Parses and interprets input.wasm. Supports a subset of WASI. Entrypoint is either _start or main.

<stdout> - Interpreted program output (if any). In case of main entrypoint the function's result is printed.

Comment rearrangement

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
};

🧪 Compiler development

Building the initial compiler

  • 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

Running tests

  • Requirements:

    • Install Node.js for running tests
  • Run ./utils.mjs test

    This runs tests defined in utils.mjs. Test programs are located in examples/test

NOTE: there is currently no built-in testing solution in the compiler, existing test setup is good enough for now.