mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Merge branch 'trunk' of github.com:rtfeldman/roc into wasm_module_builder
This commit is contained in:
commit
6fca1caee5
38 changed files with 3040 additions and 2427 deletions
233
compiler/test_wasm/src/helpers/eval.rs
Normal file
233
compiler/test_wasm/src/helpers/eval.rs
Normal file
|
@ -0,0 +1,233 @@
|
|||
use std::cell::Cell;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use roc_can::builtins::builtin_defs_map;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_gen_wasm::combine_and_serialize;
|
||||
// use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
||||
use roc_gen_wasm::from_wasm32_memory::FromWasm32Memory;
|
||||
|
||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||
|
||||
std::thread_local! {
|
||||
static TEST_COUNTER: Cell<u32> = Cell::new(0);
|
||||
}
|
||||
|
||||
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, T: Wasm32TestResult>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
src: &str,
|
||||
stdlib: &'a roc_builtins::std::StdLib,
|
||||
_result_type_dummy: &T,
|
||||
) -> 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,
|
||||
interns,
|
||||
exposed_to_host,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
// You can comment and uncomment this block out to get more useful information
|
||||
// while you're working on the wasm backend!
|
||||
// {
|
||||
// println!("=========== Procedures ==========");
|
||||
// println!("{:?}", procedures);
|
||||
// println!("=================================\n");
|
||||
|
||||
// println!("=========== Interns ==========");
|
||||
// println!("{:?}", interns);
|
||||
// println!("=================================\n");
|
||||
|
||||
// println!("=========== Exposed ==========");
|
||||
// println!("{:?}", exposed_to_host);
|
||||
// println!("=================================\n");
|
||||
// }
|
||||
|
||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
let main_fn_symbol = loaded.entry_point.symbol;
|
||||
let main_fn_index = procedures
|
||||
.keys()
|
||||
.position(|(s, _)| *s == main_fn_symbol)
|
||||
.unwrap();
|
||||
|
||||
let exposed_to_host = exposed_to_host.keys().copied().collect::<MutSet<_>>();
|
||||
|
||||
let env = roc_gen_wasm::Env {
|
||||
arena,
|
||||
interns,
|
||||
exposed_to_host,
|
||||
};
|
||||
|
||||
let (mut parity_builder, mut wasm_module) =
|
||||
roc_gen_wasm::build_module_help(&env, procedures).unwrap();
|
||||
|
||||
T::insert_test_wrapper(
|
||||
arena,
|
||||
&mut parity_builder,
|
||||
&mut wasm_module,
|
||||
TEST_WRAPPER_NAME,
|
||||
main_fn_index as u32,
|
||||
);
|
||||
|
||||
let mut module_bytes = std::vec::Vec::with_capacity(4096);
|
||||
combine_and_serialize(&mut module_bytes, parity_builder, &mut wasm_module);
|
||||
|
||||
// for debugging (e.g. with wasm2wat or wasm-objdump)
|
||||
if true {
|
||||
use std::io::Write;
|
||||
|
||||
let mut hash_state = DefaultHasher::new();
|
||||
src.hash(&mut hash_state);
|
||||
let src_hash = hash_state.finish();
|
||||
|
||||
// Filename contains a hash of the Roc test source code. Helpful when comparing across commits.
|
||||
let dir = "/tmp/roc/compiler/gen_wasm/output";
|
||||
std::fs::create_dir_all(dir).unwrap();
|
||||
let path = format!("{}/test-{:016x}.wasm", dir, src_hash);
|
||||
|
||||
// Print out filename (appears just after test name)
|
||||
println!("dumping file {:?}", path);
|
||||
|
||||
match std::fs::File::create(path) {
|
||||
Err(e) => eprintln!("Problem creating wasm debug file: {:?}", e),
|
||||
Ok(mut file) => {
|
||||
file.write_all(&module_bytes).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now, do wasmer stuff
|
||||
|
||||
use wasmer::{Instance, Module, Store};
|
||||
|
||||
let store = Store::default();
|
||||
// let module = Module::from_file(&store, &test_wasm_path).unwrap();
|
||||
let wasmer_module = Module::from_binary(&store, &module_bytes).unwrap();
|
||||
|
||||
// First, we create the `WasiEnv`
|
||||
use wasmer_wasi::WasiState;
|
||||
let mut wasi_env = WasiState::new("hello").finalize().unwrap();
|
||||
|
||||
// Then, we get the import object related to our WASI
|
||||
// and attach it to the Wasm instance.
|
||||
let import_object = wasi_env
|
||||
.import_object(&wasmer_module)
|
||||
.unwrap_or_else(|_| wasmer::imports!());
|
||||
|
||||
Instance::new(&wasmer_module, &import_object).unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, expected: T) -> Result<T, String>
|
||||
where
|
||||
T: FromWasm32Memory + Wasm32TestResult,
|
||||
{
|
||||
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 instance = crate::helpers::eval::helper_wasm(&arena, src, stdlib, &expected);
|
||||
|
||||
let memory = instance.exports.get_memory("memory").unwrap();
|
||||
|
||||
let test_wrapper = instance.exports.get_function(TEST_WRAPPER_NAME).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 FromWasm32Memory>::decode(memory, address as u32);
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_wasm_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $expected) {
|
||||
Err(msg) => panic!("{:?}", msg),
|
||||
Ok(actual) => {
|
||||
assert_eq!($transform(actual), $expected)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty) => {
|
||||
$crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform);
|
||||
};
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn identity<T>(value: T) -> T {
|
||||
value
|
||||
}
|
43
compiler/test_wasm/src/helpers/mod.rs
Normal file
43
compiler/test_wasm/src/helpers/mod.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
#[macro_use]
|
||||
pub mod eval;
|
||||
pub mod wasm32_test_result;
|
||||
|
||||
/// 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()
|
||||
}
|
270
compiler/test_wasm/src/helpers/wasm32_test_result.rs
Normal file
270
compiler/test_wasm/src/helpers/wasm32_test_result.rs
Normal file
|
@ -0,0 +1,270 @@
|
|||
use parity_wasm::builder;
|
||||
|
||||
use roc_gen_wasm::code_builder::{Align, CodeBuilder, ValueType};
|
||||
use roc_gen_wasm::from_wasm32_memory::FromWasm32Memory;
|
||||
use roc_gen_wasm::module_builder::{Export, ExportType, WasmModule};
|
||||
use roc_gen_wasm::LocalId;
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
|
||||
pub trait Wasm32TestResult {
|
||||
fn insert_test_wrapper<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
module_builder: &mut builder::ModuleBuilder,
|
||||
wasm_module: &mut WasmModule<'a>,
|
||||
wrapper_name: &str,
|
||||
main_function_index: u32,
|
||||
) {
|
||||
let signature = builder::signature()
|
||||
.with_result(parity_wasm::elements::ValueType::I32)
|
||||
.build_sig();
|
||||
|
||||
// parity-wasm FunctionDefinition with no instructions
|
||||
let empty_fn_def = builder::function().with_signature(signature).build();
|
||||
let location = module_builder.push_function(empty_fn_def);
|
||||
|
||||
wasm_module.export.entries.push(Export {
|
||||
name: wrapper_name.to_string(),
|
||||
ty: ExportType::Func,
|
||||
index: location.body,
|
||||
});
|
||||
|
||||
let mut code_builder = CodeBuilder::new(arena);
|
||||
Self::build_wrapper_body(&mut code_builder, main_function_index);
|
||||
wasm_module.code.code_builders.push(code_builder);
|
||||
}
|
||||
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32);
|
||||
}
|
||||
|
||||
macro_rules! build_wrapper_body_primitive {
|
||||
($store_instruction: ident, $align: expr) => {
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
let frame_pointer_id = LocalId(0);
|
||||
let frame_pointer = Some(frame_pointer_id);
|
||||
let local_types = &[ValueType::I32];
|
||||
let frame_size = 8;
|
||||
|
||||
code_builder.get_local(frame_pointer_id);
|
||||
// Raw "call" instruction. Don't bother with symbol & relocation since we're not going to link.
|
||||
code_builder.inst_imm32(roc_gen_wasm::opcodes::CALL, 0, true, main_function_index);
|
||||
code_builder.$store_instruction($align, 0);
|
||||
code_builder.get_local(frame_pointer_id);
|
||||
|
||||
code_builder.finalize(local_types, frame_size, frame_pointer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wasm_test_result_primitive {
|
||||
($type_name: ident, $store_instruction: ident, $align: expr) => {
|
||||
impl Wasm32TestResult for $type_name {
|
||||
build_wrapper_body_primitive!($store_instruction, $align);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn build_wrapper_body_stack_memory(
|
||||
code_builder: &mut CodeBuilder,
|
||||
main_function_index: u32,
|
||||
size: usize,
|
||||
) {
|
||||
let local_id = LocalId(0);
|
||||
let local_types = &[ValueType::I32];
|
||||
let frame_pointer = Some(local_id);
|
||||
|
||||
code_builder.get_local(local_id);
|
||||
// Raw "call" instruction. Don't bother with symbol & relocation since we're not going to link.
|
||||
code_builder.inst_imm32(roc_gen_wasm::opcodes::CALL, 0, true, main_function_index);
|
||||
code_builder.get_local(local_id);
|
||||
code_builder.finalize(local_types, size as i32, frame_pointer);
|
||||
}
|
||||
|
||||
macro_rules! wasm_test_result_stack_memory {
|
||||
($type_name: ident) => {
|
||||
impl Wasm32TestResult for $type_name {
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
$type_name::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
wasm_test_result_primitive!(bool, i32_store8, Align::Bytes1);
|
||||
wasm_test_result_primitive!(RocOrder, i32_store8, Align::Bytes1);
|
||||
|
||||
wasm_test_result_primitive!(u8, i32_store8, Align::Bytes1);
|
||||
wasm_test_result_primitive!(i8, i32_store8, Align::Bytes1);
|
||||
wasm_test_result_primitive!(u16, i32_store16, Align::Bytes2);
|
||||
wasm_test_result_primitive!(i16, i32_store16, Align::Bytes2);
|
||||
wasm_test_result_primitive!(u32, i32_store, Align::Bytes4);
|
||||
wasm_test_result_primitive!(i32, i32_store, Align::Bytes4);
|
||||
wasm_test_result_primitive!(u64, i64_store, Align::Bytes8);
|
||||
wasm_test_result_primitive!(i64, i64_store, Align::Bytes8);
|
||||
|
||||
wasm_test_result_primitive!(f32, f32_store, Align::Bytes8);
|
||||
wasm_test_result_primitive!(f64, f64_store, Align::Bytes8);
|
||||
|
||||
wasm_test_result_stack_memory!(u128);
|
||||
wasm_test_result_stack_memory!(i128);
|
||||
wasm_test_result_stack_memory!(RocDec);
|
||||
wasm_test_result_stack_memory!(RocStr);
|
||||
|
||||
impl<T: Wasm32TestResult> Wasm32TestResult for RocList<T> {
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(code_builder, main_function_index, 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Wasm32TestResult> Wasm32TestResult for &'_ T {
|
||||
build_wrapper_body_primitive!(i32_store, Align::Bytes4);
|
||||
}
|
||||
|
||||
impl<T, const N: usize> Wasm32TestResult for [T; N]
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(code_builder, main_function_index, N * T::ACTUAL_WIDTH)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Wasm32TestResult for (T, U)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH + U::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V> Wasm32TestResult for (T, U, V)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH + U::ACTUAL_WIDTH + V::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V, W> Wasm32TestResult for (T, U, V, W)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
W: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH + U::ACTUAL_WIDTH + V::ACTUAL_WIDTH + W::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V, W, X> Wasm32TestResult for (T, U, V, W, X)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
W: Wasm32TestResult + FromWasm32Memory,
|
||||
X: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH + U::ACTUAL_WIDTH + V::ACTUAL_WIDTH + W::ACTUAL_WIDTH + X::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V, W, X, Y> Wasm32TestResult for (T, U, V, W, X, Y)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
W: Wasm32TestResult + FromWasm32Memory,
|
||||
X: Wasm32TestResult + FromWasm32Memory,
|
||||
Y: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH
|
||||
+ U::ACTUAL_WIDTH
|
||||
+ V::ACTUAL_WIDTH
|
||||
+ W::ACTUAL_WIDTH
|
||||
+ X::ACTUAL_WIDTH
|
||||
+ Y::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V, W, X, Y, Z> Wasm32TestResult for (T, U, V, W, X, Y, Z)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
W: Wasm32TestResult + FromWasm32Memory,
|
||||
X: Wasm32TestResult + FromWasm32Memory,
|
||||
Y: Wasm32TestResult + FromWasm32Memory,
|
||||
Z: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH
|
||||
+ U::ACTUAL_WIDTH
|
||||
+ V::ACTUAL_WIDTH
|
||||
+ W::ACTUAL_WIDTH
|
||||
+ X::ACTUAL_WIDTH
|
||||
+ Y::ACTUAL_WIDTH
|
||||
+ Z::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, V, W, X, Y, Z, A> Wasm32TestResult for (T, U, V, W, X, Y, Z, A)
|
||||
where
|
||||
T: Wasm32TestResult + FromWasm32Memory,
|
||||
U: Wasm32TestResult + FromWasm32Memory,
|
||||
V: Wasm32TestResult + FromWasm32Memory,
|
||||
W: Wasm32TestResult + FromWasm32Memory,
|
||||
X: Wasm32TestResult + FromWasm32Memory,
|
||||
Y: Wasm32TestResult + FromWasm32Memory,
|
||||
Z: Wasm32TestResult + FromWasm32Memory,
|
||||
A: Wasm32TestResult + FromWasm32Memory,
|
||||
{
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
T::ACTUAL_WIDTH
|
||||
+ U::ACTUAL_WIDTH
|
||||
+ V::ACTUAL_WIDTH
|
||||
+ W::ACTUAL_WIDTH
|
||||
+ X::ACTUAL_WIDTH
|
||||
+ Y::ACTUAL_WIDTH
|
||||
+ Z::ACTUAL_WIDTH
|
||||
+ A::ACTUAL_WIDTH,
|
||||
)
|
||||
}
|
||||
}
|
3
compiler/test_wasm/src/lib.rs
Normal file
3
compiler/test_wasm/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
mod helpers;
|
||||
pub mod wasm_num;
|
||||
pub mod wasm_records;
|
1052
compiler/test_wasm/src/wasm_num.rs
Normal file
1052
compiler/test_wasm/src/wasm_num.rs
Normal file
File diff suppressed because it is too large
Load diff
911
compiler/test_wasm/src/wasm_records.rs
Normal file
911
compiler/test_wasm/src/wasm_records.rs
Normal file
|
@ -0,0 +1,911 @@
|
|||
#![cfg(all(test, target_os = "linux", any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
|
||||
use crate::assert_evals_to;
|
||||
use indoc::indoc;
|
||||
|
||||
// #[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: False, c : False, d : True }
|
||||
|
||||
record
|
||||
"#
|
||||
),
|
||||
[true, false, false, true],
|
||||
[bool; 4]
|
||||
);
|
||||
}
|
||||
|
||||
#[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; 9]
|
||||
);
|
||||
}
|
||||
|
||||
#[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_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 stack_memory_return_from_branch() {
|
||||
// stack memory pointer should end up in the right place after returning from a branch
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
stackMemoryJunk = { x: 999, y: 111 }
|
||||
if True then
|
||||
{ x: 123, y: 321 }
|
||||
else
|
||||
stackMemoryJunk
|
||||
"#
|
||||
),
|
||||
(123, 321),
|
||||
(i64, i64)
|
||||
);
|
||||
}
|
||||
|
||||
// #[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…
Add table
Add a link
Reference in a new issue