mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Merge branch 'trunk' into decision-tree-remove-clone
This commit is contained in:
commit
f49bd04e68
21 changed files with 463 additions and 491 deletions
|
@ -899,42 +899,6 @@ pub fn listSublist(
|
|||
return RocList.empty();
|
||||
}
|
||||
|
||||
pub fn listDrop(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
drop_count: usize,
|
||||
dec: Dec,
|
||||
) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
const keep_count = size - drop_count;
|
||||
|
||||
var i: usize = 0;
|
||||
const iterations = std.math.min(drop_count, size);
|
||||
|
||||
while (i < iterations) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
if (drop_count >= size) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
const output = RocList.allocate(alignment, keep_count, element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
@memcpy(target_ptr, source_ptr + drop_count * element_width, keep_count * element_width);
|
||||
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
|
||||
return output;
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listDropAt(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
|
|
|
@ -46,7 +46,6 @@ comptime {
|
|||
exportListFn(list.listSortWith, "sort_with");
|
||||
exportListFn(list.listConcat, "concat");
|
||||
exportListFn(list.listSublist, "sublist");
|
||||
exportListFn(list.listDrop, "drop");
|
||||
exportListFn(list.listDropAt, "drop_at");
|
||||
exportListFn(list.listSet, "set");
|
||||
exportListFn(list.listSetInPlace, "set_in_place");
|
||||
|
|
|
@ -185,7 +185,6 @@ pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
|||
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
|
||||
pub const LIST_DROP: &str = "roc_builtins.list.drop";
|
||||
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
|
||||
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
||||
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
||||
|
|
|
@ -2150,20 +2150,33 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
/// List.drop : List elem, Nat -> List elem
|
||||
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
let index_var = var_store.fresh();
|
||||
let len_var = var_store.fresh();
|
||||
|
||||
let get_list_len = RunLowLevel {
|
||||
op: LowLevel::ListLen,
|
||||
args: vec![(list_var, Var(Symbol::ARG_1))],
|
||||
ret_var: len_var,
|
||||
};
|
||||
|
||||
let get_len = RunLowLevel {
|
||||
op: LowLevel::NumSubWrap,
|
||||
args: vec![(len_var, get_list_len), (len_var, Var(Symbol::ARG_2))],
|
||||
ret_var: len_var,
|
||||
};
|
||||
|
||||
let body = RunLowLevel {
|
||||
op: LowLevel::ListDrop,
|
||||
op: LowLevel::ListSublist,
|
||||
args: vec![
|
||||
(list_var, Var(Symbol::ARG_1)),
|
||||
(index_var, Var(Symbol::ARG_2)),
|
||||
(len_var, Var(Symbol::ARG_2)),
|
||||
(len_var, get_len),
|
||||
],
|
||||
ret_var: list_var,
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(list_var, Symbol::ARG_1), (index_var, Symbol::ARG_2)],
|
||||
vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
list_var,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::spaces::{fmt_spaces, INDENT};
|
||||
use bumpalo::collections::{String, Vec};
|
||||
use roc_parse::ast::Module;
|
||||
use bumpalo::collections::String;
|
||||
use roc_parse::ast::{Collection, Module};
|
||||
use roc_parse::header::{AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, PlatformHeader};
|
||||
use roc_region::all::Located;
|
||||
|
||||
|
@ -64,7 +64,7 @@ pub fn fmt_interface_header<'a>(buf: &mut String<'a>, header: &'a InterfaceHeade
|
|||
fmt_spaces(buf, header.after_imports.iter(), indent);
|
||||
}
|
||||
|
||||
fmt_imports(buf, &header.imports, indent);
|
||||
fmt_imports(buf, header.imports, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_app_header<'a>(buf: &mut String<'a>, header: &'a AppHeader<'a>) {
|
||||
|
@ -76,7 +76,7 @@ pub fn fmt_app_header<'a>(buf: &mut String<'a>, header: &'a AppHeader<'a>) {
|
|||
buf.push_str("imports");
|
||||
|
||||
fmt_spaces(buf, header.before_imports.iter(), indent);
|
||||
fmt_imports(buf, &header.imports, indent);
|
||||
fmt_imports(buf, header.imports, indent);
|
||||
fmt_spaces(buf, header.after_imports.iter(), indent);
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ pub fn fmt_platform_header<'a>(_buf: &mut String<'a>, _header: &'a PlatformHeade
|
|||
|
||||
fn fmt_imports<'a>(
|
||||
buf: &mut String<'a>,
|
||||
loc_entries: &'a Vec<'a, Located<ImportsEntry<'a>>>,
|
||||
loc_entries: Collection<'a, Located<ImportsEntry<'a>>>,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.push('[');
|
||||
|
@ -112,7 +112,7 @@ fn fmt_imports<'a>(
|
|||
|
||||
fn fmt_exposes<'a>(
|
||||
buf: &mut String<'a>,
|
||||
loc_entries: &'a Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
loc_entries: &'a Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.push('[');
|
||||
|
|
|
@ -227,88 +227,18 @@ where
|
|||
ret_layout,
|
||||
..
|
||||
} => {
|
||||
// For most builtins instead of calling a function, we can just inline the low level.
|
||||
match *func_sym {
|
||||
Symbol::NUM_ABS => self.build_run_low_level(
|
||||
// If this function is just a lowlevel wrapper, then inline it
|
||||
if let Some(lowlevel) = LowLevel::from_inlined_wrapper(*func_sym) {
|
||||
self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumAbs,
|
||||
&lowlevel,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_ADD => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumAdd,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_ACOS => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumAcos,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_ASIN => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumAsin,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_ATAN => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumAtan,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_MUL => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumMul,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_POW_INT => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumPowInt,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_SUB => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumSub,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::NUM_ROUND => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::NumRound,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::BOOL_EQ => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::Eq,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
Symbol::STR_CONCAT => self.build_run_low_level(
|
||||
sym,
|
||||
&LowLevel::StrConcat,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
x if x
|
||||
)
|
||||
} else if func_sym
|
||||
.module_string(&self.env().interns)
|
||||
.starts_with(ModuleName::APP) =>
|
||||
.starts_with(ModuleName::APP)
|
||||
{
|
||||
let fn_name = LayoutIds::default()
|
||||
.get(*func_sym, layout)
|
||||
|
@ -316,8 +246,11 @@ where
|
|||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(arguments)?;
|
||||
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
||||
}
|
||||
x => Err(format!("the function, {:?}, is not yet implemented", x)),
|
||||
} else {
|
||||
Err(format!(
|
||||
"the function, {:?}, is not yet implemented",
|
||||
func_sym
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,10 @@ use crate::llvm::build_dict::{
|
|||
use crate::llvm::build_hash::generic_hash;
|
||||
use crate::llvm::build_list::{
|
||||
self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_append, list_concat,
|
||||
list_contains, list_drop, list_drop_at, list_find_trivial_not_found, list_find_unsafe,
|
||||
list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map,
|
||||
list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat,
|
||||
list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap,
|
||||
list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe, list_get_unsafe,
|
||||
list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_map2,
|
||||
list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat, list_reverse,
|
||||
list_set, list_single, list_sort_with, list_sublist, list_swap,
|
||||
};
|
||||
use crate::llvm::build_str::{
|
||||
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
|
||||
|
@ -5490,27 +5490,6 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("Invalid layout {:?} in List.sublist", list_layout),
|
||||
}
|
||||
}
|
||||
ListDrop => {
|
||||
// List.drop : List elem, Nat -> List elem
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let original_wrapper = list.into_struct_value();
|
||||
|
||||
let count = load_symbol(scope, &args[1]);
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||
Layout::Builtin(Builtin::List(element_layout)) => list_drop(
|
||||
env,
|
||||
layout_ids,
|
||||
original_wrapper,
|
||||
count.into_int_value(),
|
||||
element_layout,
|
||||
),
|
||||
_ => unreachable!("Invalid layout {:?} in List.drop", list_layout),
|
||||
}
|
||||
}
|
||||
ListDropAt => {
|
||||
// List.dropAt : List elem, Nat -> List elem
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
|
|
@ -328,28 +328,6 @@ pub fn list_sublist<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.drop : List elem, Nat -> List elem
|
||||
pub fn list_drop<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
count: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
call_bitcode_fn_returns_list(
|
||||
env,
|
||||
&[
|
||||
pass_list_cc(env, original_wrapper.into()),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
count.into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_DROP,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.dropAt : List elem, Nat -> List elem
|
||||
pub fn list_drop_at<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
|
|
@ -2,12 +2,13 @@ use bumpalo::{self, collections::Vec};
|
|||
|
||||
use code_builder::Align;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
|
||||
use crate::layout::WasmLayout;
|
||||
use crate::low_level::{build_call_low_level, LowlevelBuildResult};
|
||||
use crate::low_level::{decode_low_level, LowlevelBuildResult};
|
||||
use crate::storage::{Storage, StoredValue, StoredValueKind};
|
||||
use crate::wasm_module::linking::{
|
||||
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK,
|
||||
|
@ -22,8 +23,8 @@ use crate::wasm_module::{
|
|||
LocalId, Signature, SymInfo, ValueType,
|
||||
};
|
||||
use crate::{
|
||||
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE,
|
||||
STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_SIZE,
|
||||
PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||
};
|
||||
|
||||
/// The memory address where the constants data will be loaded during module instantiation.
|
||||
|
@ -469,6 +470,11 @@ impl<'a> WasmBackend<'a> {
|
|||
arguments,
|
||||
}) => match call_type {
|
||||
CallType::ByName { name: func_sym, .. } => {
|
||||
// If this function is just a lowlevel wrapper, then inline it
|
||||
if let Some(lowlevel) = LowLevel::from_inlined_wrapper(*func_sym) {
|
||||
return self.build_low_level(lowlevel, arguments, wasm_layout);
|
||||
}
|
||||
|
||||
let mut wasm_args_tmp: Vec<Symbol>;
|
||||
let (wasm_args, has_return_val) = match wasm_layout {
|
||||
WasmLayout::StackMemory { .. } => {
|
||||
|
@ -511,10 +517,50 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
|
||||
CallType::LowLevel { op: lowlevel, .. } => {
|
||||
let return_layout = WasmLayout::new(layout);
|
||||
self.build_low_level(*lowlevel, arguments, wasm_layout)
|
||||
}
|
||||
|
||||
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
||||
},
|
||||
|
||||
Expr::Struct(fields) => self.create_struct(sym, layout, fields),
|
||||
|
||||
Expr::StructAtIndex {
|
||||
index,
|
||||
field_layouts,
|
||||
structure,
|
||||
} => {
|
||||
if let StoredValue::StackMemory { location, .. } = self.storage.get(structure) {
|
||||
let (local_id, mut offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
for field in field_layouts.iter().take(*index as usize) {
|
||||
offset += field.stack_size(PTR_SIZE);
|
||||
}
|
||||
self.storage.copy_value_from_memory(
|
||||
&mut self.code_builder,
|
||||
*sym,
|
||||
local_id,
|
||||
offset,
|
||||
);
|
||||
} else {
|
||||
unreachable!("Unexpected storage for {:?}", structure)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
x => Err(format!("Expression is not yet implemented {:?}", x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_low_level(
|
||||
&mut self,
|
||||
lowlevel: LowLevel,
|
||||
arguments: &'a [Symbol],
|
||||
return_layout: WasmLayout,
|
||||
) -> Result<(), String> {
|
||||
self.storage.load_symbols(&mut self.code_builder, arguments);
|
||||
|
||||
let build_result = build_call_low_level(
|
||||
let build_result = decode_low_level(
|
||||
&mut self.code_builder,
|
||||
&mut self.storage,
|
||||
lowlevel,
|
||||
|
@ -535,14 +581,6 @@ impl<'a> WasmBackend<'a> {
|
|||
)),
|
||||
}
|
||||
}
|
||||
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
||||
},
|
||||
|
||||
Expr::Struct(fields) => self.create_struct(sym, layout, fields),
|
||||
|
||||
x => Err(format!("Expression is not yet implemented {:?}", x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_literal(
|
||||
&mut self,
|
||||
|
@ -741,14 +779,15 @@ impl<'a> WasmBackend<'a> {
|
|||
};
|
||||
self.module.import.entries.push(import);
|
||||
|
||||
let sym_idx = self.linker_symbols.len() as u32;
|
||||
let sym_idx = self.linker_symbols.len();
|
||||
let sym_info = SymInfo::Function(WasmObjectSymbol::Imported {
|
||||
flags: WASM_SYM_UNDEFINED,
|
||||
index: import_index,
|
||||
});
|
||||
self.linker_symbols.push(sym_info);
|
||||
self.builtin_sym_index_map.insert(name, sym_idx);
|
||||
|
||||
(import_index, sym_idx)
|
||||
(import_index, sym_idx as u32)
|
||||
}
|
||||
};
|
||||
self.code_builder.call(
|
||||
|
|
|
@ -15,10 +15,10 @@ pub enum LowlevelBuildResult {
|
|||
NotImplemented,
|
||||
}
|
||||
|
||||
pub fn build_call_low_level<'a>(
|
||||
pub fn decode_low_level<'a>(
|
||||
code_builder: &mut CodeBuilder<'a>,
|
||||
storage: &mut Storage<'a>,
|
||||
lowlevel: &LowLevel,
|
||||
lowlevel: LowLevel,
|
||||
args: &'a [Symbol],
|
||||
ret_layout: &WasmLayout,
|
||||
) -> LowlevelBuildResult {
|
||||
|
@ -34,9 +34,9 @@ pub fn build_call_low_level<'a>(
|
|||
| ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap
|
||||
| ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
||||
| ListSublist | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize
|
||||
| DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys
|
||||
| DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => {
|
||||
| ListSublist | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize | DictEmpty
|
||||
| DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys | DictValues
|
||||
| DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => {
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,9 @@ pub fn build_call_low_level<'a>(
|
|||
NumIsMultipleOf => return NotImplemented,
|
||||
NumAbs => match ret_layout.value_type() {
|
||||
I32 => {
|
||||
let arg_storage = storage.get(&args[0]).to_owned();
|
||||
storage.ensure_value_has_local(code_builder, args[0], arg_storage);
|
||||
storage.load_symbols(code_builder, args);
|
||||
code_builder.i32_const(0);
|
||||
storage.load_symbols(code_builder, args);
|
||||
code_builder.i32_sub();
|
||||
|
@ -138,6 +141,9 @@ pub fn build_call_low_level<'a>(
|
|||
code_builder.select();
|
||||
}
|
||||
I64 => {
|
||||
let arg_storage = storage.get(&args[0]).to_owned();
|
||||
storage.ensure_value_has_local(code_builder, args[0], arg_storage);
|
||||
storage.load_symbols(code_builder, args);
|
||||
code_builder.i64_const(0);
|
||||
storage.load_symbols(code_builder, args);
|
||||
code_builder.i64_sub();
|
||||
|
|
|
@ -319,6 +319,67 @@ impl<'a> Storage<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generate code to copy a StoredValue from an arbitrary memory location
|
||||
/// (defined by a pointer and offset).
|
||||
pub fn copy_value_from_memory(
|
||||
&mut self,
|
||||
code_builder: &mut CodeBuilder,
|
||||
to_symbol: Symbol,
|
||||
from_ptr: LocalId,
|
||||
from_offset: u32,
|
||||
) -> u32 {
|
||||
let to_storage = self.get(&to_symbol).to_owned();
|
||||
match to_storage {
|
||||
StoredValue::StackMemory {
|
||||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
} => {
|
||||
let (to_ptr, to_offset) = location.local_and_offset(self.stack_frame_pointer);
|
||||
copy_memory(
|
||||
code_builder,
|
||||
CopyMemoryConfig {
|
||||
from_ptr,
|
||||
from_offset,
|
||||
to_ptr,
|
||||
to_offset,
|
||||
size,
|
||||
alignment_bytes,
|
||||
},
|
||||
);
|
||||
size
|
||||
}
|
||||
|
||||
StoredValue::VirtualMachineStack {
|
||||
value_type, size, ..
|
||||
}
|
||||
| StoredValue::Local {
|
||||
value_type, size, ..
|
||||
} => {
|
||||
use crate::wasm_module::Align::*;
|
||||
|
||||
code_builder.get_local(from_ptr);
|
||||
match (value_type, size) {
|
||||
(ValueType::I64, 8) => code_builder.i64_load(Bytes8, from_offset),
|
||||
(ValueType::I32, 4) => code_builder.i32_load(Bytes4, from_offset),
|
||||
(ValueType::I32, 2) => code_builder.i32_load16_s(Bytes2, from_offset),
|
||||
(ValueType::I32, 1) => code_builder.i32_load8_s(Bytes1, from_offset),
|
||||
(ValueType::F32, 4) => code_builder.f32_load(Bytes4, from_offset),
|
||||
(ValueType::F64, 8) => code_builder.f64_load(Bytes8, from_offset),
|
||||
_ => {
|
||||
panic!("Cannot store {:?} with alignment of {:?}", value_type, size);
|
||||
}
|
||||
};
|
||||
|
||||
if let StoredValue::Local { local_id, .. } = to_storage {
|
||||
code_builder.set_local(local_id);
|
||||
}
|
||||
|
||||
size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate code to copy from one StoredValue to another
|
||||
/// Copies the _entire_ value. For struct fields etc., see `copy_value_to_memory`
|
||||
pub fn clone_value(
|
||||
|
|
|
@ -2608,8 +2608,8 @@ fn parse_header<'a>(
|
|||
opt_shorthand,
|
||||
header_src,
|
||||
packages: &[],
|
||||
exposes: header.exposes.into_bump_slice(),
|
||||
imports: header.imports.into_bump_slice(),
|
||||
exposes: header.exposes.items,
|
||||
imports: header.imports.items,
|
||||
to_platform: None,
|
||||
};
|
||||
|
||||
|
@ -2642,8 +2642,8 @@ fn parse_header<'a>(
|
|||
opt_shorthand,
|
||||
header_src,
|
||||
packages,
|
||||
exposes: header.provides.into_bump_slice(),
|
||||
imports: header.imports.into_bump_slice(),
|
||||
exposes: header.provides.items,
|
||||
imports: header.imports.items,
|
||||
to_platform: Some(header.to.value.clone()),
|
||||
};
|
||||
|
||||
|
@ -3236,7 +3236,7 @@ fn send_header_two<'a>(
|
|||
|
||||
let extra = HeaderFor::PkgConfig {
|
||||
config_shorthand: shorthand,
|
||||
platform_main_type: requires[0].value.clone(),
|
||||
platform_main_type: requires[0].value,
|
||||
main_for_host,
|
||||
};
|
||||
|
||||
|
@ -3409,8 +3409,7 @@ fn fabricate_pkg_config_module<'a>(
|
|||
header_src: &'a str,
|
||||
module_timing: ModuleTiming,
|
||||
) -> (ModuleId, Msg<'a>) {
|
||||
let provides: &'a [Located<ExposesEntry<'a, &'a str>>] =
|
||||
header.provides.clone().into_bump_slice();
|
||||
let provides: &'a [Located<ExposesEntry<'a, &'a str>>] = header.provides.items;
|
||||
|
||||
let info = PlatformHeaderInfo {
|
||||
filename,
|
||||
|
@ -3420,8 +3419,8 @@ fn fabricate_pkg_config_module<'a>(
|
|||
app_module_id,
|
||||
packages: &[],
|
||||
provides,
|
||||
requires: arena.alloc([header.requires.signature.clone()]),
|
||||
imports: header.imports.clone().into_bump_slice(),
|
||||
requires: arena.alloc([header.requires.signature]),
|
||||
imports: header.imports.items,
|
||||
};
|
||||
|
||||
send_header_two(
|
||||
|
@ -3467,7 +3466,7 @@ fn fabricate_effects_module<'a>(
|
|||
{
|
||||
let mut module_ids = (*module_ids).lock();
|
||||
|
||||
for exposed in header.exposes {
|
||||
for exposed in header.exposes.iter() {
|
||||
if let ExposesEntry::Exposed(module_name) = exposed.value {
|
||||
module_ids.get_or_insert(&PQModuleName::Qualified(
|
||||
shorthand,
|
||||
|
@ -3886,7 +3885,7 @@ fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a>
|
|||
Module(module_name, exposes) => {
|
||||
let mut exposed = Vec::with_capacity(exposes.len());
|
||||
|
||||
for loc_entry in exposes {
|
||||
for loc_entry in exposes.iter() {
|
||||
exposed.push(ident_from_exposed(&loc_entry.value));
|
||||
}
|
||||
|
||||
|
@ -3901,7 +3900,7 @@ fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a>
|
|||
Package(package_name, module_name, exposes) => {
|
||||
let mut exposed = Vec::with_capacity(exposes.len());
|
||||
|
||||
for loc_entry in exposes {
|
||||
for loc_entry in exposes.iter() {
|
||||
exposed.push(ident_from_exposed(&loc_entry.value));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::symbol::Symbol;
|
||||
|
||||
/// Low-level operations that get translated directly into e.g. LLVM instructions.
|
||||
/// These are always wrapped when exposed to end users, and can only make it
|
||||
/// into an Expr when added directly by can::builtins
|
||||
|
@ -45,7 +47,6 @@ pub enum LowLevel {
|
|||
ListKeepErrs,
|
||||
ListSortWith,
|
||||
ListSublist,
|
||||
ListDrop,
|
||||
ListDropAt,
|
||||
ListSwap,
|
||||
ListAny,
|
||||
|
@ -115,106 +116,6 @@ pub enum LowLevel {
|
|||
ExpectTrue,
|
||||
}
|
||||
|
||||
macro_rules! first_order {
|
||||
() => {
|
||||
StrConcat
|
||||
| StrJoinWith
|
||||
| StrIsEmpty
|
||||
| StrStartsWith
|
||||
| StrStartsWithCodePt
|
||||
| StrEndsWith
|
||||
| StrSplit
|
||||
| StrCountGraphemes
|
||||
| StrFromInt
|
||||
| StrFromUtf8
|
||||
| StrFromUtf8Range
|
||||
| StrToUtf8
|
||||
| StrRepeat
|
||||
| StrTrim
|
||||
| StrTrimLeft
|
||||
| StrTrimRight
|
||||
| StrFromFloat
|
||||
| ListLen
|
||||
| ListGetUnsafe
|
||||
| ListSet
|
||||
| ListSublist
|
||||
| ListDrop
|
||||
| ListDropAt
|
||||
| ListSingle
|
||||
| ListRepeat
|
||||
| ListReverse
|
||||
| ListConcat
|
||||
| ListContains
|
||||
| ListAppend
|
||||
| ListPrepend
|
||||
| ListJoin
|
||||
| ListRange
|
||||
| ListSwap
|
||||
| DictSize
|
||||
| DictEmpty
|
||||
| DictInsert
|
||||
| DictRemove
|
||||
| DictContains
|
||||
| DictGetUnsafe
|
||||
| DictKeys
|
||||
| DictValues
|
||||
| DictUnion
|
||||
| DictIntersection
|
||||
| DictDifference
|
||||
| SetFromList
|
||||
| NumAdd
|
||||
| NumAddWrap
|
||||
| NumAddChecked
|
||||
| NumSub
|
||||
| NumSubWrap
|
||||
| NumSubChecked
|
||||
| NumMul
|
||||
| NumMulWrap
|
||||
| NumMulChecked
|
||||
| NumGt
|
||||
| NumGte
|
||||
| NumLt
|
||||
| NumLte
|
||||
| NumCompare
|
||||
| NumDivUnchecked
|
||||
| NumDivCeilUnchecked
|
||||
| NumRemUnchecked
|
||||
| NumIsMultipleOf
|
||||
| NumAbs
|
||||
| NumNeg
|
||||
| NumSin
|
||||
| NumCos
|
||||
| NumSqrtUnchecked
|
||||
| NumLogUnchecked
|
||||
| NumRound
|
||||
| NumToFloat
|
||||
| NumPow
|
||||
| NumCeiling
|
||||
| NumPowInt
|
||||
| NumFloor
|
||||
| NumIsFinite
|
||||
| NumAtan
|
||||
| NumAcos
|
||||
| NumAsin
|
||||
| NumBitwiseAnd
|
||||
| NumBitwiseXor
|
||||
| NumBitwiseOr
|
||||
| NumShiftLeftBy
|
||||
| NumShiftRightBy
|
||||
| NumBytesToU16
|
||||
| NumBytesToU32
|
||||
| NumShiftRightZfBy
|
||||
| NumIntCast
|
||||
| Eq
|
||||
| NotEq
|
||||
| And
|
||||
| Or
|
||||
| Not
|
||||
| Hash
|
||||
| ExpectTrue
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! higher_order {
|
||||
() => {
|
||||
ListMap
|
||||
|
@ -241,17 +142,13 @@ impl LowLevel {
|
|||
pub fn is_higher_order(&self) -> bool {
|
||||
use LowLevel::*;
|
||||
|
||||
match self {
|
||||
first_order!() => false,
|
||||
higher_order!() => true,
|
||||
}
|
||||
matches!(self, higher_order!())
|
||||
}
|
||||
|
||||
pub fn function_argument_position(&self) -> usize {
|
||||
use LowLevel::*;
|
||||
|
||||
match self {
|
||||
first_order!() => unreachable!(),
|
||||
ListMap => 1,
|
||||
ListMap2 => 2,
|
||||
ListMap3 => 3,
|
||||
|
@ -267,6 +164,127 @@ impl LowLevel {
|
|||
ListAny => 1,
|
||||
ListFindUnsafe => 1,
|
||||
DictWalk => 2,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Used in dev backends to inline some lowlevel wrapper functions
|
||||
/// For wrappers that contain logic, we return None to prevent inlining
|
||||
/// (Mention each explicitly rather than using `_`, to show they have not been forgotten)
|
||||
pub fn from_inlined_wrapper(symbol: Symbol) -> Option<LowLevel> {
|
||||
use LowLevel::*;
|
||||
|
||||
match symbol {
|
||||
Symbol::STR_CONCAT => Some(StrConcat),
|
||||
Symbol::STR_JOIN_WITH => Some(StrJoinWith),
|
||||
Symbol::STR_IS_EMPTY => Some(StrIsEmpty),
|
||||
Symbol::STR_STARTS_WITH => Some(StrStartsWith),
|
||||
Symbol::STR_STARTS_WITH_CODE_PT => Some(StrStartsWithCodePt),
|
||||
Symbol::STR_ENDS_WITH => Some(StrEndsWith),
|
||||
Symbol::STR_SPLIT => Some(StrSplit),
|
||||
Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes),
|
||||
Symbol::STR_FROM_INT => Some(StrFromInt),
|
||||
Symbol::STR_FROM_UTF8 => None,
|
||||
Symbol::STR_FROM_UTF8_RANGE => None,
|
||||
Symbol::STR_TO_UTF8 => Some(StrToUtf8),
|
||||
Symbol::STR_REPEAT => Some(StrRepeat),
|
||||
Symbol::STR_FROM_FLOAT => Some(StrFromFloat),
|
||||
Symbol::STR_TRIM => Some(StrTrim),
|
||||
Symbol::STR_TRIM_LEFT => Some(StrTrimLeft),
|
||||
Symbol::STR_TRIM_RIGHT => Some(StrTrimRight),
|
||||
Symbol::LIST_LEN => Some(ListLen),
|
||||
Symbol::LIST_GET => None,
|
||||
Symbol::LIST_SET => None,
|
||||
Symbol::LIST_SINGLE => Some(ListSingle),
|
||||
Symbol::LIST_REPEAT => Some(ListRepeat),
|
||||
Symbol::LIST_REVERSE => Some(ListReverse),
|
||||
Symbol::LIST_CONCAT => Some(ListConcat),
|
||||
Symbol::LIST_CONTAINS => Some(ListContains),
|
||||
Symbol::LIST_APPEND => Some(ListAppend),
|
||||
Symbol::LIST_PREPEND => Some(ListPrepend),
|
||||
Symbol::LIST_JOIN => Some(ListJoin),
|
||||
Symbol::LIST_RANGE => Some(ListRange),
|
||||
Symbol::LIST_MAP => Some(ListMap),
|
||||
Symbol::LIST_MAP2 => Some(ListMap2),
|
||||
Symbol::LIST_MAP3 => Some(ListMap3),
|
||||
Symbol::LIST_MAP4 => Some(ListMap4),
|
||||
Symbol::LIST_MAP_WITH_INDEX => Some(ListMapWithIndex),
|
||||
Symbol::LIST_KEEP_IF => Some(ListKeepIf),
|
||||
Symbol::LIST_WALK => Some(ListWalk),
|
||||
Symbol::LIST_WALK_UNTIL => Some(ListWalkUntil),
|
||||
Symbol::LIST_WALK_BACKWARDS => Some(ListWalkBackwards),
|
||||
Symbol::LIST_KEEP_OKS => Some(ListKeepOks),
|
||||
Symbol::LIST_KEEP_ERRS => Some(ListKeepErrs),
|
||||
Symbol::LIST_SORT_WITH => Some(ListSortWith),
|
||||
Symbol::LIST_SUBLIST => Some(ListSublist),
|
||||
Symbol::LIST_DROP_AT => Some(ListDropAt),
|
||||
Symbol::LIST_SWAP => Some(ListSwap),
|
||||
Symbol::LIST_ANY => Some(ListAny),
|
||||
Symbol::LIST_FIND => None,
|
||||
Symbol::DICT_LEN => Some(DictSize),
|
||||
Symbol::DICT_EMPTY => Some(DictEmpty),
|
||||
Symbol::DICT_INSERT => Some(DictInsert),
|
||||
Symbol::DICT_REMOVE => Some(DictRemove),
|
||||
Symbol::DICT_CONTAINS => Some(DictContains),
|
||||
Symbol::DICT_GET => None,
|
||||
Symbol::DICT_KEYS => Some(DictKeys),
|
||||
Symbol::DICT_VALUES => Some(DictValues),
|
||||
Symbol::DICT_UNION => Some(DictUnion),
|
||||
Symbol::DICT_INTERSECTION => Some(DictIntersection),
|
||||
Symbol::DICT_DIFFERENCE => Some(DictDifference),
|
||||
Symbol::DICT_WALK => Some(DictWalk),
|
||||
Symbol::SET_FROM_LIST => Some(SetFromList),
|
||||
Symbol::NUM_ADD => Some(NumAdd),
|
||||
Symbol::NUM_ADD_WRAP => Some(NumAddWrap),
|
||||
Symbol::NUM_ADD_CHECKED => None,
|
||||
Symbol::NUM_SUB => Some(NumSub),
|
||||
Symbol::NUM_SUB_WRAP => Some(NumSubWrap),
|
||||
Symbol::NUM_SUB_CHECKED => None,
|
||||
Symbol::NUM_MUL => Some(NumMul),
|
||||
Symbol::NUM_MUL_WRAP => Some(NumMulWrap),
|
||||
Symbol::NUM_MUL_CHECKED => None,
|
||||
Symbol::NUM_GT => Some(NumGt),
|
||||
Symbol::NUM_GTE => Some(NumGte),
|
||||
Symbol::NUM_LT => Some(NumLt),
|
||||
Symbol::NUM_LTE => Some(NumLte),
|
||||
Symbol::NUM_COMPARE => Some(NumCompare),
|
||||
Symbol::NUM_DIV_FLOAT => None,
|
||||
Symbol::NUM_DIV_CEIL => None,
|
||||
Symbol::NUM_REM => None,
|
||||
Symbol::NUM_IS_MULTIPLE_OF => Some(NumIsMultipleOf),
|
||||
Symbol::NUM_ABS => Some(NumAbs),
|
||||
Symbol::NUM_NEG => Some(NumNeg),
|
||||
Symbol::NUM_SIN => Some(NumSin),
|
||||
Symbol::NUM_COS => Some(NumCos),
|
||||
Symbol::NUM_SQRT => None,
|
||||
Symbol::NUM_LOG => None,
|
||||
Symbol::NUM_ROUND => Some(NumRound),
|
||||
Symbol::NUM_TO_FLOAT => Some(NumToFloat),
|
||||
Symbol::NUM_POW => Some(NumPow),
|
||||
Symbol::NUM_CEILING => Some(NumCeiling),
|
||||
Symbol::NUM_POW_INT => Some(NumPowInt),
|
||||
Symbol::NUM_FLOOR => Some(NumFloor),
|
||||
// => Some(NumIsFinite),
|
||||
Symbol::NUM_ATAN => Some(NumAtan),
|
||||
Symbol::NUM_ACOS => Some(NumAcos),
|
||||
Symbol::NUM_ASIN => Some(NumAsin),
|
||||
Symbol::NUM_BYTES_TO_U16 => None,
|
||||
Symbol::NUM_BYTES_TO_U32 => None,
|
||||
Symbol::NUM_BITWISE_AND => Some(NumBitwiseAnd),
|
||||
Symbol::NUM_BITWISE_XOR => Some(NumBitwiseXor),
|
||||
Symbol::NUM_BITWISE_OR => Some(NumBitwiseOr),
|
||||
Symbol::NUM_SHIFT_LEFT => Some(NumShiftLeftBy),
|
||||
Symbol::NUM_SHIFT_RIGHT => Some(NumShiftRightBy),
|
||||
Symbol::NUM_SHIFT_RIGHT_ZERO_FILL => Some(NumShiftRightZfBy),
|
||||
Symbol::NUM_INT_CAST => Some(NumIntCast),
|
||||
Symbol::BOOL_EQ => Some(Eq),
|
||||
Symbol::BOOL_NEQ => Some(NotEq),
|
||||
Symbol::BOOL_AND => Some(And),
|
||||
Symbol::BOOL_OR => Some(Or),
|
||||
Symbol::BOOL_NOT => Some(Not),
|
||||
// => Some(Hash),
|
||||
// => Some(ExpectTrue),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -968,7 +968,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
// List.append should own its first argument
|
||||
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
|
||||
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
|
||||
|
|
|
@ -101,7 +101,6 @@ enum FirstOrder {
|
|||
ListGetUnsafe,
|
||||
ListSet,
|
||||
ListSublist,
|
||||
ListDrop,
|
||||
ListDropAt,
|
||||
ListSingle,
|
||||
ListRepeat,
|
||||
|
|
|
@ -38,7 +38,7 @@ pub enum PackageOrPath<'a> {
|
|||
Path(StrLiteral<'a>),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ModuleName<'a>(&'a str);
|
||||
|
||||
impl<'a> From<ModuleName<'a>> for &'a str {
|
||||
|
@ -60,8 +60,8 @@ impl<'a> ModuleName<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct InterfaceHeader<'a> {
|
||||
pub name: Loc<ModuleName<'a>>,
|
||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub exposes: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
pub before_header: &'a [CommentOrNewline<'a>],
|
||||
|
@ -82,8 +82,8 @@ pub enum To<'a> {
|
|||
pub struct AppHeader<'a> {
|
||||
pub name: Loc<StrLiteral<'a>>,
|
||||
pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub to: Loc<To<'a>>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
|
@ -117,7 +117,7 @@ pub struct PackageHeader<'a> {
|
|||
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum PlatformRigid<'a> {
|
||||
Entry { rigid: &'a str, alias: &'a str },
|
||||
|
||||
|
@ -137,7 +137,7 @@ impl<'a> Spaceable<'a> for PlatformRigid<'a> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformRequires<'a> {
|
||||
pub rigids: Vec<'a, Loc<PlatformRigid<'a>>>,
|
||||
pub rigids: Collection<'a, Loc<PlatformRigid<'a>>>,
|
||||
pub signature: Loc<TypedIdent<'a>>,
|
||||
}
|
||||
|
||||
|
@ -145,10 +145,10 @@ pub struct PlatformRequires<'a> {
|
|||
pub struct PlatformHeader<'a> {
|
||||
pub name: Loc<PackageName<'a>>,
|
||||
pub requires: PlatformRequires<'a>,
|
||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
pub exposes: Collection<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>,
|
||||
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
pub effects: Effects<'a>,
|
||||
|
||||
// Potential comments and newlines - these will typically all be empty.
|
||||
|
@ -177,7 +177,7 @@ pub struct Effects<'a> {
|
|||
pub entries: &'a [Loc<TypedIdent<'a>>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ExposesEntry<'a, T> {
|
||||
/// e.g. `Task`
|
||||
Exposed(T),
|
||||
|
@ -196,16 +196,19 @@ impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ImportsEntry<'a> {
|
||||
/// e.g. `Task` or `Task.{ Task, after }`
|
||||
Module(ModuleName<'a>, Vec<'a, Loc<ExposesEntry<'a, &'a str>>>),
|
||||
Module(
|
||||
ModuleName<'a>,
|
||||
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
|
||||
/// e.g. `base.Task` or `base.Task.{ after }` or `base.{ Task.{ Task, after } }`
|
||||
Package(
|
||||
&'a str,
|
||||
ModuleName<'a>,
|
||||
Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
|
||||
// Spaces
|
||||
|
@ -224,7 +227,7 @@ impl<'a> ExposesEntry<'a, &'a str> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum TypedIdent<'a> {
|
||||
/// e.g.
|
||||
///
|
||||
|
|
|
@ -220,11 +220,11 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|||
#[allow(clippy::type_complexity)]
|
||||
let opt_imports: Option<(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ImportsEntry<'a>>>,
|
||||
Collection<'a, Located<ImportsEntry<'a>>>,
|
||||
)> = opt_imports;
|
||||
|
||||
let ((before_imports, after_imports), imports) =
|
||||
opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Vec::new_in(arena)));
|
||||
opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Collection::empty()));
|
||||
let provides: ProvidesTo<'a> = provides; // rustc must be told the type here
|
||||
|
||||
let header = AppHeader {
|
||||
|
@ -303,7 +303,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
|||
|
||||
#[derive(Debug)]
|
||||
struct ProvidesTo<'a> {
|
||||
entries: Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
entries: Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
to: Located<To<'a>>,
|
||||
|
||||
before_provides_keyword: &'a [CommentOrNewline<'a>],
|
||||
|
@ -362,7 +362,7 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
EProvides<'a>,
|
||||
> {
|
||||
|
@ -376,14 +376,16 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
word1(b',', EProvides::ListEnd),
|
||||
word1(b']', EProvides::ListEnd),
|
||||
min_indent,
|
||||
EProvides::Open,
|
||||
EProvides::Space,
|
||||
EProvides::IndentListEnd
|
||||
EProvides::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -442,15 +444,17 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
|
|||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Vec<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> {
|
||||
collection_e!(
|
||||
) -> impl Parser<'a, Collection<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
ERequires::Open,
|
||||
ERequires::Space,
|
||||
ERequires::IndentListEnd
|
||||
ERequires::IndentListEnd,
|
||||
PlatformRigid::SpaceBefore
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -487,7 +491,7 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||
),
|
||||
EExposes,
|
||||
> {
|
||||
|
@ -502,14 +506,16 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EExposes::ListStart),
|
||||
exposes_entry(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::Space,
|
||||
EExposes::IndentListEnd
|
||||
EExposes::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -539,7 +545,7 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
Collection<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
),
|
||||
EExposes,
|
||||
> {
|
||||
|
@ -554,14 +560,16 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EExposes::ListStart),
|
||||
exposes_module(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::Space,
|
||||
EExposes::IndentListEnd
|
||||
EExposes::IndentListEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -631,7 +639,7 @@ fn imports<'a>() -> impl Parser<
|
|||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ImportsEntry<'a>>>,
|
||||
Collection<'a, Located<ImportsEntry<'a>>>,
|
||||
),
|
||||
EImports,
|
||||
> {
|
||||
|
@ -646,14 +654,16 @@ fn imports<'a>() -> impl Parser<
|
|||
EImports::IndentImports,
|
||||
EImports::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EImports::ListStart),
|
||||
loc!(imports_entry()),
|
||||
word1(b',', EImports::ListEnd),
|
||||
word1(b']', EImports::ListEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::Space,
|
||||
EImports::IndentListEnd
|
||||
EImports::IndentListEnd,
|
||||
ImportsEntry::SpaceBefore
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -687,14 +697,16 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
|
|||
space0_e(min_indent, EEffects::Space, EEffects::IndentListStart)
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
let (_, entries, state) = collection_e!(
|
||||
let (_, entries, state) = collection_trailing_sep_e!(
|
||||
word1(b'{', EEffects::ListStart),
|
||||
specialize(EEffects::TypedIdent, loc!(typed_ident())),
|
||||
word1(b',', EEffects::ListEnd),
|
||||
word1(b'}', EEffects::ListEnd),
|
||||
min_indent,
|
||||
EEffects::Open,
|
||||
EEffects::Space,
|
||||
EEffects::IndentListEnd
|
||||
EEffects::IndentListEnd,
|
||||
TypedIdent::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -706,7 +718,7 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
|
|||
spaces_after_type_name,
|
||||
effect_shortname: type_shortname,
|
||||
effect_type_name: type_name,
|
||||
entries: entries.into_bump_slice(),
|
||||
entries: entries.items,
|
||||
},
|
||||
state,
|
||||
))
|
||||
|
@ -768,7 +780,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> {
|
|||
|
||||
type Temp<'a> = (
|
||||
(Option<&'a str>, ModuleName<'a>),
|
||||
Option<Vec<'a, Located<ExposesEntry<'a, &'a str>>>>,
|
||||
Option<Collection<'a, Located<ExposesEntry<'a, &'a str>>>>,
|
||||
);
|
||||
|
||||
map_with_arena!(
|
||||
|
@ -785,19 +797,21 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> {
|
|||
// e.g. `.{ Task, after}`
|
||||
maybe!(skip_first!(
|
||||
word1(b'.', EImports::ExposingDot),
|
||||
collection_e!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', EImports::SetStart),
|
||||
exposes_entry(EImports::Identifier),
|
||||
word1(b',', EImports::SetEnd),
|
||||
word1(b'}', EImports::SetEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::Space,
|
||||
EImports::IndentSetEnd
|
||||
EImports::IndentSetEnd,
|
||||
ExposesEntry::SpaceBefore
|
||||
)
|
||||
))
|
||||
),
|
||||
|arena, ((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena));
|
||||
|_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(Collection::empty);
|
||||
|
||||
match opt_shortname {
|
||||
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
|
||||
|
|
|
@ -214,6 +214,7 @@ pub enum EHeader<'a> {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EProvides<'a> {
|
||||
Provides(Row, Col),
|
||||
Open(Row, Col),
|
||||
To(Row, Col),
|
||||
IndentProvides(Row, Col),
|
||||
IndentTo(Row, Col),
|
||||
|
@ -230,6 +231,7 @@ pub enum EProvides<'a> {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EExposes {
|
||||
Exposes(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentExposes(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
IndentListEnd(Row, Col),
|
||||
|
@ -242,6 +244,7 @@ pub enum EExposes {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ERequires<'a> {
|
||||
Requires(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentRequires(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
IndentListEnd(Row, Col),
|
||||
|
@ -302,6 +305,7 @@ pub enum EPackageEntry<'a> {
|
|||
pub enum EEffects<'a> {
|
||||
Space(BadInputError, Row, Col),
|
||||
Effects(Row, Col),
|
||||
Open(Row, Col),
|
||||
IndentEffects(Row, Col),
|
||||
ListStart(Row, Col),
|
||||
ListEnd(Row, Col),
|
||||
|
@ -315,6 +319,7 @@ pub enum EEffects<'a> {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EImports {
|
||||
Open(Row, Col),
|
||||
Imports(Row, Col),
|
||||
IndentImports(Row, Col),
|
||||
IndentListStart(Row, Col),
|
||||
|
@ -1183,83 +1188,6 @@ macro_rules! collection {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collection_e {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $space_problem:expr, $indent_problem:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
skip_first!(
|
||||
// We specifically allow space characters inside here, so that
|
||||
// `[ ]` can be successfully parsed as an empty list, and then
|
||||
// changed by the formatter back into `[]`.
|
||||
//
|
||||
// We don't allow newlines or comments in the middle of empty
|
||||
// roc_collections because those are normally stored in an Expr,
|
||||
// and there's no Expr in which to store them in an empty collection!
|
||||
//
|
||||
// We could change the AST to add extra storage specifically to
|
||||
// support empty literals containing newlines or comments, but this
|
||||
// does not seem worth even the tiniest regression in compiler performance.
|
||||
zero_or_more!($crate::parser::word1(b' ', |row, col| $space_problem(
|
||||
crate::parser::BadInputError::LineTooLong,
|
||||
row,
|
||||
col
|
||||
))),
|
||||
skip_second!(
|
||||
$crate::parser::sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_around_ee(
|
||||
$elem,
|
||||
$min_indent,
|
||||
$space_problem,
|
||||
$indent_problem,
|
||||
$indent_problem
|
||||
)
|
||||
),
|
||||
$closing_brace
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse zero or more elements between two braces (e.g. square braces).
|
||||
/// Elements can be optionally surrounded by spaces, and are separated by a
|
||||
/// delimiter (e.g comma-separated) with optionally a trailing delimiter.
|
||||
/// Braces and delimiters get discarded.
|
||||
#[macro_export]
|
||||
macro_rules! collection_trailing_sep {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
skip_first!(
|
||||
// We specifically allow space characters inside here, so that
|
||||
// `[ ]` can be successfully parsed as an empty list, and then
|
||||
// changed by the formatter back into `[]`.
|
||||
//
|
||||
// We don't allow newlines or comments in the middle of empty
|
||||
// roc_collections because those are normally stored in an Expr,
|
||||
// and there's no Expr in which to store them in an empty collection!
|
||||
//
|
||||
// We could change the AST to add extra storage specifically to
|
||||
// support empty literals containing newlines or comments, but this
|
||||
// does not seem worth even the tiniest regression in compiler performance.
|
||||
zero_or_more!($crate::parser::ascii_char(b' ')),
|
||||
skip_second!(
|
||||
and!(
|
||||
$crate::parser::trailing_sep_by0(
|
||||
$delimiter,
|
||||
$crate::blankspace::space0_around($elem, $min_indent)
|
||||
),
|
||||
$crate::blankspace::space0($min_indent)
|
||||
),
|
||||
$closing_brace
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collection_trailing_sep_e {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr, $space_before:expr) => {
|
||||
|
|
|
@ -3077,8 +3077,8 @@ mod test_parse {
|
|||
fn empty_app_header() {
|
||||
let arena = Bump::new();
|
||||
let packages = Collection::empty();
|
||||
let imports = Vec::new_in(&arena);
|
||||
let provides = Vec::new_in(&arena);
|
||||
let imports = Collection::empty();
|
||||
let provides = Collection::empty();
|
||||
let module_name = StrLiteral::PlainLine("test-app");
|
||||
let header = AppHeader {
|
||||
name: Located::new(0, 0, 4, 14, module_name),
|
||||
|
@ -3117,8 +3117,8 @@ mod test_parse {
|
|||
|
||||
let arena = Bump::new();
|
||||
let packages = Collection::empty();
|
||||
let imports = Vec::new_in(&arena);
|
||||
let provides = Vec::new_in(&arena);
|
||||
let imports = Collection::empty();
|
||||
let provides = Collection::empty();
|
||||
let module_name = StrLiteral::PlainLine("test-app");
|
||||
let header = AppHeader {
|
||||
before_header: &[],
|
||||
|
@ -3166,11 +3166,11 @@ mod test_parse {
|
|||
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
|
||||
let arena = Bump::new();
|
||||
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
|
||||
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena));
|
||||
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Collection::empty());
|
||||
let loc_import = Located::new(2, 2, 14, 25, import);
|
||||
let imports = bumpalo::vec![in &arena; loc_import];
|
||||
let imports = Collection::with_items(arena.alloc([loc_import]));
|
||||
let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort"));
|
||||
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||
let provides = Collection::with_items(arena.alloc([provide_entry]));
|
||||
let module_name = StrLiteral::PlainLine("quicksort");
|
||||
|
||||
let header = AppHeader {
|
||||
|
@ -3222,11 +3222,40 @@ mod test_parse {
|
|||
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
|
||||
let arena = Bump::new();
|
||||
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
|
||||
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena));
|
||||
let loc_import = Located::new(2, 2, 14, 25, import);
|
||||
let imports = bumpalo::vec![in &arena; loc_import];
|
||||
let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort"));
|
||||
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||
let import = ImportsEntry::Package(
|
||||
"foo",
|
||||
ModuleName::new("Bar"),
|
||||
Collection::with_items_and_comments(
|
||||
&arena,
|
||||
arena.alloc([
|
||||
Located::new(
|
||||
3,
|
||||
3,
|
||||
8,
|
||||
11,
|
||||
ExposesEntry::SpaceBefore(
|
||||
arena.alloc(ExposesEntry::Exposed("Baz")),
|
||||
arena.alloc([Newline]),
|
||||
),
|
||||
),
|
||||
Located::new(
|
||||
4,
|
||||
4,
|
||||
8,
|
||||
17,
|
||||
ExposesEntry::SpaceBefore(
|
||||
arena.alloc(ExposesEntry::Exposed("FourtyTwo")),
|
||||
arena.alloc([Newline]),
|
||||
),
|
||||
),
|
||||
]),
|
||||
arena.alloc([Newline, LineComment(" I'm a happy comment")]),
|
||||
),
|
||||
);
|
||||
let loc_import = Located::new(2, 6, 14, 5, import);
|
||||
let imports = Collection::with_items(arena.alloc([loc_import]));
|
||||
let provide_entry = Located::new(7, 7, 15, 24, Exposed("quicksort"));
|
||||
let provides = Collection::with_items(arena.alloc([provide_entry]));
|
||||
let module_name = StrLiteral::PlainLine("quicksort");
|
||||
|
||||
let header = AppHeader {
|
||||
|
@ -3235,7 +3264,7 @@ mod test_parse {
|
|||
packages,
|
||||
imports,
|
||||
provides,
|
||||
to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")),
|
||||
to: Located::new(7, 7, 31, 35, To::ExistingPackage("base")),
|
||||
after_app_keyword: &[],
|
||||
before_packages: newlines,
|
||||
after_packages: &[],
|
||||
|
@ -3253,8 +3282,12 @@ mod test_parse {
|
|||
r#"
|
||||
app "quicksort"
|
||||
packages { base: "./platform", }
|
||||
imports [ foo.Bar.Baz ]
|
||||
provides [ quicksort ] to base
|
||||
imports [ foo.Bar.{
|
||||
Baz,
|
||||
FourtyTwo,
|
||||
# I'm a happy comment
|
||||
} ]
|
||||
provides [ quicksort, ] to base
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -3285,7 +3318,7 @@ mod test_parse {
|
|||
let region2 = Region::new(0, 0, 45, 47);
|
||||
|
||||
PlatformRequires {
|
||||
rigids: Vec::new_in(&arena),
|
||||
rigids: Collection::empty(),
|
||||
signature: Located::at(
|
||||
region1,
|
||||
TypedIdent::Entry {
|
||||
|
@ -3307,10 +3340,10 @@ mod test_parse {
|
|||
before_header: &[],
|
||||
name: Located::new(0, 0, 9, 23, pkg_name),
|
||||
requires,
|
||||
exposes: Vec::new_in(&arena),
|
||||
exposes: Collection::empty(),
|
||||
packages: Collection::empty(),
|
||||
imports: Vec::new_in(&arena),
|
||||
provides: Vec::new_in(&arena),
|
||||
imports: Collection::empty(),
|
||||
provides: Collection::empty(),
|
||||
effects,
|
||||
after_platform_keyword: &[],
|
||||
before_requires: &[],
|
||||
|
@ -3352,9 +3385,9 @@ mod test_parse {
|
|||
let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry);
|
||||
let arena = Bump::new();
|
||||
let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
|
||||
let imports = Vec::new_in(&arena);
|
||||
let imports = Collection::empty();
|
||||
let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost"));
|
||||
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||
let provides = Collection::with_items(arena.alloc([provide_entry]));
|
||||
let effects = Effects {
|
||||
effect_type_name: "Effect",
|
||||
effect_shortname: "fx",
|
||||
|
@ -3370,7 +3403,13 @@ mod test_parse {
|
|||
let region3 = Region::new(1, 1, 14, 26);
|
||||
|
||||
PlatformRequires {
|
||||
rigids: bumpalo::vec![ in &arena; Located::at(region3, PlatformRigid::Entry { alias: "Model", rigid: "model" }) ],
|
||||
rigids: Collection::with_items(arena.alloc([Located::at(
|
||||
region3,
|
||||
PlatformRigid::Entry {
|
||||
alias: "Model",
|
||||
rigid: "model",
|
||||
},
|
||||
)])),
|
||||
signature: Located::at(
|
||||
region1,
|
||||
TypedIdent::Entry {
|
||||
|
@ -3392,7 +3431,7 @@ mod test_parse {
|
|||
before_header: &[],
|
||||
name: Located::new(0, 0, 9, 19, pkg_name),
|
||||
requires,
|
||||
exposes: Vec::new_in(&arena),
|
||||
exposes: Collection::empty(),
|
||||
packages,
|
||||
imports,
|
||||
provides,
|
||||
|
@ -3432,8 +3471,8 @@ mod test_parse {
|
|||
#[test]
|
||||
fn empty_interface_header() {
|
||||
let arena = Bump::new();
|
||||
let exposes = Vec::new_in(&arena);
|
||||
let imports = Vec::new_in(&arena);
|
||||
let exposes = Collection::empty();
|
||||
let imports = Collection::empty();
|
||||
let module_name = ModuleName::new("Foo");
|
||||
let header = InterfaceHeader {
|
||||
before_header: &[],
|
||||
|
@ -3464,8 +3503,8 @@ mod test_parse {
|
|||
#[test]
|
||||
fn nested_module() {
|
||||
let arena = Bump::new();
|
||||
let exposes = Vec::new_in(&arena);
|
||||
let imports = Vec::new_in(&arena);
|
||||
let exposes = Collection::empty();
|
||||
let imports = Collection::empty();
|
||||
let module_name = ModuleName::new("Foo.Bar.Baz");
|
||||
let header = InterfaceHeader {
|
||||
before_header: &[],
|
||||
|
|
|
@ -3093,6 +3093,7 @@ fn to_provides_report<'a>(
|
|||
use roc_parse::parser::EProvides;
|
||||
|
||||
match *parse_problem {
|
||||
EProvides::ListEnd(row, col) | // TODO: give this its own error message
|
||||
EProvides::Identifier(row, col) => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_row_col(row, col);
|
||||
|
@ -3158,6 +3159,7 @@ fn to_exposes_report<'a>(
|
|||
use roc_parse::parser::EExposes;
|
||||
|
||||
match *parse_problem {
|
||||
EExposes::ListEnd(row, col) | // TODO: give this its own error message
|
||||
EExposes::Identifier(row, col) => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_row_col(row, col);
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::helpers::wasm::assert_evals_to;
|
|||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn basic_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -45,7 +45,7 @@ fn basic_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn f64_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -137,7 +137,7 @@ fn fn_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn def_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -192,7 +192,7 @@ fn when_on_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn when_record_with_guard_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -207,7 +207,7 @@ fn when_record_with_guard_pattern() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn let_with_record_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -223,7 +223,7 @@ fn let_with_record_pattern() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn record_guard_pattern() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -239,7 +239,7 @@ fn record_guard_pattern() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn twice_record_access() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -254,7 +254,7 @@ fn twice_record_access() {
|
|||
);
|
||||
}
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
fn empty_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -873,7 +873,7 @@ fn update_single_element_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn booleans_in_record() {
|
||||
assert_evals_to!(
|
||||
indoc!("{ x: 1 == 1, y: 1 == 1 }"),
|
||||
|
@ -908,7 +908,7 @@ fn alignment_in_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn blue_and_present() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -927,7 +927,7 @@ fn blue_and_present() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn blue_and_absent() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue