mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 07:17:50 +03:00
add wasm tests
This commit is contained in:
parent
0770bb242e
commit
ff29b19338
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -1345,11 +1345,22 @@ name = "gen_wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"indoc 0.3.6",
|
||||
"libc",
|
||||
"parity-wasm",
|
||||
"pretty_assertions 0.5.1",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_std",
|
||||
"roc_types",
|
||||
"target-lexicon",
|
||||
"tempfile",
|
||||
"wasmer",
|
||||
"wasmer-wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -13,4 +13,16 @@ bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||
parity-wasm = "0.42"
|
||||
|
||||
[dev-dependencies]
|
||||
roc_can = { path = "../can" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_load = { path = "../load" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
roc_module = { path = "../module" }
|
||||
indoc = "0.3.3"
|
||||
pretty_assertions = "0.5.1"
|
||||
libc = "0.2"
|
||||
target-lexicon = "0.12.2"
|
||||
wasmer = "2.0.0"
|
||||
wasmer-wasi = "2.0.0"
|
||||
tempfile = "3.1.0"
|
||||
|
469
compiler/gen_wasm/tests/helpers/eval.rs
Normal file
469
compiler/gen_wasm/tests/helpers/eval.rs
Normal file
@ -0,0 +1,469 @@
|
||||
use roc_can::builtins::builtin_defs_map;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
|
||||
fn promote_expr_to_module(src: &str) -> String {
|
||||
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||
|
||||
for line in src.lines() {
|
||||
// indent the body!
|
||||
buffer.push_str(" ");
|
||||
buffer.push_str(line);
|
||||
buffer.push('\n');
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn helper_wasm<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
src: &str,
|
||||
stdlib: &'a roc_builtins::std::StdLib,
|
||||
_is_gen_test: bool,
|
||||
_ignore_problems: bool,
|
||||
) -> wasmer::Instance {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
let filename = PathBuf::from("Test.roc");
|
||||
let src_dir = Path::new("fake/test/path");
|
||||
|
||||
let module_src;
|
||||
let temp;
|
||||
if src.starts_with("app") {
|
||||
// this is already a module
|
||||
module_src = src;
|
||||
} else {
|
||||
// this is an expression, promote it to a module
|
||||
temp = promote_expr_to_module(src);
|
||||
module_src = &temp;
|
||||
}
|
||||
|
||||
let exposed_types = MutMap::default();
|
||||
let loaded = roc_load::file::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
filename,
|
||||
module_src,
|
||||
stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
8,
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
let loaded = loaded.expect("failed to load module");
|
||||
|
||||
use roc_load::file::MonomorphizedModule;
|
||||
let MonomorphizedModule {
|
||||
procedures: top_procedures,
|
||||
interns,
|
||||
exposed_to_host,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
let mut procedures = MutMap::default();
|
||||
|
||||
for (key, proc) in top_procedures {
|
||||
procedures.insert(key, proc);
|
||||
}
|
||||
|
||||
let exposed_to_host = exposed_to_host.keys().copied().collect::<MutSet<_>>();
|
||||
|
||||
let env = gen_wasm::Env {
|
||||
arena,
|
||||
interns,
|
||||
exposed_to_host,
|
||||
};
|
||||
|
||||
let module_bytes = gen_wasm::build_module(&env, procedures).unwrap();
|
||||
|
||||
// for debugging (e.g. with wasm2wat)
|
||||
if false {
|
||||
use std::io::Write;
|
||||
let mut file = std::fs::File::create("/home/folkertdev/roc/wasm/manual.wasm").unwrap();
|
||||
file.write_all(&module_bytes).unwrap();
|
||||
}
|
||||
|
||||
// now, do wasmer stuff
|
||||
|
||||
use wasmer::{Function, Instance, Module, Store};
|
||||
|
||||
let store = Store::default();
|
||||
// let module = Module::from_file(&store, &test_wasm_path).unwrap();
|
||||
let module = Module::new(&store, &module_bytes).unwrap();
|
||||
|
||||
// First, we create the `WasiEnv`
|
||||
use wasmer_wasi::WasiState;
|
||||
let mut wasi_env = WasiState::new("hello")
|
||||
// .args(&["world"])
|
||||
// .env("KEY", "Value")
|
||||
.finalize()
|
||||
.unwrap();
|
||||
|
||||
// Then, we get the import object related to our WASI
|
||||
// and attach it to the Wasm instance.
|
||||
let mut import_object = wasi_env
|
||||
.import_object(&module)
|
||||
.unwrap_or_else(|_| wasmer::imports!());
|
||||
|
||||
{
|
||||
let mut exts = wasmer::Exports::new();
|
||||
|
||||
let main_function = Function::new_native(&store, fake_wasm_main_function);
|
||||
let ext = wasmer::Extern::Function(main_function);
|
||||
exts.insert("main", ext);
|
||||
|
||||
let main_function = Function::new_native(&store, wasm_roc_panic);
|
||||
let ext = wasmer::Extern::Function(main_function);
|
||||
exts.insert("roc_panic", ext);
|
||||
|
||||
import_object.register("env", exts);
|
||||
}
|
||||
|
||||
Instance::new(&module, &import_object).unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn wasm_roc_panic(address: u32, tag_id: u32) {
|
||||
match tag_id {
|
||||
0 => {
|
||||
let mut string = "";
|
||||
|
||||
MEMORY.with(|f| {
|
||||
let memory = f.borrow().unwrap();
|
||||
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(address);
|
||||
let width = 100;
|
||||
let c_ptr = (ptr.deref(memory, 0, width)).unwrap();
|
||||
|
||||
use libc::c_char;
|
||||
use std::ffi::CStr;
|
||||
let slice = unsafe { CStr::from_ptr(c_ptr as *const _ as *const c_char) };
|
||||
string = slice.to_str().unwrap();
|
||||
});
|
||||
|
||||
panic!("Roc failed with message: {:?}", string)
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
thread_local! {
|
||||
pub static MEMORY: RefCell<Option<&'static wasmer::Memory>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fake_wasm_main_function(_: u32, _: u32) -> u32 {
|
||||
panic!("wasm entered the main function; this should never happen!")
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, ignore_problems: bool) -> Result<T, String>
|
||||
where
|
||||
T: FromWasmMemory,
|
||||
{
|
||||
let arena = bumpalo::Bump::new();
|
||||
|
||||
// NOTE the stdlib must be in the arena; just taking a reference will segfault
|
||||
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
|
||||
|
||||
let is_gen_test = true;
|
||||
let instance =
|
||||
crate::helpers::eval::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems);
|
||||
|
||||
let memory = instance.exports.get_memory("memory").unwrap();
|
||||
|
||||
crate::helpers::eval::MEMORY.with(|f| {
|
||||
*f.borrow_mut() = Some(unsafe { std::mem::transmute(memory) });
|
||||
});
|
||||
|
||||
let test_wrapper = instance.exports.get_function("test_wrapper").unwrap();
|
||||
|
||||
match test_wrapper.call(&[]) {
|
||||
Err(e) => Err(format!("{:?}", e)),
|
||||
Ok(result) => {
|
||||
let address = match result[0] {
|
||||
wasmer::Value::I32(a) => a,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let output = <T as crate::helpers::eval::FromWasmMemory>::decode(
|
||||
memory,
|
||||
// skip the RocCallResult tag id
|
||||
address as u32 + 8,
|
||||
);
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_wasm_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => {
|
||||
match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) {
|
||||
Err(msg) => println!("{:?}", msg),
|
||||
Ok(actual) => {
|
||||
#[allow(clippy::bool_assert_comparison)]
|
||||
assert_eq!($transform(actual), $expected)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty) => {
|
||||
$crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false);
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty) => {{
|
||||
assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
|
||||
}};
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
// Same as above, except with an additional transformation argument.
|
||||
{
|
||||
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn identity<T>(value: T) -> T {
|
||||
value
|
||||
}
|
||||
|
||||
pub trait FromWasmMemory: Sized {
|
||||
const SIZE_OF_WASM: usize;
|
||||
const ALIGN_OF_WASM: usize;
|
||||
const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 {
|
||||
Self::SIZE_OF_WASM
|
||||
} else {
|
||||
Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM))
|
||||
};
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! from_wasm_memory_primitive_decode {
|
||||
($type_name:ident) => {
|
||||
const SIZE_OF_WASM: usize = core::mem::size_of::<$type_name>();
|
||||
const ALIGN_OF_WASM: usize = core::mem::align_of::<$type_name>();
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
let mut output: MaybeUninit<Self> = MaybeUninit::uninit();
|
||||
let width = std::mem::size_of::<Self>();
|
||||
|
||||
let ptr = output.as_mut_ptr();
|
||||
let raw_ptr = ptr as *mut u8;
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) };
|
||||
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset as u32);
|
||||
let foobar = (ptr.deref(memory, 0, width as u32)).unwrap();
|
||||
let wasm_slice = unsafe { std::mem::transmute(foobar) };
|
||||
|
||||
slice.copy_from_slice(wasm_slice);
|
||||
|
||||
unsafe { output.assume_init() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! from_wasm_memory_primitive {
|
||||
($($type_name:ident ,)+) => {
|
||||
$(
|
||||
impl FromWasmMemory for $type_name {
|
||||
from_wasm_memory_primitive_decode!($type_name);
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
from_wasm_memory_primitive!(
|
||||
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder,
|
||||
);
|
||||
|
||||
impl FromWasmMemory for () {
|
||||
const SIZE_OF_WASM: usize = 0;
|
||||
const ALIGN_OF_WASM: usize = 0;
|
||||
|
||||
fn decode(_: &wasmer::Memory, _: u32) -> Self {}
|
||||
}
|
||||
|
||||
impl FromWasmMemory for RocStr {
|
||||
const SIZE_OF_WASM: usize = 8;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let bytes = <u64 as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let length = (bytes >> 32) as u32;
|
||||
let elements = bytes as u32;
|
||||
|
||||
if length == 0 {
|
||||
RocStr::default()
|
||||
} else if (length as i32) < 0 {
|
||||
// this is a small string
|
||||
let last_byte = bytes.to_ne_bytes()[7];
|
||||
let actual_length = (last_byte ^ 0b1000_0000) as usize;
|
||||
|
||||
let slice = &bytes.to_ne_bytes()[..actual_length as usize];
|
||||
RocStr::from_slice(slice)
|
||||
} else {
|
||||
// this is a big string
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(elements);
|
||||
let foobar = (ptr.deref(memory, 0, length)).unwrap();
|
||||
let wasm_slice = unsafe { std::mem::transmute(foobar) };
|
||||
|
||||
RocStr::from_slice(wasm_slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory + Clone> FromWasmMemory for RocList<T> {
|
||||
const SIZE_OF_WASM: usize = 8;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let bytes = <u64 as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let length = (bytes >> 32) as u32;
|
||||
let elements = bytes as u32;
|
||||
|
||||
let mut items = Vec::with_capacity(length as usize);
|
||||
|
||||
for i in 0..length {
|
||||
let item = <T as FromWasmMemory>::decode(
|
||||
memory,
|
||||
elements + i * <T as FromWasmMemory>::SIZE_OF_WASM as u32,
|
||||
);
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
RocList::from_slice(&items)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory + Clone> FromWasmMemory for &'_ [T] {
|
||||
const SIZE_OF_WASM: usize = 8;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let bytes = <u64 as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let length = (bytes >> 32) as u32;
|
||||
let elements = bytes as u32;
|
||||
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(elements);
|
||||
let width = <T as FromWasmMemory>::SIZE_OF_WASM as u32 * length;
|
||||
let foobar = (ptr.deref(memory, 0, width)).unwrap();
|
||||
let wasm_slice =
|
||||
unsafe { std::slice::from_raw_parts(foobar as *const _ as *const _, length as usize) };
|
||||
|
||||
wasm_slice
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory> FromWasmMemory for &'_ T {
|
||||
const SIZE_OF_WASM: usize = 4;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let elements = <u32 as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let actual = <T as FromWasmMemory>::decode(memory, elements);
|
||||
|
||||
let b = Box::new(actual);
|
||||
|
||||
std::boxed::Box::<T>::leak(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory + Clone, const N: usize> FromWasmMemory for [T; N] {
|
||||
const SIZE_OF_WASM: usize = N * T::SIZE_OF_WASM;
|
||||
const ALIGN_OF_WASM: usize = T::ALIGN_OF_WASM;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset);
|
||||
let width = <T as FromWasmMemory>::SIZE_OF_WASM as u32 * N as u32;
|
||||
let foobar = (ptr.deref(memory, 0, width)).unwrap();
|
||||
let wasm_slice: &[T; N] = unsafe { &*(foobar as *const _ as *const [T; N]) };
|
||||
|
||||
wasm_slice.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWasmMemory for usize {
|
||||
const SIZE_OF_WASM: usize = 4;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
<u32 as FromWasmMemory>::decode(memory, offset) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory, U: FromWasmMemory> FromWasmMemory for (T, U) {
|
||||
const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM;
|
||||
const ALIGN_OF_WASM: usize = max2(T::SIZE_OF_WASM, U::SIZE_OF_WASM);
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
assert!(
|
||||
T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM,
|
||||
"this function does not handle alignment"
|
||||
);
|
||||
|
||||
let t = <T as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let u = <U as FromWasmMemory>::decode(memory, offset + T::ACTUAL_WIDTH as u32);
|
||||
|
||||
(t, u)
|
||||
}
|
||||
}
|
||||
|
||||
const fn max2(a: usize, b: usize) -> usize {
|
||||
if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
const fn max3(a: usize, b: usize, c: usize) -> usize {
|
||||
max2(max2(a, b), c)
|
||||
}
|
||||
|
||||
impl<T: FromWasmMemory, U: FromWasmMemory, V: FromWasmMemory> FromWasmMemory for (T, U, V) {
|
||||
const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM + V::SIZE_OF_WASM;
|
||||
const ALIGN_OF_WASM: usize = max3(T::SIZE_OF_WASM, U::SIZE_OF_WASM, V::SIZE_OF_WASM);
|
||||
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
assert!(
|
||||
T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM,
|
||||
"this function does not handle alignment"
|
||||
);
|
||||
|
||||
assert!(
|
||||
U::ALIGN_OF_WASM >= V::ALIGN_OF_WASM,
|
||||
"this function does not handle alignment"
|
||||
);
|
||||
|
||||
let t = <T as FromWasmMemory>::decode(memory, offset);
|
||||
|
||||
let u = <U as FromWasmMemory>::decode(memory, offset + T::ACTUAL_WIDTH as u32);
|
||||
|
||||
let v = <V as FromWasmMemory>::decode(
|
||||
memory,
|
||||
offset + T::ACTUAL_WIDTH as u32 + U::ACTUAL_WIDTH as u32,
|
||||
);
|
||||
|
||||
(t, u, v)
|
||||
}
|
||||
}
|
44
compiler/gen_wasm/tests/helpers/mod.rs
Normal file
44
compiler/gen_wasm/tests/helpers/mod.rs
Normal file
@ -0,0 +1,44 @@
|
||||
extern crate bumpalo;
|
||||
|
||||
#[macro_use]
|
||||
pub mod eval;
|
||||
|
||||
/// Used in the with_larger_debug_stack() function, for tests that otherwise
|
||||
/// run out of stack space in debug builds (but don't in --release builds)
|
||||
#[allow(dead_code)]
|
||||
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
/// Without this, some tests pass in `cargo test --release` but fail without
|
||||
/// the --release flag because they run out of stack space. This increases
|
||||
/// stack size for debug builds only, while leaving the stack space at the default
|
||||
/// amount for release builds.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn with_larger_debug_stack<F>(run_test: F)
|
||||
where
|
||||
F: FnOnce(),
|
||||
F: Send,
|
||||
F: 'static,
|
||||
{
|
||||
std::thread::Builder::new()
|
||||
.stack_size(EXPANDED_STACK_SIZE)
|
||||
.spawn(run_test)
|
||||
.expect("Error while spawning expanded dev stack size thread")
|
||||
.join()
|
||||
.expect("Error while joining expanded dev stack size thread")
|
||||
}
|
||||
|
||||
/// In --release builds, don't increase the stack size. Run the test normally.
|
||||
/// This way, we find out if any of our tests are blowing the stack even after
|
||||
/// optimizations in release builds.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[inline(always)]
|
||||
pub fn with_larger_debug_stack<F>(run_test: F)
|
||||
where
|
||||
F: FnOnce() -> (),
|
||||
F: Send,
|
||||
F: 'static,
|
||||
{
|
||||
run_test()
|
||||
}
|
863
compiler/gen_wasm/tests/wasm_num.rs
Normal file
863
compiler/gen_wasm/tests/wasm_num.rs
Normal file
@ -0,0 +1,863 @@
|
||||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
#[macro_use]
|
||||
extern crate indoc;
|
||||
|
||||
extern crate bumpalo;
|
||||
extern crate libc;
|
||||
|
||||
#[macro_use]
|
||||
mod helpers;
|
||||
|
||||
#[cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
|
||||
mod dev_num {
|
||||
#[test]
|
||||
fn i64_values() {
|
||||
assert_evals_to!("0", 0, i64);
|
||||
assert_evals_to!("-0", 0, i64);
|
||||
assert_evals_to!("-1", -1, i64);
|
||||
assert_evals_to!("1", 1, i64);
|
||||
assert_evals_to!("9_000_000_000_000", 9_000_000_000_000, i64);
|
||||
assert_evals_to!("-9_000_000_000_000", -9_000_000_000_000, i64);
|
||||
assert_evals_to!("0b1010", 0b1010, i64);
|
||||
assert_evals_to!("0o17", 0o17, i64);
|
||||
assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_values() {
|
||||
assert_evals_to!("0.0", 0.0, f64);
|
||||
assert_evals_to!("-0.0", 0.0, f64);
|
||||
assert_evals_to!("1.0", 1.0, f64);
|
||||
assert_evals_to!("-1.0", -1.0, f64);
|
||||
assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64);
|
||||
assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64);
|
||||
assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_add_i64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
1 + 2 + 3
|
||||
"#
|
||||
),
|
||||
6,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_add_f64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
1.1 + 2.4 + 3
|
||||
"#
|
||||
),
|
||||
6.5,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_sub_i64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
1 - 2 - 3
|
||||
"#
|
||||
),
|
||||
-4,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_mul_i64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
2 * 4 * 6
|
||||
"#
|
||||
),
|
||||
48,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i64_force_stack() {
|
||||
// This claims 33 registers. One more than Arm and RISC-V, and many more than x86-64.
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
a = 0
|
||||
b = 1
|
||||
c = 2
|
||||
d = 3
|
||||
e = 4
|
||||
f = 5
|
||||
g = 6
|
||||
h = 7
|
||||
i = 8
|
||||
j = 9
|
||||
k = 10
|
||||
l = 11
|
||||
m = 12
|
||||
n = 13
|
||||
o = 14
|
||||
p = 15
|
||||
q = 16
|
||||
r = 17
|
||||
s = 18
|
||||
t = 19
|
||||
u = 20
|
||||
v = 21
|
||||
w = 22
|
||||
x = 23
|
||||
y = 24
|
||||
z = 25
|
||||
aa = 26
|
||||
ab = 27
|
||||
ac = 28
|
||||
ad = 29
|
||||
ae = 30
|
||||
af = 31
|
||||
ag = 32
|
||||
|
||||
a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag
|
||||
"#
|
||||
),
|
||||
528,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i64_abs() {
|
||||
assert_evals_to!("Num.abs -6", 6, i64);
|
||||
assert_evals_to!("Num.abs 7", 7, i64);
|
||||
assert_evals_to!("Num.abs 0", 0, i64);
|
||||
assert_evals_to!("Num.abs -0", 0, i64);
|
||||
assert_evals_to!("Num.abs -1", 1, i64);
|
||||
assert_evals_to!("Num.abs 1", 1, i64);
|
||||
assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64);
|
||||
assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_int_eq() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
4 == 4
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
3 == 4
|
||||
"#
|
||||
),
|
||||
false,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_basic_fn() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64)
|
||||
always42 = \_ -> 42
|
||||
|
||||
always42 5
|
||||
"#
|
||||
),
|
||||
42,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_wrap_add_nums() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
add2 = \num1, num2 -> num1 + num2
|
||||
|
||||
add2 4 5
|
||||
"#
|
||||
),
|
||||
9,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_wrap_add_nums_force_stack() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9
|
||||
|
||||
add9 1 2 3 4 5 6 7 8 9
|
||||
"#
|
||||
),
|
||||
45,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pow_int() {
|
||||
assert_evals_to!("Num.powInt 2 3", 8, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acos() {
|
||||
assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asin() {
|
||||
assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn atan() {
|
||||
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_if_fn() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
limitedNegate = \num ->
|
||||
x =
|
||||
if num == 1 then
|
||||
-1
|
||||
else if num == -1 then
|
||||
1
|
||||
else
|
||||
num
|
||||
x
|
||||
|
||||
limitedNegate 1
|
||||
"#
|
||||
),
|
||||
-1,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_fib_fn() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
fib = \n ->
|
||||
if n == 0 then
|
||||
0
|
||||
else if n == 1 then
|
||||
1
|
||||
else
|
||||
(fib (n - 1)) + (fib (n - 2))
|
||||
|
||||
fib 10
|
||||
"#
|
||||
),
|
||||
55,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_abs() {
|
||||
assert_evals_to!("Num.abs -4.7", 4.7, f64);
|
||||
assert_evals_to!("Num.abs 5.8", 5.8, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_round() {
|
||||
assert_evals_to!("Num.round 3.6", 4, i64);
|
||||
assert_evals_to!("Num.round 3.4", 3, i64);
|
||||
assert_evals_to!("Num.round 2.5", 3, i64);
|
||||
assert_evals_to!("Num.round -2.3", -2, i64);
|
||||
assert_evals_to!("Num.round -2.5", -3, i64);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn f64_sqrt() {
|
||||
// // FIXME this works with normal types, but fails when checking uniqueness types
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.sqrt 100 is
|
||||
// Ok val -> val
|
||||
// Err _ -> -1
|
||||
// "#
|
||||
// ),
|
||||
// 10.0,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_float_eq() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// 1.0 == 1.0
|
||||
// "#
|
||||
// ),
|
||||
// true,
|
||||
// bool
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_div_f64() {
|
||||
// // FIXME this works with normal types, but fails when checking uniqueness types
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when 48 / 2 is
|
||||
// Ok val -> val
|
||||
// Err _ -> -1
|
||||
// "#
|
||||
// ),
|
||||
// 24.0,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_int_neq() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// 4 != 5
|
||||
// "#
|
||||
// ),
|
||||
// true,
|
||||
// bool
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_wrap_int_neq() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// wrappedNotEq : a, a -> Bool
|
||||
// wrappedNotEq = \num1, num2 ->
|
||||
// num1 != num2
|
||||
|
||||
// wrappedNotEq 2 3
|
||||
// "#
|
||||
// ),
|
||||
// true,
|
||||
// bool
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_sub_f64() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// 1.5 - 2.4 - 3
|
||||
// "#
|
||||
// ),
|
||||
// -3.9,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_div_i64() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when 1000 // 10 is
|
||||
// Ok val -> val
|
||||
// Err _ -> -1
|
||||
// "#
|
||||
// ),
|
||||
// 100,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_div_by_zero_i64() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when 1000 // 0 is
|
||||
// Err DivByZero -> 99
|
||||
// _ -> -24
|
||||
// "#
|
||||
// ),
|
||||
// 99,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_rem_i64() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.rem 8 3 is
|
||||
// Ok val -> val
|
||||
// Err _ -> -1
|
||||
// "#
|
||||
// ),
|
||||
// 2,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_rem_div_by_zero_i64() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.rem 8 0 is
|
||||
// Err DivByZero -> 4
|
||||
// Ok _ -> -23
|
||||
// "#
|
||||
// ),
|
||||
// 4,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_zero_i64() {
|
||||
// assert_evals_to!("Num.isZero 0", true, bool);
|
||||
// assert_evals_to!("Num.isZero 1", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_positive_i64() {
|
||||
// assert_evals_to!("Num.isPositive 0", false, bool);
|
||||
// assert_evals_to!("Num.isPositive 1", true, bool);
|
||||
// assert_evals_to!("Num.isPositive -5", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_negative_i64() {
|
||||
// assert_evals_to!("Num.isNegative 0", false, bool);
|
||||
// assert_evals_to!("Num.isNegative 3", false, bool);
|
||||
// assert_evals_to!("Num.isNegative -2", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_positive_f64() {
|
||||
// assert_evals_to!("Num.isPositive 0.0", false, bool);
|
||||
// assert_evals_to!("Num.isPositive 4.7", true, bool);
|
||||
// assert_evals_to!("Num.isPositive -8.5", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_negative_f64() {
|
||||
// assert_evals_to!("Num.isNegative 0.0", false, bool);
|
||||
// assert_evals_to!("Num.isNegative 9.9", false, bool);
|
||||
// assert_evals_to!("Num.isNegative -4.4", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_zero_f64() {
|
||||
// assert_evals_to!("Num.isZero 0", true, bool);
|
||||
// assert_evals_to!("Num.isZero 0_0", true, bool);
|
||||
// assert_evals_to!("Num.isZero 0.0", true, bool);
|
||||
// assert_evals_to!("Num.isZero 1", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_odd() {
|
||||
// assert_evals_to!("Num.isOdd 4", false, bool);
|
||||
// assert_evals_to!("Num.isOdd 5", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_is_even() {
|
||||
// assert_evals_to!("Num.isEven 6", true, bool);
|
||||
// assert_evals_to!("Num.isEven 7", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn sin() {
|
||||
// assert_evals_to!("Num.sin 0", 0.0, f64);
|
||||
// assert_evals_to!("Num.sin 1.41421356237", 0.9877659459922529, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn cos() {
|
||||
// assert_evals_to!("Num.cos 0", 1.0, f64);
|
||||
// assert_evals_to!("Num.cos 3.14159265359", -1.0, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn tan() {
|
||||
// assert_evals_to!("Num.tan 0", 0.0, f64);
|
||||
// assert_evals_to!("Num.tan 1", 1.557407724654902, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn lt_i64() {
|
||||
// assert_evals_to!("1 < 2", true, bool);
|
||||
// assert_evals_to!("1 < 1", false, bool);
|
||||
// assert_evals_to!("2 < 1", false, bool);
|
||||
// assert_evals_to!("0 < 0", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn lte_i64() {
|
||||
// assert_evals_to!("1 <= 1", true, bool);
|
||||
// assert_evals_to!("2 <= 1", false, bool);
|
||||
// assert_evals_to!("1 <= 2", true, bool);
|
||||
// assert_evals_to!("0 <= 0", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gt_i64() {
|
||||
// assert_evals_to!("2 > 1", true, bool);
|
||||
// assert_evals_to!("2 > 2", false, bool);
|
||||
// assert_evals_to!("1 > 1", false, bool);
|
||||
// assert_evals_to!("0 > 0", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gte_i64() {
|
||||
// assert_evals_to!("1 >= 1", true, bool);
|
||||
// assert_evals_to!("1 >= 2", false, bool);
|
||||
// assert_evals_to!("2 >= 1", true, bool);
|
||||
// assert_evals_to!("0 >= 0", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn lt_f64() {
|
||||
// assert_evals_to!("1.1 < 1.2", true, bool);
|
||||
// assert_evals_to!("1.1 < 1.1", false, bool);
|
||||
// assert_evals_to!("1.2 < 1.1", false, bool);
|
||||
// assert_evals_to!("0.0 < 0.0", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn lte_f64() {
|
||||
// assert_evals_to!("1.1 <= 1.1", true, bool);
|
||||
// assert_evals_to!("1.2 <= 1.1", false, bool);
|
||||
// assert_evals_to!("1.1 <= 1.2", true, bool);
|
||||
// assert_evals_to!("0.0 <= 0.0", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gt_f64() {
|
||||
// assert_evals_to!("2.2 > 1.1", true, bool);
|
||||
// assert_evals_to!("2.2 > 2.2", false, bool);
|
||||
// assert_evals_to!("1.1 > 2.2", false, bool);
|
||||
// assert_evals_to!("0.0 > 0.0", false, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gte_f64() {
|
||||
// assert_evals_to!("1.1 >= 1.1", true, bool);
|
||||
// assert_evals_to!("1.1 >= 1.2", false, bool);
|
||||
// assert_evals_to!("1.2 >= 1.1", true, bool);
|
||||
// assert_evals_to!("0.0 >= 0.0", true, bool);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_order_of_arithmetic_ops() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// 1 + 3 * 7 - 2
|
||||
// "#
|
||||
// ),
|
||||
// 20,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_order_of_arithmetic_ops_complex_float() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// 3 - 48 * 2.0
|
||||
// "#
|
||||
// ),
|
||||
// -93.0,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn if_guard_bind_variable_false() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// wrapper = \{} ->
|
||||
// when 10 is
|
||||
// x if x == 5 -> 0
|
||||
// _ -> 42
|
||||
|
||||
// wrapper {}
|
||||
// "#
|
||||
// ),
|
||||
// 42,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn if_guard_bind_variable_true() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// wrapper = \{} ->
|
||||
// when 10 is
|
||||
// x if x == 10 -> 42
|
||||
// _ -> 0
|
||||
|
||||
// wrapper {}
|
||||
// "#
|
||||
// ),
|
||||
// 42,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn tail_call_elimination() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// sum = \n, accum ->
|
||||
// when n is
|
||||
// 0 -> accum
|
||||
// _ -> sum (n - 1) (n + accum)
|
||||
|
||||
// sum 1_000_000 0
|
||||
// "#
|
||||
// ),
|
||||
// 500000500000,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn int_negate() {
|
||||
// assert_evals_to!("Num.neg 123", -123, i64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn gen_wrap_int_neg() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// wrappedNeg = \num -> -num
|
||||
|
||||
// wrappedNeg 3
|
||||
// "#
|
||||
// ),
|
||||
// -3,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn int_to_float() {
|
||||
// assert_evals_to!("Num.toFloat 0x9", 9.0, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn num_to_float() {
|
||||
// assert_evals_to!("Num.toFloat 9", 9.0, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn float_to_float() {
|
||||
// assert_evals_to!("Num.toFloat 0.5", 0.5, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn int_compare() {
|
||||
// assert_evals_to!("Num.compare 0 1", RocOrder::Lt, RocOrder);
|
||||
// assert_evals_to!("Num.compare 1 1", RocOrder::Eq, RocOrder);
|
||||
// assert_evals_to!("Num.compare 1 0", RocOrder::Gt, RocOrder);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn float_compare() {
|
||||
// assert_evals_to!("Num.compare 0.01 3.14", RocOrder::Lt, RocOrder);
|
||||
// assert_evals_to!("Num.compare 3.14 3.14", RocOrder::Eq, RocOrder);
|
||||
// assert_evals_to!("Num.compare 3.14 0.01", RocOrder::Gt, RocOrder);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn pow() {
|
||||
// assert_evals_to!("Num.pow 2.0 2.0", 4.0, f64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn ceiling() {
|
||||
// assert_evals_to!("Num.ceiling 1.1", 2, i64);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn floor() {
|
||||
// assert_evals_to!("Num.floor 1.9", 1, i64);
|
||||
// }
|
||||
|
||||
// // #[test]
|
||||
// // #[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
||||
// // fn int_overflow() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // 9_223_372_036_854_775_807 + 1
|
||||
// // "#
|
||||
// // ),
|
||||
// // 0,
|
||||
// // i64
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// #[test]
|
||||
// fn int_add_checked() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.addChecked 1 2 is
|
||||
// Ok v -> v
|
||||
// _ -> -1
|
||||
// "#
|
||||
// ),
|
||||
// 3,
|
||||
// i64
|
||||
// );
|
||||
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.addChecked 9_223_372_036_854_775_807 1 is
|
||||
// Err Overflow -> -1
|
||||
// Ok v -> v
|
||||
// "#
|
||||
// ),
|
||||
// -1,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn int_add_wrap() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Num.addWrap 9_223_372_036_854_775_807 1
|
||||
// "#
|
||||
// ),
|
||||
// std::i64::MIN,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn float_add_checked_pass() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.addChecked 1.0 0.0 is
|
||||
// Ok v -> v
|
||||
// Err Overflow -> -1.0
|
||||
// "#
|
||||
// ),
|
||||
// 1.0,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn float_add_checked_fail() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when Num.addChecked 1.7976931348623157e308 1.7976931348623157e308 is
|
||||
// Err Overflow -> -1
|
||||
// Ok v -> v
|
||||
// "#
|
||||
// ),
|
||||
// -1.0,
|
||||
// f64
|
||||
// );
|
||||
// }
|
||||
|
||||
// // #[test]
|
||||
// // #[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)]
|
||||
// // fn float_overflow() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // 1.7976931348623157e308 + 1.7976931348623157e308
|
||||
// // "#
|
||||
// // ),
|
||||
// // 0.0,
|
||||
// // f64
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// #[test]
|
||||
// fn max_i128() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Num.maxI128
|
||||
// "#
|
||||
// ),
|
||||
// i128::MAX,
|
||||
// i128
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn num_max_int() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Num.maxInt
|
||||
// "#
|
||||
// ),
|
||||
// i64::MAX,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn num_min_int() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Num.minInt
|
||||
// "#
|
||||
// ),
|
||||
// i64::MIN,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
}
|
937
compiler/gen_wasm/tests/wasm_records.rs
Normal file
937
compiler/gen_wasm/tests/wasm_records.rs
Normal file
@ -0,0 +1,937 @@
|
||||
#[macro_use]
|
||||
extern crate indoc;
|
||||
|
||||
#[macro_use]
|
||||
mod helpers;
|
||||
|
||||
#[cfg(all(test, target_os = "linux", any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
|
||||
mod dev_records {
|
||||
#[test]
|
||||
fn basic_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ y: 17, x: 15, z: 19 }.x
|
||||
"#
|
||||
),
|
||||
15,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: 17, z: 19 }.y
|
||||
"#
|
||||
),
|
||||
17,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: 17, z: 19 }.z
|
||||
"#
|
||||
),
|
||||
19,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x
|
||||
"#
|
||||
),
|
||||
15,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a
|
||||
"#
|
||||
),
|
||||
12,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b
|
||||
"#
|
||||
),
|
||||
15,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c
|
||||
"#
|
||||
),
|
||||
2,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z
|
||||
"#
|
||||
),
|
||||
19,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { y: 17.2, x: 15.1, z: 19.3 }
|
||||
|
||||
rec.x
|
||||
"#
|
||||
),
|
||||
15.1,
|
||||
f64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { y: 17.2, x: 15.1, z: 19.3 }
|
||||
|
||||
rec.y
|
||||
"#
|
||||
),
|
||||
17.2,
|
||||
f64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { y: 17.2, x: 15.1, z: 19.3 }
|
||||
|
||||
rec.z
|
||||
"#
|
||||
),
|
||||
19.3,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn fn_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// getRec = \x -> { y: 17, x, z: 19 }
|
||||
|
||||
// (getRec 15).x
|
||||
// "#
|
||||
// ),
|
||||
// 15,
|
||||
// i64
|
||||
// );
|
||||
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// rec = { x: 15, y: 17, z: 19 }
|
||||
|
||||
// rec.y
|
||||
// "#
|
||||
// ),
|
||||
// 17,
|
||||
// i64
|
||||
// );
|
||||
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// rec = { x: 15, y: 17, z: 19 }
|
||||
|
||||
// rec.z
|
||||
// "#
|
||||
// ),
|
||||
// 19,
|
||||
// i64
|
||||
// );
|
||||
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// rec = { x: 15, y: 17, z: 19 }
|
||||
|
||||
// rec.z + rec.x
|
||||
// "#
|
||||
// ),
|
||||
// 34,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn def_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { y: 17, x: 15, z: 19 }
|
||||
|
||||
rec.x
|
||||
"#
|
||||
),
|
||||
15,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { x: 15, y: 17, z: 19 }
|
||||
|
||||
rec.y
|
||||
"#
|
||||
),
|
||||
17,
|
||||
i64
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { x: 15, y: 17, z: 19 }
|
||||
|
||||
rec.z
|
||||
"#
|
||||
),
|
||||
19,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_on_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when { x: 0x2 } is
|
||||
{ x } -> x + 3
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_record_with_guard_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when { x: 0x2, y: 3.14 } is
|
||||
{ x: var } -> var + 3
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_with_record_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x } = { x: 0x2, y: 3.14 }
|
||||
|
||||
x
|
||||
"#
|
||||
),
|
||||
2,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_guard_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when { x: 0x2, y: 3.14 } is
|
||||
{ x: 0x4 } -> 5
|
||||
{ x } -> x + 3
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn twice_record_access() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x = {a: 0x2, b: 0x3 }
|
||||
|
||||
x.a + x.b
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn empty_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
v = {}
|
||||
|
||||
v
|
||||
"#
|
||||
),
|
||||
(),
|
||||
()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i64_record1_literal() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
{ x: 3 }
|
||||
"#
|
||||
),
|
||||
3,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn i64_record2_literal() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { x: 3, y: 5 }
|
||||
// "#
|
||||
// ),
|
||||
// (3, 5),
|
||||
// (i64, i64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// // #[test]
|
||||
// // fn i64_record3_literal() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // { x: 3, y: 5, z: 17 }
|
||||
// // "#
|
||||
// // ),
|
||||
// // (3, 5, 17),
|
||||
// // (i64, i64, i64)
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// #[test]
|
||||
// fn f64_record2_literal() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { x: 3.1, y: 5.1 }
|
||||
// "#
|
||||
// ),
|
||||
// (3.1, 5.1),
|
||||
// (f64, f64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// // #[test]
|
||||
// // fn f64_record3_literal() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // { x: 3.1, y: 5.1, z: 17.1 }
|
||||
// // "#
|
||||
// // ),
|
||||
// // (3.1, 5.1, 17.1),
|
||||
// // (f64, f64, f64)
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// // #[test]
|
||||
// // fn bool_record4_literal() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // record : { a : Bool, b : Bool, c : Bool, d : Bool }
|
||||
// // record = { a: True, b: True, c : True, d : Bool }
|
||||
|
||||
// // record
|
||||
// // "#
|
||||
// // ),
|
||||
// // (true, false, false, true),
|
||||
// // (bool, bool, bool, bool)
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// #[test]
|
||||
// fn i64_record1_literal() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3 }
|
||||
// "#
|
||||
// ),
|
||||
// 3,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// // #[test]
|
||||
// // fn i64_record9_literal() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 }
|
||||
// // "#
|
||||
// // ),
|
||||
// // (3, 5, 17, 1, 9, 12, 13, 14, 15),
|
||||
// // (i64, i64, i64, i64, i64, i64, i64, i64, i64)
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// // #[test]
|
||||
// // fn f64_record3_literal() {
|
||||
// // assert_evals_to!(
|
||||
// // indoc!(
|
||||
// // r#"
|
||||
// // { x: 3.1, y: 5.1, z: 17.1 }
|
||||
// // "#
|
||||
// // ),
|
||||
// // (3.1, 5.1, 17.1),
|
||||
// // (f64, f64, f64)
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// #[test]
|
||||
// fn bool_literal() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// x : Bool
|
||||
// x = True
|
||||
|
||||
// x
|
||||
// "#
|
||||
// ),
|
||||
// true,
|
||||
// bool
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_when_use_default() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// app "test" provides [ main ] to "./platform"
|
||||
|
||||
// f = \r ->
|
||||
// when r is
|
||||
// { x: Blue, y ? 3 } -> y
|
||||
// { x: Red, y ? 5 } -> y
|
||||
|
||||
// main =
|
||||
// a = f { x: Blue, y: 7 }
|
||||
// b = f { x: Blue }
|
||||
// c = f { x: Red, y: 11 }
|
||||
// d = f { x: Red }
|
||||
|
||||
// a * b * c * d
|
||||
// "#
|
||||
// ),
|
||||
// 3 * 5 * 7 * 11,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_when_use_default_nested() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \r ->
|
||||
// when r is
|
||||
// { x: Blue, y ? 3 } -> y
|
||||
// { x: Red, y ? 5 } -> y
|
||||
|
||||
// a = f { x: Blue, y: 7 }
|
||||
// b = f { x: Blue }
|
||||
// c = f { x: Red, y: 11 }
|
||||
// d = f { x: Red }
|
||||
|
||||
// a * b * c * d
|
||||
// "#
|
||||
// ),
|
||||
// 3 * 5 * 7 * 11,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_when_no_use_default() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// app "test" provides [ main ] to "./platform"
|
||||
|
||||
// f = \r ->
|
||||
// { x ? 10, y } = r
|
||||
// x + y
|
||||
|
||||
// main =
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_when_no_use_default_nested() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \r ->
|
||||
// { x ? 10, y } = r
|
||||
// x + y
|
||||
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_let_use_default() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// app "test" provides [ main ] to "./platform"
|
||||
|
||||
// f = \r ->
|
||||
// { x ? 10, y } = r
|
||||
// x + y
|
||||
|
||||
// main =
|
||||
// f { y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 19,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_let_no_use_default() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// app "test" provides [ main ] to "./platform"
|
||||
|
||||
// f = \r ->
|
||||
// { x ? 10, y } = r
|
||||
// x + y
|
||||
|
||||
// main =
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_let_no_use_default_nested() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \r ->
|
||||
// { x ? 10, y } = r
|
||||
// x + y
|
||||
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_function_use_default() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \{ x ? 10, y } -> x + y
|
||||
|
||||
// f { y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 19,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[ignore]
|
||||
// fn optional_field_function_no_use_default() {
|
||||
// // blocked on https://github.com/rtfeldman/roc/issues/786
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// app "test" provides [ main ] to "./platform"
|
||||
|
||||
// f = \{ x ? 10, y } -> x + y
|
||||
|
||||
// main =
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[ignore]
|
||||
// fn optional_field_function_no_use_default_nested() {
|
||||
// // blocked on https://github.com/rtfeldman/roc/issues/786
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \{ x ? 10, y } -> x + y
|
||||
|
||||
// f { x: 4, y: 9 }
|
||||
// "#
|
||||
// ),
|
||||
// 13,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_singleton_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when { x : 4 } is
|
||||
// { x ? 3 } -> x
|
||||
// "#
|
||||
// ),
|
||||
// 4,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional_field_empty_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// when { } is
|
||||
// { x ? 3 } -> x
|
||||
// "#
|
||||
// ),
|
||||
// 3,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_2() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { x: 3, y: 5 }
|
||||
// "#
|
||||
// ),
|
||||
// [3, 5],
|
||||
// [i64; 2]
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_3() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { x: 3, y: 5, z: 4 }
|
||||
// "#
|
||||
// ),
|
||||
// (3, 5, 4),
|
||||
// (i64, i64, i64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_4() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3, b: 5, c: 4, d: 2 }
|
||||
// "#
|
||||
// ),
|
||||
// [3, 5, 4, 2],
|
||||
// [i64; 4]
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_5() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3, b: 5, c: 4, d: 2, e: 1 }
|
||||
// "#
|
||||
// ),
|
||||
// [3, 5, 4, 2, 1],
|
||||
// [i64; 5]
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_6() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
|
||||
// "#
|
||||
// ),
|
||||
// [3, 5, 4, 2, 1, 7],
|
||||
// [i64; 6]
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_7() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
|
||||
// "#
|
||||
// ),
|
||||
// [3, 5, 4, 2, 1, 7, 8],
|
||||
// [i64; 7]
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_float_int() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 3.14, b: 0x1 }
|
||||
// "#
|
||||
// ),
|
||||
// (3.14, 0x1),
|
||||
// (f64, i64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_int_float() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 0x1, b: 3.14 }
|
||||
// "#
|
||||
// ),
|
||||
// (0x1, 3.14),
|
||||
// (i64, f64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_float_float() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 6.28, b: 3.14 }
|
||||
// "#
|
||||
// ),
|
||||
// (6.28, 3.14),
|
||||
// (f64, f64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_record_float_float_float() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { a: 6.28, b: 3.14, c: 0.1 }
|
||||
// "#
|
||||
// ),
|
||||
// (6.28, 3.14, 0.1),
|
||||
// (f64, f64, f64)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn return_nested_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// { flag: 0x0, payload: { a: 6.28, b: 3.14, c: 0.1 } }
|
||||
// "#
|
||||
// ),
|
||||
// (0x0, (6.28, 3.14, 0.1)),
|
||||
// (i64, (f64, f64, f64))
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn accessor() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// .foo { foo: 4 } + .foo { bar: 6.28, foo: 3 }
|
||||
// "#
|
||||
// ),
|
||||
// 7,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn accessor_single_element_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// .foo { foo: 4 }
|
||||
// "#
|
||||
// ),
|
||||
// 4,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn update_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// rec = { foo: 42, bar: 6 }
|
||||
|
||||
// { rec & foo: rec.foo + 1 }
|
||||
// "#
|
||||
// ),
|
||||
// (6, 43),
|
||||
// (i64, i64)
|
||||
// );
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn update_single_element_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
rec = { foo: 42}
|
||||
|
||||
{ rec & foo: rec.foo + 1 }
|
||||
"#
|
||||
),
|
||||
43,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn booleans_in_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!("{ x: 1 == 1, y: 1 == 1 }"),
|
||||
// (true, true),
|
||||
// (bool, bool)
|
||||
// );
|
||||
// assert_evals_to!(
|
||||
// indoc!("{ x: 1 != 1, y: 1 == 1 }"),
|
||||
// (false, true),
|
||||
// (bool, bool)
|
||||
// );
|
||||
// assert_evals_to!(
|
||||
// indoc!("{ x: 1 == 1, y: 1 != 1 }"),
|
||||
// (true, false),
|
||||
// (bool, bool)
|
||||
// );
|
||||
// assert_evals_to!(
|
||||
// indoc!("{ x: 1 != 1, y: 1 != 1 }"),
|
||||
// (false, false),
|
||||
// (bool, bool)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn alignment_in_record() {
|
||||
// assert_evals_to!(
|
||||
// indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"),
|
||||
// (32i64, true, 2u8),
|
||||
// (i64, bool, u8)
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn blue_and_present() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \r ->
|
||||
// when r is
|
||||
// { x: Blue, y ? 3 } -> y
|
||||
// { x: Red, y ? 5 } -> y
|
||||
|
||||
// f { x: Blue, y: 7 }
|
||||
// "#
|
||||
// ),
|
||||
// 7,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn blue_and_absent() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// f = \r ->
|
||||
// when r is
|
||||
// { x: Blue, y ? 3 } -> y
|
||||
// { x: Red, y ? 5 } -> y
|
||||
|
||||
// f { x: Blue }
|
||||
// "#
|
||||
// ),
|
||||
// 3,
|
||||
// i64
|
||||
// );
|
||||
// }
|
||||
}
|
Loading…
Reference in New Issue
Block a user