edlc_codegen_cranelift 0.2.13

Cranelift codegen backend for the EDL compiler
Documentation
mod foo;

use test_bin::foo::bar;
use test_lib::println;

use test_bin::foo::TEST;
use test_bin::foo::boa::TESTOS;

/// Manual implementation of the `min` function for `i32` signed integer types.
fn min(x: i32, y: i32) -> i32 {
    if x < y {
        // returns x if x < y through early-return
        ret x;
    } else {
        // print test message and return y through the return value if the if-else chain
        println("what?");
        todo()
        // y
        // std::panic("your code is ass");
        // ret todo();
    }
}

fn todo() -> ! {
    std::panic("unimplemented");
}

type MyData<T> = struct {
    name: str,
    id: usize,
    buffer: T,
};

impl core::Add<MyData<f32>, f32> for MyData<f32> {
    type Output = MyData<f32>;

    fn add(self, rhs: f32) -> Self::Output {
        MyData {
            name: self.name,
            id: self.id,
            buffer: self.buffer + rhs
        }
    }
}

// creates some tuple
fn make_tuple(args: { first: i32, second: f32 }) -> (i32, f32) {
    (args.first, args.second)
//    todo()
}

type SVector<T, const N: usize>
where T: f32 | f64 = struct {
    data: [T; N],
    test: T,
};

impl<const N: usize> SVector<f32, N> {
    fn norm(self) -> f32 {
        let mut out = 0.0;
        let mut i = 0usize;
        loop {
            if i >= N { break }
            out += self.data[i] * self.data[i];
            i += 1;
        }
        out
    }
}

impl<T, const N: usize> SVector<T, N>
where
    T: f32 | f64,
    const N: 1 | 2 | 3 | 4,
{
    fn print(self) {
        std::io::print("(");
        let mut i = 0usize;
        loop {
            if i >= N { break }
            if i != 0 {
                std::io::print(", ");
            }
            std::io::print(self.data[i]);
            i += 1;
        }
        std::io::print(")");
    }
}

impl<T> SVector<T, 1> {
    fn new(x: T) -> Self
    where T: f32 | f64,
    {
        SVector {
            data: [x],
            test: x,
        }
    }
}

impl<T> SVector<T, 2> {
    fn new(x: T, y: T) -> Self {
        SVector {
            data: [x, y],
            test: x,
        }
    }
}

impl<T> SVector<T, 3> {
    fn new(x: T, y: T, z: T) -> Self {
        SVector {
            data: [x, y, z],
            test: x,
        }
    }
}

/// Main entry point to the solver implementation.
fn main() {
    // this function call uses the import from above to find the function definition in the source tree
    let mut x = bar(1.0, 2.0);
    // this function uses the relative module name to find the function definition.
    // since the module `foo` is a child of this module, we do not need to specify the name of the parent module
    // explicitly in the functions' qualifier name
    x = foo::bar(0.1, x);
    // this function call uses the fully qualified name to resolve the function `bar` in the source tree.
    x = test_bin::foo::bar(x, 3.1415);

    // std::panic("test"); // if this is commented in, the remainder of the function is flagged for dead code!
    // todo();

    let mut data_fragment = MyData { name: "i am a data fragment", id: 1, buffer: 42.0f32 };
    println(data_fragment.name);
    println(data_fragment.id);
    println(data_fragment.buffer);

    let tmp = data_fragment + 0.3_f32;
    println(tmp.name);
    println(tmp.buffer);

    // create some tuple from a dict (lol)
    let t: (i32, f32) = make_tuple({ first: 0, second: 0.2 });
    println(t.0);
    println(t.1);

    let data: [usize; _] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    println(TESTOS);
    foo::boa::i_am_testos();
    println(min(-5, -3));

    let mut i = 0usize;
    let mut max: usize = 0;
    loop {
        if i >= TEST {
            break;
        }
        println("Hello, world!");
        foo::print_pi();
        println(foo::pi);

        max = usize::max(max, data[i]);
        i += 1;
    }
    // todo()
}

#[setup]
fn simple_setup() {
    println("setting up testing environment");
}

#[teardown]
fn simple_teardown() {
    println("tearing down testing environment");
}

#[bench(setup=simple_setup, teardown=simple_teardown)]
#[test(setup=simple_setup, teardown=simple_teardown)]
fn test_array() {
    println("testing weird bug with array accesses...");
    let A_0 = 1.0_f64;
    let A_1 = 1.0_f64;
    let A_2 = 1.0_f64;

    let pi = 3.14159265358979_f64;
    let twopi = pi * 2.0;

    let A: [f64; 3] = [1.0, 1.0, 1.0];
    let sigma: [f64; 3] = [0.1, 0.1, 0.1];

    let prefactor: f64 = 1.0 / (f64::sqrt(twopi * twopi * twopi) * sigma[0] * sigma[1] * sigma[2]);
    println(prefactor);
    println("success!");
}

#[bench]
fn benchmark() {
    let mut i: usize = 0;
    let mut out: f64 = 1.0;
    loop {
        if i >= 1000_000 { break; }
        out = f64::sin(out * 1.5);
        i += 1;
    }
    println(out);
}


// -- testing reference related stuff
impl<T, const N: usize> SVector<T, N> {
    fn index_mut(&mut self, index: usize) -> &mut T {
        core::assert(index < N);
        ret self.data[index];
    }

    fn index(&self, index: usize) -> &T {
        core::assert(index < N);
        ret self.data[index];
    }

    fn set_index(&mut self, index: usize, value: T) {
        self.data[index] = value;
    }

    fn print_test(&self) {
        println(self.test);
    }
}

fn write_value(x: &mut i32) {
    let some_value = 99;
    x = some_value;
}

fn write_float(x: &mut f64) {
    x = 4.2;
}

fn write_literal(x: &mut i32) {
    x = 42;
}

fn write_buffer(x: &mut i32, y: &i32) {
    x = y;
}

#[test]
fn test_write_buffer() {
    let mut x: i32 = 0;
    write_buffer(mut x, 67);
    core::assert(x == 67);

    write_literal(mut x);
    core::assert(x == 42);

    write_value(mut x);
    core::assert(x == 99);
}

#[test]
fn test_vec_mut_access() {
    let mut vec = SVector::new(2.1_f64, 1.0_f64);
    vec.print_test();
    core::assert(vec.index(0) == 2.1);
    core::assert(vec.index(1) == 1.0);

    vec.data[0] += 0.1;
    core::assert(vec.index(0) == 2.2);

    vec.set_index(0, 4.2);
    core::assert(vec.index(0) == 4.2);

    vec.index_mut(1) = 204.1;
    core::assert(vec.index(1) == 204.1);

    write_float(vec.index_mut(1));
    core::assert(vec.index(1) == 4.2);
}

#[test]
fn test_temp_reference() {
    let value = [1_i32, 2, 3, 4, 5][2];
    core::assert(value == 3_i32);
    // [1_i32, 2, 3, 4, 5][2] = 3;  <-- this must *not* compile!
}

type CfdType = f64;

#[test]
fn test_associated_alias() {
    let x: CfdType = 2.0;
    println(CfdType::sqrt(x));
    core::assert(CfdType::floor(CfdType::sqrt(x) * 100.0) == 141.0);
    let x = x * 2.0;
    core::assert(x == 4.0);
}