mod util;
use util::*;
#[test]
fn precedence() {
let result = run("
let a = true;
let b = false;
let c = true;
let d = false;
ret_bool((a || b && c) == (a || (b && c)));
ret_bool((a && b || c && d) == ((a && b) || (c && d)));
ret_bool((a && b && c || d) == (((a && b) && c) || d));
ret_bool((!a && b || c) == (((!a) && b) || c));
ret_bool((!a && b || c) == !(a && b || c));
");
assert_all(&result, &[ true, true, true, true, false ]);
}
#[test]
fn expression_eval_order() {
let result = run("
fn one() -> i32 { ret_i32(1); 1 }
fn two() -> i32 { ret_i32(2); 2 }
fn main() {
ret_i32(one() + two());
ret_i32(one() - two() + one());
ret_i32(one() - (two() + one()));
ret_i32(one() - two() * two());
ret_i32((two() + two()) / two());
}
");
assert_all(&result, &[
1i32, 2, 3,
1, 2, 1, 0,
1, 2, 1, -2,
1, 2, 2, -3,
2, 2, 2, 2,
]);
}
#[test]
fn expression_short_circuit() {
let result = run("
fn t() -> bool { ret_bool(true); true }
fn f() -> bool { ret_bool(false); false }
fn main() {
ret_bool(t() && f());
ret_bool(t() && f() || t());
ret_bool(f() && t() || t());
ret_bool(t() || f() && t());
ret_bool(t() && f() || t() && f());
ret_bool(f() && t() || f() && t());
}
");
assert_all(&result, &[
true, false, false,
true, false, true, true,
false, true, true,
true, true,
true, false, true, false, false,
false, false, false,
]);
}
#[test]
fn stack_value_expressions() {
let result = run("
ret_i32(1 + 4);
ret_i32(1 + 4 * 2);
ret_i32((1 + 4) * 2);
ret_i32(5 - 7);
ret_i32(5 - 7 * 2);
ret_i32((5 - 7 * 2) / 3);
ret_i32(5 - 8 * 2 / 4);
ret_i32(5 % 9 * 2);
ret_i32(9 % 9 * 2);
ret_i32(5 % 7 -2 * 2);
ret_i32(1 + -5 % 7 -2 * 2);
");
assert_all(&result, &[
1i32 + 4,
1 + 4 * 2,
(1 + 4) * 2,
5 - 7,
5 - 7 * 2,
(5 - 7 * 2) / 3,
5 - 8 * 2 / 4,
5 % 9 * 2,
9 % 9 * 2,
5 % 7 -2 * 2,
1 + -5 % 7 -2 * 2,
]);
}
#[test]
fn numerics() {
let result = run("
ret_u8( 255 - 1 );
ret_u16( 65535 - 2 );
ret_u32( 4294967295 - 3 );
ret_u64( 18446744073709551615 - 4 );
ret_i8( 127 - 5 );
ret_i16( 32767 - 6 );
ret_i32( 2147483647 - 7 );
ret_i64( 9223372036854775807 - 8 );
ret_f32( 1234567.0 * 7654321.0 );
ret_f64( 123456789.0 * 987654321.0 );
");
assert(&result[0], 255u8 - 1);
assert(&result[1], 65535u16 - 2);
assert(&result[2], 4294967295u32 - 3);
assert(&result[3], 18446744073709551615u64 - 4);
assert(&result[4], 127i8 - 5);
assert(&result[5], 32767i16 - 6);
assert(&result[6], 2147483647i32 - 7);
assert(&result[7], 9223372036854775807i64 - 8);
assert(&result[8], 1234567.0f32 * 7654321.0);
assert(&result[9], 123456789.0f64 * 987654321.0);
}
#[test]
fn compound_i8() {
let result = run("
let mut x = 1;
x += 1;
ret_i8(x);
x *= 6;
ret_i8(x);
x -= 3;
ret_i8(x);
x /= 3;
ret_i8(x);
x %= 2;
ret_i8(x);
");
assert_all(&result, &[ 2i8, 12, 9, 3, 1 ]);
}
#[test]
fn compound_i64() {
let result = run("
let mut x = 10000000000;
x += 1;
ret_i64(x);
x *= 6;
ret_i64(x);
x -= 6;
ret_i64(x);
x /= 3;
ret_i64(x);
x %= 2;
ret_i64(x);
");
assert_all(&result, &[ 10000000001i64, 60000000006, 60000000000, 20000000000, 0 ]);
}
#[test]
fn compound_f64() {
let result = run("
let mut x = 1.000001;
x += 1.0;
ret_f64(x);
x *= 6.0;
ret_f64(x);
x -= 3.0;
ret_f64(x);
x /= 3.0;
ret_f64(x);
x %= 3.0;
ret_f64(x);
");
assert_all(&result, &[
1.000001f64 + 1.0,
(1.000001 + 1.0) * 6.0,
((1.000001 + 1.0) * 6.0) - 3.,
(((1.000001 + 1.0) * 6.0) - 3.) / 3.,
((((1.000001 + 1.0) * 6.0) - 3.) / 3.) % 3.,
]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_u8_u16() {
let result = run("
ret_u16(23u8 as u16);
ret_u16(255u8 as u16);
ret_u16(243u8 as u16);
");
assert_all(&result, &[ 23u16, 255, 243 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_u64_u16() {
let result = run("
ret_u16(23u64 as u16);
ret_u16(280u64 as u16);
ret_u16(243u64 as u16);
");
assert_all(&result, &[ 23u64 as u16, 280u64 as u16, 243u64 as u16 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_u8_u64() {
let result = run("
ret_u64(23u8 as u64);
ret_u64(255u8 as u64);
ret_u64(7u8 as u64);
");
assert_all(&result, &[ 23u64, 255, 7 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_u64_u8() {
let result = run("
ret_u8(23u64 as u8);
ret_u8(280u64 as u8);
ret_u8(243u64 as u8);
");
assert_all(&result, &[ 23u8, 255, 243 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i8_i16() {
let result = run("
ret_i16(-23i8 as i16);
ret_i16(-125i8 as i16);
ret_i16(127i8 as i16);
");
assert_all(&result, &[ -23i16, -125, 127 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i64_i16() {
let result = run("
ret_i16(-23i64 as i16);
ret_i16(-280i64 as i16);
ret_i16(243i64 as i16);
");
assert_all(&result, &[ -23i64 as i16, -280i64 as i16, 243i64 as i16 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i8_i64() {
let result = run("
ret_i64(-23i8 as i64);
ret_i64(-128i8 as i64);
ret_i64(125i8 as i64);
");
assert_all(&result, &[ -23i64, -128, 125 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i64_i8() {
let result = run("
ret_i8(-23i64 as i8);
ret_i8(-280i64 as i8);
ret_i8(243i64 as i8);
");
assert_all(&result, &[ -23i8, -128, 127 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i8_u16() {
let result = run("
ret_u16(-23i8 as u16);
ret_u16(-128i8 as u16);
ret_u16(127i8 as u16);
");
assert_all(&result, &[ 0u16, 0, 127 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i64_u16() {
let result = run("
ret_u16(-23i64 as u16);
ret_u16(-280i64 as u16);
ret_u16(243i64 as u16);
");
assert_all(&result, &[ 0u16, 0, 243 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i8_u64() {
let result = run("
ret_u64(-23i8 as u64);
ret_u64(-128i8 as u64);
ret_u64(127i8 as u64);
");
assert_all(&result, &[ 0u64, 0, 127 ]);
}
#[allow(overflowing_literals)]
#[test]
fn cast_i64_u8() {
let result = run("
ret_u8(-23i64 as u8);
ret_u8(-280i64 as u8);
ret_u8(243i64 as u8);
");
assert_all(&result, &[ 0u8, 0, 243 ]);
}
#[test]
fn cast_f64_f32() {
let result = run("
ret_f32(3.1415f64 as f32);
ret_f32(-3.1415f64 as f32);
ret_f32(68123.45f64 as f32);
");
assert_all(&result, &[ 3.1415f64 as f32, -3.1415f64 as f32, 68123.45f64 as f32 ]);
}
#[test]
fn cast_f32_f64() {
let result = run("
ret_f64(3.1415f32 as f64);
ret_f64(-3.1415f32 as f64);
ret_f64(68123.45f32 as f64);
");
assert_all(&result, &[ 3.1415f32 as f64, -3.1415f32 as f64, 68123.45f32 as f64 ]);
}
#[test]
fn cast_i16_f64() {
let result = run("
ret_f64(3i16 as f64);
ret_f64(-3i16 as f64);
ret_f64(-9731i16 as f64);
");
assert_all(&result, &[ 3i16 as f64, -3i16 as f64, -9731i16 as f64 ]);
}
#[test]
fn cast_i32_f32() {
let result = run("
ret_f32(3i32 as f32);
ret_f32(-3i32 as f32);
ret_f32(-9731i32 as f32);
");
assert_all(&result, &[ 3i32 as f32, -3i32 as f32, -9731i32 as f32 ]);
}
#[test]
fn cast_f64_i16() {
let result = run("
ret_i16(3.1415f64 as i16);
ret_i16(-3.1415f64 as i16);
ret_i16(68123.45f64 as i16);
ret_i16(2147483657f64 as i16);
ret_i16(-2147483657f64 as i16);
");
assert_all(&result, &[ 3i16, -3, 32767, 32767, -32768 ]);
}
#[test]
fn cast_f32_i8() {
let result = run("
ret_i8(3.1415f32 as i8);
ret_i8(-3.1415f32 as i8);
ret_i8(68123.45f32 as i8);
ret_i8(2147483657f64 as i8);
ret_i8(-2147483657f64 as i8);
");
assert_all(&result, &[ 3i8, -3, 127, 127, -128 ]);
}
#[test]
fn cast_f32_u16() {
let result = run("
ret_u16(3.1415f32 as u16);
ret_u16(-3.1415f32 as u16);
ret_u16(68123.45f32 as u16);
ret_u16(2147483657f32 as u16);
ret_u16(-2147483657f32 as u16);
");
assert_all(&result, &[ 3u16, 0, 65535, 65535, 0 ]);
}
#[test]
fn op_order_gt() {
let result = run("
let x = 1u8;
ret_bool(x*3 > --x*3);
ret_bool(x == 0);
");
assert_all(&result, &[ true, true ]);
}
#[test]
fn op_order_lt() {
let result = run("
let y = 1u8;
ret_bool(y*3 < ++y*3);
ret_bool(y == 2);
");
assert_all(&result, &[ true, true ]);
}
#[test]
fn branching() {
let result = run("
let mut x = 1;
let y = 2;
while x <= 3 {
if x < y {
ret_i32(x);
} else if x > y {
ret_i32(y);
} else {
ret_i32(x + y);
}
x = x + 1;
}
");
assert_all(&result, &[ 1i32, 4, 2 ]);
}
#[test]
fn branching_ref_cleanup() {
let result = run("
if true {
let a = \"Hello\";
ret_string(a);
} else {
let b = \"World\";
ret_string(b);
}
");
assert_all(&result, &[ "Hello".to_string() ]);
}
#[test]
fn array_literal() {
let result = run("
let x = [ 1, 2, 3, 4 ];
ret_i32(x[0]);
ret_i32(x[1]);
ret_i32(x[2]);
ret_i32(x[3]);
");
assert_all(&result, &[ 1i32, 2, 3, 4 ]);
}
#[test]
fn array_nesting() {
let result = run("
let x = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ];
ret_i32(x[0][0]);
ret_i32(x[0][1]);
ret_i32(x[0][2]);
ret_i32(x[1][0]);
ret_i32(x[1][1]);
ret_i32(x[1][2]);
");
assert_all(&result, &[ 1i32, 2, 3, 4, 5, 6 ]);
}
#[test]
fn array_subindex() {
let result = run("
let x = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ];
let y = x[0];
let z = x[1];
ret_i32(y[0]);
ret_i32(y[1]);
ret_i32(y[2]);
ret_i32(z[0]);
ret_i32(z[1]);
ret_i32(z[2]);
");
assert_all(&result, &[ 1i32, 2, 3, 4, 5, 6 ]);
}
#[test]
fn array_inference1() {
let result = run("
let x = [ [ [ 1, 2, 3, 4 ] ] ];
let y = x[0];
let z = y[0];
let u = z[1];
ret_i8(u);
");
assert_all(&result, &[ 2i8 ]);
}
#[test]
fn array_inference2() {
let result = run("
let x = [ [ [ 1, 2, 3, 4 ] ] ];
let y = x[0];
let z = y[0];
ret_i8(z[0]);
ret_i8(z[1]);
ret_i8(z[2]);
");
assert_all(&result, &[ 1i8, 2, 3 ]);
}
#[test]
fn array_mixed_construction() {
let result = run("
let x = \"Hello\";
for w in [ x, \"World\" ] {
ret_str(w);
}
");
assert_all(&result, &[ "Hello".to_string(), "World".to_string() ]);
}
#[test]
fn array_simple_dynamic_constructor() {
let result = run("
let abc = \"abc\";
let cba = \"cba\";
let x = [ abc, cba ];
ret_str(x[0]);
ret_str(x[1]);
");
assert_all(&result, &[ "abc".to_string(), "cba".to_string() ]);
}
#[test]
fn array_flattened_dynamic_constructor() {
let result = run("
let ghj = \"ghj\";
let abc = \"abc\";
let cba = \"cba\";
let jhg = \"jhg\";
let x = [ [ ghj, abc ], [ cba, jhg ] ];
ret_str(x[0][1]);
ret_str(x[1][0]);
");
assert_all(&result, &[ "abc".to_string(), "cba".to_string() ]);
}
#[test]
fn array_nested_dynamic_constructor() {
let result = run("
let ghj_abc = [ \"ghj\", \"abc\" ];
let cba_jhg = [ \"cba\", \"jhg\" ];
let x = [ ghj_abc, cba_jhg ];
ret_str(x[0][1]);
ret_str(x[1][0]);
");
assert_all(&result, &[ "abc".to_string(), "cba".to_string() ]);
}
#[test]
fn array_nested_var_dynamic_constructor() {
let result = run("
let ghj = \"ghj\";
let abc = \"abc\";
let cba = \"cba\";
let jhg = \"jhg\";
let ghj_abc = [ ghj, abc ];
let cba_jhg = [ cba, jhg ];
let x = [ ghj_abc, cba_jhg ];
ret_str(x[0][1]);
ret_str(x[1][0]);
");
assert_all(&result, &[ "abc".to_string(), "cba".to_string() ]);
}
#[test]
fn array_casting() {
let result = run("
fn accept(x: [ u8 ], y: [ u16 ]) {
ret_u16((x[0] as u16) + y[0]);
ret_u16((x[1] as u16) + y[1]);
ret_u16((x[2] as u16) + y[2]);
ret_u16((x[3] as u16) + y[3]);
}
fn main() {
let x: [ u8 ] = [ 1, 2, 3, 4 ];
let y: [ u16 ] = [ 4, 3, 2, 1, 0 ];
accept(x, y);
}
");
assert_all(&result, &[ 5u16, 5, 5, 5 ]);
}
#[test]
#[should_panic(expected = "Resolver error: Expected type [ u8 ], got [ u16 ] in line 7, column 20.")]
fn array_type_fail() {
run("
fn accept(x: [ u8 ]) {
ret_u8(x[3]);
}
fn main() {
let x: [ u16 ] = [ 1, 2, 3, 4, 5 ];
accept(x);
}
");
}
#[test]
fn array_len() {
let sa_type = STACK_ADDRESS_TYPE;
let result = run(&format!("
let array_u16: [ u16 ] = [ 1, 2, 3, 4 ];
let array_u8: [ u8 ] = [ 4, 3, 2, 1, 0 ];
ret_{sa_type:?}(array_u16.len());
ret_{sa_type:?}(array_u8.len());
ret_{sa_type:?}([ 5, 4, 3, 2, 1, 0 ].len());
", ));
assert_all_sa(&result, &[ 4, 5, 6 ]);
}
#[test]
fn array_push() {
let sa_type = STACK_ADDRESS_TYPE;
let result = run(&format!("
let dynamic_array = [ 1u16, 2, 3 ];
dynamic_array.push(4u16);
ret_{sa_type:?}(dynamic_array.len());
ret_{sa_type:?}(dynamic_array[3] as {sa_type:?});
"));
assert_all_sa(&result, &[ 4, 4 ]);
}
#[test]
fn array_ref_elements() {
let result = run("
struct Struct {
value: u8,
}
fn main() {
let a: [ Struct ] = [ ];
a.push(Struct { value: 1 });
a.push(Struct { value: 2 });
a.push(Struct { value: 3 });
a.push(Struct { value: 4 });
a.push(Struct { value: 5 });
a.push(Struct { value: 6 });
let b = a.pop(); // 6
ret_u8(b.value);
a.truncate(4);
let c = a.pop(); // 4
ret_u8(c.value);
let d = a.remove(0); // 1
ret_u8(d.value);
for x in a { // 2, 3
ret_u8(x.value);
}
ret_u8(a.len() as u8); // 2
}
");
assert_all(&result, &[ 6u8, 4, 1, 2, 3, 2 ]);
}
#[test]
fn struct_access() {
let result = run("
struct Test {
ba: bool,
bb: bool,
ia: i8,
ib: i16,
ic: i32,
id: i64,
ua: u8,
ub: u16,
uc: u32,
ud: u64,
fa: f32,
fb: f64,
}
fn main() {
let x: Test = Test {
ba: true, bb: false,
ia: -1, ib: 2, ic: -3, id: 4,
ua: 1, ub: 2, uc: 3, ud: 4,
fa: 0.01, fb: 0.001
};
ret_i8(x.ia);
ret_i16(x.ib);
ret_i32(x.ic);
ret_i64(x.id);
ret_u8(x.ua);
ret_u16(x.ub);
ret_u32(x.uc);
ret_u64(x.ud);
ret_f32(x.fa);
ret_f64(x.fb);
ret_bool(x.ba);
ret_bool(x.bb);
}
");
assert(&result[0], -1i8);
assert(&result[1], 2i16);
assert(&result[2], -3i32);
assert(&result[3], 4i64);
assert(&result[4], 1u8);
assert(&result[5], 2u16);
assert(&result[6], 3u32);
assert(&result[7], 4u64);
assert(&result[8], 0.01f32);
assert(&result[9], 0.001f64);
assert(&result[10], true);
assert(&result[11], false);
}
#[test]
fn struct_nesting() {
let result = run("
struct MoreInner {
one: i8,
two: i16,
three: i32,
}
struct Inner {
a: f32,
b: i64,
c: MoreInner,
}
struct Outer {
first: u8,
second: u16,
third: Inner,
}
fn main() {
let x: Outer = Outer { first: 3, second: 345, third: Inner { a: 3.1415, b: -23, c: MoreInner { one: -1, two: -378, three: -123 } } };
ret_u8(x.first);
ret_u16(x.second);
ret_f32(x.third.a);
ret_i64(x.third.b);
ret_i8(x.third.c.one);
ret_i16(x.third.c.two);
ret_i32(x.third.c.three);
}
");
assert(&result[0], 3u8);
assert(&result[1], 345u16);
assert(&result[2], 3.1415f32);
assert(&result[3], -23i64);
assert(&result[4], -1i8);
assert(&result[5], -378i16);
assert(&result[6], -123i32);
}
#[test]
fn struct_array() {
let result = run("
struct Inner {
ia: u8,
ib: [ u64 ],
}
struct Outer {
oa: i16,
ob: Inner,
}
fn main() {
let x: Outer = Outer {
oa: -369,
ob: Inner {
ia: 8,
ib: [ 3, 333, 333333 ],
}
};
ret_i16(x.oa);
ret_u8(x.ob.ia);
ret_u64(x.ob.ib[0]);
ret_u64(x.ob.ib[1]);
ret_u64(x.ob.ib[2]);
}
");
assert(&result[0], -369i16);
assert(&result[1], 8u8);
assert(&result[2], 3u64);
assert(&result[3], 333u64);
assert(&result[4], 333333u64);
}
#[test]
fn member_assign_primitive() {
let result = run("
struct Inner {
ia: u8,
ib: [ u64 ],
}
struct Outer {
oa: i16,
ob: Inner,
}
fn main() {
let mut x: Outer = Outer {
oa: 0,
ob: Inner {
ia: 0,
ib: [ 0, 0, 0 ],
}
};
x.oa = -369;
x.ob.ia = 8;
ret_i16(x.oa);
ret_u8(x.ob.ia);
}
");
assert(&result[0], -369i16);
assert(&result[1], 8u8);
}
#[test]
fn index_assign_primitive() {
let result = run("
struct Inner {
ia: u8,
ib: [ u64 ],
}
struct Outer {
oa: [ u8 ],
ob: Inner,
}
fn main() {
let x: Outer = Outer {
oa: [ 0, 0, 0 ],
ob: Inner {
ia: 0,
ib: [ 0, 0, 0 ],
}
};
x.oa[0] = 13;
x.oa[1] = 133;
x.oa[2] = 255;
x.ob.ib[0] = 12345678901;
x.ob.ib[1] = 12345678902;
x.ob.ib[2] = 12345678903;
ret_u8(x.oa[0]);
ret_u8(x.oa[1]);
ret_u8(x.oa[2]);
ret_u64(x.ob.ib[0]);
ret_u64(x.ob.ib[1]);
ret_u64(x.ob.ib[2]);
}
");
assert(&result[0], 13u8);
assert(&result[1], 133u8);
assert(&result[2], 255u8);
assert(&result[3], 12345678901u64);
assert(&result[4], 12345678902u64);
assert(&result[5], 12345678903u64);
}
#[test]
fn heap_compound_assign() {
let sa_type = STACK_ADDRESS_TYPE;
let result = run(&format!("
fn left() -> {sa_type:?} {{
ret_u8(9);
0
}}
fn right() -> u8 {{
ret_u8(6);
1
}}
fn main() {{
let test = [ 0u8 ];
ret_u8(test[0]);
test[left()] += right();
ret_u8(test[0]);
}}
"));
assert_all(&result, &[ 0u8, 9, 6, 1 ]);
}
#[test]
fn heap_compound_assign64() {
let sa_type = STACK_ADDRESS_TYPE;
let result = run(&format!("
fn left() -> {sa_type:?} {{
ret_u64(9);
0
}}
fn right() -> u64 {{
ret_u64(6);
1
}}
fn main() {{
let test = [ 0u64 ];
ret_u64(test[0]);
test[left()] += right();
ret_u64(test[0]);
test[left()] += right();
ret_u64(test[0]);
test[left()] -= right();
ret_u64(test[0]);
}}
"));
assert_all(&result, &[ 0u64, 9, 6, 1, 9, 6, 2, 9, 6, 1 ]);
}
#[test]
fn assign_heap_index_target() {
let result = run("
let array = [ [ 0u8, 1 ] ];
array[0] = [ 2u8, 3 ];
ret_u8(array[0][1]);
array[0][1] = 4;
ret_u8(array[0][1]);
array[0][1] += 4;
ret_u8(array[0][1]);
array[0][1] -= 1;
ret_u8(array[0][1]);
");
assert_all(&result, &[ 3u8, 4, 8, 7 ]);
}
#[test]
fn assign_heap_var_target() {
let result = run("
let mut values = [ 5u8, 6 ];
let morevalues = [ [ 15u8, 16 ], [ 12, 13 ] ];
values = [ 7u8, 8 ];
ret_u8(values[1]);
values = morevalues[1];
ret_u8(values[0]);
// compound ops not defined for arrays
");
assert_all(&result, &[ 8u8, 12 ]);
}
#[test]
fn assign_stack_target() {
let result = run("
let mut value = 1u8;
let values = [ 0u8, 10 ];
value = 2;
ret_u8(value);
value = values[1];
ret_u8(value);
value += 2;
ret_u8(value);
value += values[1];
ret_u8(value);
");
assert_all(&result, &[ 2u8, 10, 12, 22 ]);
}
#[test]
fn string_literal() {
let result = run("
let hello = \"Hello World!\";
let echo = \"Hello Echo!\";
ret_str(hello);
ret_string(hello);
ret_str(echo);
ret_string(echo);
");
assert_all(&result, &[
"Hello World!".to_string(), "Hello World!".to_string() ,
"Hello Echo!".to_string(), "Hello Echo!".to_string() ,
]);
}
#[test]
fn for_in_negative() {
let result = run("
for i in -3..3 {
ret_i32(i);
}
");
assert_all(&result, &[ -3i32, -2, -1, 0, 1, 2 ]);
}
#[test]
fn for_in_none() {
let result = run("
for i in 1..1 {
ret_u16(i);
}
");
assert!(result.len() == 0);
}
#[test]
fn for_in_dec() {
let result = run("
for i in 1..0 {
ret_i8(i);
}
");
assert!(result.len() == 0);
}
#[test]
fn for_in_negative_inclusive() {
let result = run("
for i in -3..=3 {
ret_i8(i);
}
");
assert_all(&result, &[ -3i8, -2, -1, 0, 1, 2, 3 ]);
}
#[test]
fn for_in_equal_inclusive() {
let result = run("
for i in 1..=1 {
ret_u16(i);
}
");
assert_all(&result, &[ 1u16 ]);
}
#[test]
fn for_in_dec_inclusive() {
let result = run("
for i in 1..=0 {
ret_i8(i);
}
");
assert!(result.len() == 0);
}
#[test]
fn for_in_inference_let() {
let result = run("
for x in 1..4 {
let y = x * 2;
ret_u8(y);
}
");
assert_all(&result, &[ 2u8, 4, 6 ]);
}
#[test]
fn for_in_inference_assign() {
let result = run("
let mut y;
for x in 1..4 {
y = x * 2;
ret_u8(y);
}
ret_u8(y);
");
assert_all(&result, &[ 2u8, 4, 6, 6 ]);
}
#[test]
fn for_in_array() {
let result = run("
for x in [ 7u8, 11, 13, 17 ] {
ret_u8(x);
}
");
assert_all(&result, &[ 7u8, 11, 13, 17 ]);
}
#[test]
fn for_in_array_var() {
let result = run("
let array = [ 7u8, 11, 13, 17 ];
for x in array {
ret_u8(x);
}
");
assert_all(&result, &[ 7u8, 11, 13, 17 ]);
}
#[test]
fn for_in_array_struct() {
let result = run("
struct Test {
inner: u8,
}
fn main() {
let array = [ Test { inner: 7 }, Test { inner: 17 }];
for x in array {
ret_u8(x.inner);
}
}
");
assert_all(&result, &[ 7u8, 17 ]);
}
#[test]
fn for_in_array_string() {
let result = run("
let array = [ \"Hello\", \"World\" ];
for x in array {
ret_string(x);
}
");
assert_all(&result, &[ "Hello".to_string(), "World".to_string() ]);
}
#[test]
fn for_in_inference() {
let result = run("
let array = [ 1, 2, 3, 4 ];
for i in array {
ret_u8(i);
}
");
assert_all(&result, &[ 1u8, 2, 3, 4 ]);
}
#[test]
fn recursion() {
let result = run("
fn fib(n: i32) -> i32 {
if n < 2 {
n
} else {
fib(n - 1) + fib(n - 2)
}
}
fn main() {
ret_i32(fib(1));
ret_i32(fib(2));
ret_i32(fib(5));
ret_i32(fib(7));
}
");
assert_all(&result, &[ 1i32, 1, 5, 13 ]);
}
#[test]
fn unary_op() {
let result = run("
let val = true;
ret_bool(val);
ret_bool(!val);
ret_bool(!!val);
ret_bool(!!!val);
");
assert_all(&result, &[ true, false, true, false ]);
}
#[test]
fn postfix_suffix() {
let result = run("
let val = 0i8;
ret_i8(val++);
ret_i8(val--);
ret_i8(++val);
ret_i8(--val);
");
assert_all(&result, &[ 0i8, 1, 1, 0 ]);
}
#[test]
fn heap_postfix_suffix() {
let result = run("
struct Test {
field: u8,
}
fn main() {
let x = [ 0u8 ];
let y = x[0]++; // used result
let z = ++x[0];
x[0]++; // unused result
++x[0];
ret_u8(x[0]);
ret_u8(y);
ret_u8(z);
let a = Test { field: 0 };
let b = a.field++; // used result
let c = ++a.field;
a.field++; // unused result
++a.field;
ret_u8(a.field);
ret_u8(b);
ret_u8(c);
}
");
assert_all(&result, &[
4u8, 0, 2,
4u8, 0, 2,
]);
}
#[test]
fn explicit_return() {
let result = run("
fn test(x: i32) -> i32 {
ret_i32(x);
if x == 1 {
ret_i32(1);
return 1;
ret_i32(-1);
} else if x == 2 {
ret_i32(2);
// return from sub-block
{
return 2;
}
ret_i32(-2);
} else {
if x == 3 {
ret_i32(3);
return 3;
ret_i32(-3);
} else if x == 4 {
ret_i32(4);
return 4;
ret_i32(-4);
}
// else fall through
ret_i32(5);
return 5;
ret_i32(-5);
}
ret_i32(-6);
}
fn main() {
ret_i32(test(1));
ret_i32(test(2));
ret_i32(test(3));
ret_i32(test(4));
ret_i32(test(5));
ret_i32(test(6));
}
");
assert_all(&result, &[
1i32, 1, 1,
2, 2, 2,
3, 3, 3,
4, 4, 4,
5, 5, 5,
6, 5, 5,
]);
}
#[test]
fn block_result() {
let result = run("
fn test(x: i32) -> i32 {
ret_i32(x);
if x == 1 {
ret_i32(1);
1
} else if x == 2 {
ret_i32(2);
// result from sub-block
{
2
}
} else {
if x == 3 {
ret_i32(3);
return 3;
} else if x == 4 {
ret_i32(4);
return 4;
}
// if no explicit return happened above
ret_i32(5);
5
}
}
fn main() {
ret_i32(test(1));
ret_i32(test(2));
ret_i32(test(3));
ret_i32(test(4));
ret_i32(test(5));
ret_i32(test(6));
}
");
assert_all(&result, &[
1i32, 1, 1,
2, 2, 2,
3, 3, 3,
4, 4, 4,
5, 5, 5,
6, 5, 5,
]);
}
#[test]
fn unused_result() {
let result = run("
fn test1(x: i32) -> i64 {
ret_i32(x);
return x as i64;
}
fn test2(x: i32) -> i64 {
ret_i32(x);
x as i64
}
fn test3(x: i32) -> i64 {
ret_i32(x);
{ x as i64 }
}
fn main() {
for i in 0..7 {
test1(i);
test2(i);
test3(i);
}
}
");
assert_all(&result, &[
0i32, 0, 0,
1, 1, 1,
2, 2, 2,
3, 3, 3,
4, 4, 4,
5, 5, 5,
6, 6, 6,
]);
}
#[test]
fn heap_return() {
let result = run("
struct Inner {
c: u32,
}
struct Outer {
a: u32,
b: Inner,
}
fn test() -> Inner {
let x = Outer {
a: 11,
b: Inner {
c: 13,
}
};
return x.b;
}
fn main() {
let mut y = test();
ret_u32(y.c);
y.c += 1;
ret_u32(y.c);
}
");
assert_all(&result, &[
13u32, 14
]);
}
#[test]
fn heap_result() {
let result = run("
struct Inner {
c: u32,
}
struct Outer {
a: u32,
b: Inner,
}
fn main() {
let mut y = {
let x = Outer {
a: 11,
b: Inner {
c: 13,
}
};
x.b
};
ret_u32(y.c);
y.c += 1;
ret_u32(y.c);
}
");
assert_all(&result, &[
13u32, 14
]);
}
#[test]
#[ignore]
fn heap_compare() {
let result = run("
let array = [ 7u8, 7 ];
ret_bool(array != [ 7u8, 7 ]);
ret_bool(array == [ 7u8, 7 ]);
ret_bool(array != [ 8u8, 7 ]);
ret_bool(array == [ 8u8, 7 ]);
ret_bool(array != [ 7u8, 8 ]);
ret_bool(array == [ 7u8, 8 ]);
");
assert_all(&result, &[
false, true,
true, false,
true, false,
]);
}
#[test]
fn string_compare() {
let result = run("
let string = \"abc\";
let cmp_a = \"abb\";
ret_bool(string != cmp_a);
ret_bool(string == cmp_a);
ret_bool(string < cmp_a);
ret_bool(string <= cmp_a);
ret_bool(string > cmp_a);
ret_bool(string >= cmp_a);
let cmp_b = \"abc\";
ret_bool(string != cmp_b);
ret_bool(string == cmp_b);
ret_bool(string < cmp_b);
ret_bool(string <= cmp_b);
ret_bool(string > cmp_b);
ret_bool(string >= cmp_b);
let cmp_c = \"abd\";
ret_bool(string != cmp_c);
ret_bool(string == cmp_c);
ret_bool(string < cmp_c);
ret_bool(string <= cmp_c);
ret_bool(string > cmp_c);
ret_bool(string >= cmp_c);
");
assert_all(&result, &[
true, false, false, false, true, true,
false, true, false, true, false, true,
true, false, true, true, false, false,
]);
}
#[test]
fn string_len_compare() {
let result = run("
let string = \"abc\";
let cmp_a = \"ab\";
ret_bool(string != cmp_a);
ret_bool(string == cmp_a);
ret_bool(string < cmp_a);
ret_bool(string <= cmp_a);
ret_bool(string > cmp_a);
ret_bool(string >= cmp_a);
let cmp_b = \"abcd\";
ret_bool(string != cmp_b);
ret_bool(string == cmp_b);
ret_bool(string < cmp_b);
ret_bool(string <= cmp_b);
ret_bool(string > cmp_b);
ret_bool(string >= cmp_b);
");
assert_all(&result, &[
true, false, false, false, true, true,
true, false, true, true, false, false,
]);
}
#[test]
fn string_concat() {
let result = run("
let a = \"Hello\";
let b = \"World\";
let result = a + \" \" + b;
ret_bool(result == \"Hello World\");
ret_bool(result != \"Hello World\");
ret_bool(result == \"Hello World fake\");
ret_bool(result != \"Hello World fake\");
");
assert_all(&result, &[
true, false,
false, true
]);
}
#[test]
fn string_compound_concat() {
let result = run("
let mut result = \"Hello\";
result += \"World\";
ret_bool(result == \"HelloWorld\");
ret_bool(result != \"Something else\");
ret_bool(result != \"HelloWorld\");
");
assert_all(&result, &[ true, true, false ]);
}
#[test]
fn string_compound_heap_concat() {
let result = run("
struct Test {
s: String
}
fn main() {
let mut result = Test { s: \"Hello\" };
result.s += \"World\";
ret_bool(result.s == \"HelloWorld\");
ret_bool(result.s != \"Something else\");
ret_bool(result.s != \"HelloWorld\");
}
");
assert_all(&result, &[ true, true, false ]);
}
#[test]
fn string_loop_concat() {
let result = run("
let test = \"Hello World\";
for i in 0..=5 {
test = test + (i as String);
}
ret_string(test);
ret_str(test);
");
assert_all(&result, &[ "Hello World012345".to_string(), "Hello World012345".to_string() ]);
}
#[test]
fn dead_code_result() {
let result = run("
fn result() -> u32 {
if true {
return 1;
} else if true {
return 2;
} else {
return 3;
}
let dead_code: f64 = 3.14;
dead_code
}
fn return_() -> u32 {
if false {
return 1;
} else if true {
return 2;
} else {
return 3;
}
let dead_code: f64 = 3.14;
return dead_code;
}
fn main() {
ret_u32(result());
ret_u32(return_());
}
");
assert_all(&result, &[
1u32, 2u32
]);
}
#[test]
fn temporary_heap_objects() {
let result = run("
fn main() {
ret_string(\"Temporary\");
ret_string(\"Heap\");
ret_string(\"Objects\");
}
");
assert_all(&result, &[ "Temporary".to_string(), "Heap".to_string(), "Objects".to_string() ]);
}
#[test]
fn dynamic_constructor() {
let result = run("
struct Test {
a: u32,
b: String,
}
fn main() {
let x = Test { a: 1100101, b: \"Hello\" + \"World\" };
ret_string(x.b);
ret_u32(x.a);
}
");
assert(&result[0], "HelloWorld".to_string());
assert(&result[1], 1100101u32);
}
#[test]
fn trait_resolution() {
let result = run("
struct StructA {
a: u8,
}
struct StructB {
b: u64,
}
pub trait TestTrait {
fn required(self: Self, value: u8) -> String;
fn provided(self: Self, value: u8) -> String {
self.required(value) + \" provided\"
}
}
impl TestTrait for StructA {
fn required(self: Self, value: u8) -> String {
\"A S:\" + self.a as String + \" P:\" + value as String
}
}
impl TestTrait for StructB {
fn required(self: Self, value: u8) -> String {
\"B S:\" + self.b as String + \" P:\" + value as String
}
}
fn indirect(stuff: TestTrait, first: u8, second: u8) {
ret_string(stuff.provided(first));
ret_string(stuff.required(second));
}
fn main() {
let a = StructA { a: 111 };
let b = StructB { b: 999 };
indirect(a, 1, 2);
indirect(b, 3, 4);
ret_string(a.provided(5));
ret_string(a.required(6));
ret_string(b.provided(7));
ret_string(b.required(8));
}
");
assert_all(&result, &[
"A S:111 P:1 provided".to_string(),
"A S:111 P:2".to_string(),
"B S:999 P:3 provided".to_string(),
"B S:999 P:4".to_string(),
"A S:111 P:5 provided".to_string(),
"A S:111 P:6".to_string(),
"B S:999 P:7 provided".to_string(),
"B S:999 P:8".to_string(),
]);
}
#[test]
fn primitive_enum() {
let result = run("
enum Simple {
A, B, C
}
fn accept(ty: Simple) {
if ty == Simple::A {
ret_u8(1);
} else if ty == Simple::B {
ret_u8(2);
} else if ty == Simple::C {
ret_u8(3);
}
}
fn main() {
accept(Simple::A);
accept(Simple::B);
accept(Simple::C);
let b = Simple::B;
if b != Simple::B {
ret_u8(101);
} else {
ret_u8(4);
}
}
");
assert_all(&result, &[ 1u8, 2, 3, 4 ]);
}
#[test]
fn primitive_enum_cast() {
let result = run("
enum Simple {
A = 3, B, C
}
fn main() {
let a = Simple::A;
ret_u8(a as u8);
ret_u8(Simple::B as u8);
if a as u8 == 3 {
ret_u8(1)
} else {
ret_u8(0);
}
}
");
assert_all(&result, &[ 3u8, 4, 1 ]);
}
#[test]
fn tempory_access() {
let result = run("
struct Test {
val: u8,
}
fn test(i: u8) -> Test {
Test { val: i }
}
fn main() {
test(3); // test discard drop
ret_u8(test(1).val);
ret_u8(test(2).val);
ret_u8(test(3).val);
}
");
assert_all(&result, &[ 1u8, 2, 3 ]);
}
#[test]
fn temporary_string() {
let result = run("
fn return_new_string(n: i32) -> String {
n as String
}
fn passthrough_string(s: String) -> String {
s
}
fn make_temporary_string() -> String {
\"World\"
}
fn make_materialized_string() -> String {
let result = \"A string\";
result
}
fn main() {
return_new_string(100); // discard drop
let x = return_new_string(200);
ret_string(x);
passthrough_string(\"Hello\"); // discard drop
let y = passthrough_string(\"Hello\");
ret_string(y);
make_temporary_string(); // discard drop
let z = make_temporary_string();
ret_string(z);
make_materialized_string(); // discard drop
let q = make_materialized_string();
ret_string(q);
}
");
assert_all(&result, &[ "200".to_string(), "Hello".to_string(), "World".to_string(), "A string".to_string() ]);
}
#[test]
fn temporary_traitobject() {
let result = run("
struct Inner {
x: u8,
}
struct Outer {
inner: Inner,
}
pub trait Trait {
fn get(self: Self) -> u8;
fn double(self: Self) -> u8 {
self.get() * 2
}
}
impl Trait for Outer {
fn get(self: Self) -> u8 {
self.inner.x
}
}
fn erase(obj: Trait) -> Trait {
obj
}
fn get(obj: Trait) -> u8 {
obj.get()
}
fn main() {
let o = erase(Outer { inner: Inner { x: 123 } });
get(o); // Test discard drop
ret_u8(erase(o).get());
ret_u8(get(o));
ret_u8(erase(o).double());
}
");
assert_all(&result, &[ 123u8, 123, 246 ]);
}