cyclang Language Overview

cyclang is a toy programming language that leverages the power of LLVM for efficient code execution. It is designed to transform your code into machine-ready instructions seamlessly. Here's a high level overview of how Cyclang works:

  1. Parsing the Grammar: cyclang uses the pest parser, an elegant parser written in Rust, to interpret and process cyclang code. You can delve into the intricacies of the cyclang parser in the source code here and the grammar file.

  2. Translating to LLVM IR: Once parsed, cyclang code gets converted to LLVM Intermediate Representation (IR) through the llvm-sys crate. LLVM IR is a low-level, type-rich representation suitable for efficient machine code generation.

  3. Just-In-Time Compilation: cyclang ensures quick and efficient execution of cyclang code by using the LLVM JIT (Just in Time) Execution engine. To see how this happens explore the Cyclang compiler source code here.

flowchart LR;
    CyclangLanguage-->PestParser;
    PestParser--> AST;
    AST-->|llvm-sys| LLVM-IR;
    LLVM-IR-->|LLVM-JIT-Engine| Output;

Language Features

Functional

This functional example demonstrates how to write a recursive function in cyclang to compute the Fibonacci series.

#![allow(unused)]
fn main() {
fn fib(i32 n) -> i32 {
    if (n < 2) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}
print(fib(20));
}

For Loop

This snippet showcases the standard for loop syntax, iterating from 0 to 9 and printing each value.

#![allow(unused)]
fn main() {
for (let i = 0; i < 10; i++)
{  
    print(i);
}
}

While Loop

In this example, a while loop continues execution as long as the condition remains true. The loop increments the val variable and exits once val reaches 10.

#![allow(unused)]
fn main() {
let cond = true;
let val = 0;
while (cond) {
    val = val + 1;
    if (val == 10) {
       cond = false;
    }
}
print(val);
}

Installing and Running (MacOS)

Note: I've only tested this on MacOS.

You will need LLVM 17 installed before you install cyclang, runn the following command

brew install llvm@17

Then the easiest way to install the binary currently is through the Rust package manager Cargo - see Install Rust. Once the step above is done, then run

cargo install cyclang

Test

Ensure you have the /bin folder set up (this will dump LLVM IR). Run tests through make test.

Debugging Release Mode Errors

If getting errors with the release mode then use Rust Sanitizer flags to debug.

Run the following command to identify memory issues

RUSTFLAGS="-Z sanitizer=address" cargo run --target={TARGET_ARCH} --release -- --file ./examples/simple.cyclo --output-llvm-ir

Where target architecture is your architecture i.e aarch64-apple-darwin

Also set proc_macro2 -> 1.66 if using Rust nightly compiler in the Cargo.toml

proc-macro2 = { version = "1.0.66", features=["default", "proc-macro"] }

Installing and Running (MacOS)

Note: I've only tested this on MacOS.

You will need LLVM 17 installed before you install cyclang, runn the following command

brew install llvm@17

Then the easiest way to install the binary currently is through the Rust package manager Cargo - see Install Rust. Once the step above is done, then run

cargo install cyclang

Test

Ensure you have the /bin folder set up (this will dump LLVM IR). Run tests through make test.

Debugging Release Mode Errors

If getting errors with the release mode then use Rust Sanitizer flags to debug.

Run the following command to identify memory issues

RUSTFLAGS="-Z sanitizer=address" cargo run --target={TARGET_ARCH} --release -- --file ./examples/simple.cyclo --output-llvm-ir

Where target architecture is your architecture i.e aarch64-apple-darwin

Also set proc_macro2 -> 1.66 if using Rust nightly compiler in the Cargo.toml

proc-macro2 = { version = "1.0.66", features=["default", "proc-macro"] }

WebAssembly

Output the WASM File for use.

llc -march=wasm32 -filetype=obj ./bin/main.ll -o ./bin/output.o
wasm-ld --no-entry --export-all -o ./bin/output.wasm ./bin/output.o

To convert this to a human readable format use

wasm2wat ./bin/output.wasm -o ./bin/output.wat  

There is an example of a Fibonacci sequence in ./examples/wasm/fib.js which loads and executes the Fibonacci sequence. Just run node ./examples/wasm/fib.js.