Merge branch 'trunk' into builtins-refactor-list-take

This commit is contained in:
satotake 2021-11-13 03:38:29 +00:00 committed by GitHub
commit 4359dcff73
29 changed files with 593 additions and 424 deletions

View file

@ -51,3 +51,4 @@ Eric Newbury <enewbury@users.noreply.github.com>
Ayaz Hafiz <ayaz.hafiz.1@gmail.com> Ayaz Hafiz <ayaz.hafiz.1@gmail.com>
Johannes Maas <github@j-maas.de> Johannes Maas <github@j-maas.de>
Takeshi Sato <doublequotation@gmail.com> Takeshi Sato <doublequotation@gmail.com>
Joost Baas <joost@joostbaas.eu>

View file

@ -395,7 +395,8 @@ pub fn to_type2<'a>(
Type2::Variable(var) Type2::Variable(var)
} }
Record { fields, ext, .. } => { Record { fields, ext, .. } => {
let field_types_map = can_assigned_fields(env, scope, references, fields, region); let field_types_map =
can_assigned_fields(env, scope, references, &fields.items, region);
let field_types = PoolVec::with_capacity(field_types_map.len() as u32, env.pool); let field_types = PoolVec::with_capacity(field_types_map.len() as u32, env.pool);

View file

@ -863,6 +863,7 @@ fn get_macos_version() -> String {
.expect("Failed to convert output of command 'sw_vers -productVersion' into a utf8 string"); .expect("Failed to convert output of command 'sw_vers -productVersion' into a utf8 string");
full_version_string full_version_string
.trim_end()
.split('.') .split('.')
.take(2) .take(2)
.collect::<Vec<&str>>() .collect::<Vec<&str>>()

View file

@ -1388,6 +1388,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(flex(TVAR1)), Box::new(flex(TVAR1)),
); );
// isOk : Result * * -> bool
add_top_level_function_type!(
Symbol::RESULT_IS_OK,
vec![result_type(flex(TVAR1), flex(TVAR3))],
Box::new(bool_type()),
);
types types
} }

View file

@ -389,7 +389,7 @@ fn can_annotation_help(
Record { fields, ext, .. } => { Record { fields, ext, .. } => {
let field_types = can_assigned_fields( let field_types = can_assigned_fields(
env, env,
fields, &fields.items,
region, region,
scope, scope,
var_store, var_store,

View file

@ -194,6 +194,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
RESULT_MAP_ERR => result_map_err, RESULT_MAP_ERR => result_map_err,
RESULT_AFTER => result_after, RESULT_AFTER => result_after,
RESULT_WITH_DEFAULT => result_with_default, RESULT_WITH_DEFAULT => result_with_default,
RESULT_IS_OK => result_is_ok,
} }
} }
@ -4162,6 +4163,83 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def {
let ret_var = var_store.fresh();
let result_var = var_store.fresh();
let mut branches = vec![];
{
// ok branch
let tag_name = TagName::Global("Ok".into());
let pattern = Pattern::AppliedTag {
whole_var: result_var,
ext_var: var_store.fresh(),
tag_name,
arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))],
};
let true_expr = Tag {
variant_var: var_store.fresh(),
ext_var: var_store.fresh(),
name: TagName::Global("True".into()),
arguments: vec![],
};
let branch = WhenBranch {
patterns: vec![no_region(pattern)],
value: no_region(true_expr),
guard: None,
};
branches.push(branch);
}
{
// err branch
let tag_name = TagName::Global("Err".into());
let pattern = Pattern::AppliedTag {
whole_var: result_var,
ext_var: var_store.fresh(),
tag_name,
arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))],
};
let false_expr = Tag {
variant_var: var_store.fresh(),
ext_var: var_store.fresh(),
name: TagName::Global("False".into()),
arguments: vec![],
};
let branch = WhenBranch {
patterns: vec![no_region(pattern)],
value: no_region(false_expr),
guard: None,
};
branches.push(branch);
}
let body = When {
cond_var: result_var,
expr_var: ret_var,
region: Region::zero(),
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
branches,
};
defn(
symbol,
vec![(result_var, Symbol::ARG_1)],
var_store,
body,
ret_var,
)
}
fn result_after(symbol: Symbol, var_store: &mut VarStore) -> Def { fn result_after(symbol: Symbol, var_store: &mut VarStore) -> Def {
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let func_var = var_store.fresh(); let func_var = var_store.fresh();

View file

@ -1,6 +1,6 @@
use crate::spaces::{fmt_comments_only, fmt_spaces, newline, NewlineAt, INDENT}; use crate::spaces::{fmt_comments_only, fmt_spaces, newline, NewlineAt, INDENT};
use bumpalo::collections::String; use bumpalo::collections::String;
use roc_parse::ast::{AssignedField, Expr, Tag, TypeAnnotation}; use roc_parse::ast::{AssignedField, Collection, Expr, Tag, TypeAnnotation};
use roc_region::all::Located; use roc_region::all::Located;
/// Does an AST node need parens around it? /// Does an AST node need parens around it?
@ -183,17 +183,13 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> {
Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()), Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()),
As(lhs, _, rhs) => lhs.value.is_multiline() || rhs.value.is_multiline(), As(lhs, _, rhs) => lhs.value.is_multiline() || rhs.value.is_multiline(),
Record { Record { fields, ext } => {
fields,
ext,
final_comments: _,
} => {
match ext { match ext {
Some(ann) if ann.value.is_multiline() => return true, Some(ann) if ann.value.is_multiline() => return true,
_ => {} _ => {}
} }
fields.iter().any(|field| field.value.is_multiline()) fields.items.iter().any(|field| field.value.is_multiline())
} }
TagUnion { TagUnion {
@ -296,16 +292,19 @@ impl<'a> Formattable<'a> for TypeAnnotation<'a> {
} }
Record { Record {
fields, fields:
ext, Collection {
items,
final_comments, final_comments,
},
ext,
} => { } => {
format_sequence!( format_sequence!(
buf, buf,
indent, indent,
'{', '{',
'}', '}',
fields, items,
final_comments, final_comments,
newlines, newlines,
AssignedField AssignedField

View file

@ -4,7 +4,7 @@ use code_builder::Align;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt}; use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
use roc_mono::layout::{Layout, LayoutIds}; use roc_mono::layout::{Builtin, Layout, LayoutIds};
use crate::layout::WasmLayout; use crate::layout::WasmLayout;
use crate::low_level::{build_call_low_level, LowlevelBuildResult}; use crate::low_level::{build_call_low_level, LowlevelBuildResult};
@ -294,16 +294,17 @@ impl<'a> WasmBackend<'a> {
_ => { _ => {
self.storage.load_symbols(&mut self.code_builder, &[*sym]); self.storage.load_symbols(&mut self.code_builder, &[*sym]);
self.code_builder.br(self.block_depth); // jump to end of function (for stack frame pop)
} }
} }
// jump to the "stack frame pop" code at the end of the function
self.code_builder.br(self.block_depth - 1);
Ok(()) Ok(())
} }
Stmt::Switch { Stmt::Switch {
cond_symbol, cond_symbol,
cond_layout: _, cond_layout,
branches, branches,
default_branch, default_branch,
ret_layout: _, ret_layout: _,
@ -321,21 +322,45 @@ impl<'a> WasmBackend<'a> {
cond_storage, cond_storage,
); );
// create (number_of_branches - 1) new blocks. // create a block for each branch except the default
for _ in 0..branches.len() { for _ in 0..branches.len() {
self.start_block(BlockType::NoResult) self.start_block(BlockType::NoResult)
} }
let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Int1));
let cond_type = WasmLayout::new(cond_layout).value_type();
// then, we jump whenever the value under scrutiny is equal to the value of a branch // then, we jump whenever the value under scrutiny is equal to the value of a branch
for (i, (value, _, _)) in branches.iter().enumerate() { for (i, (value, _, _)) in branches.iter().enumerate() {
// put the cond_symbol on the top of the stack // put the cond_symbol on the top of the stack
self.storage self.storage
.load_symbols(&mut self.code_builder, &[*cond_symbol]); .load_symbols(&mut self.code_builder, &[*cond_symbol]);
if is_bool {
// We already have a bool, don't need to compare against a const to get one
if *value == 0 {
self.code_builder.i32_eqz();
}
} else {
match cond_type {
ValueType::I32 => {
self.code_builder.i32_const(*value as i32); self.code_builder.i32_const(*value as i32);
// compare the 2 topmost values
self.code_builder.i32_eq(); self.code_builder.i32_eq();
}
ValueType::I64 => {
self.code_builder.i64_const(*value as i64);
self.code_builder.i64_eq();
}
ValueType::F32 => {
self.code_builder.f32_const(f32::from_bits(*value as u32));
self.code_builder.f32_eq();
}
ValueType::F64 => {
self.code_builder.f64_const(f64::from_bits(*value as u64));
self.code_builder.f64_eq();
}
}
}
// "break" out of `i` surrounding blocks // "break" out of `i` surrounding blocks
self.code_builder.br_if(i as u32); self.code_builder.br_if(i as u32);

View file

@ -202,10 +202,10 @@ impl<'a> CodeBuilder<'a> {
true true
} }
fn add_insertion(&mut self, insert_at: usize, opcode: u8, immediate: u32) { fn add_insertion(&mut self, insert_at: usize, opcode: OpCode, immediate: u32) {
let start = self.insert_bytes.len(); let start = self.insert_bytes.len();
self.insert_bytes.push(opcode); self.insert_bytes.push(opcode as u8);
self.insert_bytes.encode_u32(immediate); self.insert_bytes.encode_u32(immediate);
self.insertions.push(Insertion { self.insertions.push(Insertion {
@ -213,6 +213,8 @@ impl<'a> CodeBuilder<'a> {
start, start,
end: self.insert_bytes.len(), end: self.insert_bytes.len(),
}); });
// println!("insert {:?} {} at byte offset {} ", opcode, immediate, insert_at);
} }
/// Load a Symbol that is stored in the VM stack /// Load a Symbol that is stored in the VM stack
@ -244,14 +246,14 @@ impl<'a> CodeBuilder<'a> {
// Symbol is not on top of the stack. Find it. // Symbol is not on top of the stack. Find it.
if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) { if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) {
// Insert a local.set where the value was created // Insert a local.set where the value was created
self.add_insertion(pushed_at, SETLOCAL as u8, next_local_id.0); self.add_insertion(pushed_at, SETLOCAL, next_local_id.0);
// Take the value out of the stack where local.set was inserted // Take the value out of the stack where local.set was inserted
self.vm_stack.remove(found_index); self.vm_stack.remove(found_index);
// Insert a local.get at the current position // Insert a local.get at the current position
self.get_local(next_local_id); self.get_local(next_local_id);
self.vm_stack.push(symbol); self.set_top_symbol(symbol);
// This Symbol is no longer stored in the VM stack, but in a local // This Symbol is no longer stored in the VM stack, but in a local
None None
@ -267,11 +269,11 @@ impl<'a> CodeBuilder<'a> {
Popped { pushed_at } => { Popped { pushed_at } => {
// This Symbol is being used for a second time // This Symbol is being used for a second time
// Insert a local.tee where it was pushed, so we don't interfere with the first usage // Insert a local.tee where it was pushed, so we don't interfere with the first usage
self.add_insertion(pushed_at, TEELOCAL as u8, next_local_id.0); self.add_insertion(pushed_at, TEELOCAL, next_local_id.0);
// Insert a local.get at the current position // Insert a local.get at the current position
self.get_local(next_local_id); self.get_local(next_local_id);
self.vm_stack.push(symbol); self.set_top_symbol(symbol);
// This symbol has been promoted to a Local // This symbol has been promoted to a Local
// Tell the caller it no longer has a VirtualMachineSymbolState // Tell the caller it no longer has a VirtualMachineSymbolState
@ -437,10 +439,12 @@ impl<'a> CodeBuilder<'a> {
let new_len = self.vm_stack.len() - pops as usize; let new_len = self.vm_stack.len() - pops as usize;
self.vm_stack.truncate(new_len); self.vm_stack.truncate(new_len);
if push { if push {
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); self.vm_stack.push(Symbol::WASM_TMP);
} }
self.code.push(opcode as u8); self.code.push(opcode as u8);
// println!("{:10}\t{:?}", format!("{:?}", opcode), &self.vm_stack);
} }
fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) { fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) {
@ -516,25 +520,14 @@ impl<'a> CodeBuilder<'a> {
n_args: usize, n_args: usize,
has_return_val: bool, has_return_val: bool,
) { ) {
let stack_depth = self.vm_stack.len(); self.inst(CALL, n_args, has_return_val);
if n_args > stack_depth {
panic!(
"Trying to call to call function {:?} with {:?} values but only {:?} on the VM stack\n{:?}",
function_index, n_args, stack_depth, self
);
}
self.vm_stack.truncate(stack_depth - n_args);
if has_return_val {
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE);
}
self.code.push(CALL as u8);
// Write the index of the function to be called.
// Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name.
// Here we initialise the offset to an index of self.code. After completing the function, we'll add
// other factors to make it relative to the code section. (All insertions will be known then.)
let offset = self.code.len() as u32; let offset = self.code.len() as u32;
self.code.encode_padded_u32(function_index); self.code.encode_padded_u32(function_index);
// Make a RelocationEntry so the linker can see that this byte offset relates to a function by name.
// Here we initialise the offset to an index of self.code. After completing the function, we'll add
// other factors to make it relative to the code section. (All insertions will be known then.)
self.relocations.push(RelocationEntry::Index { self.relocations.push(RelocationEntry::Index {
type_id: IndexRelocType::FunctionIndexLeb, type_id: IndexRelocType::FunctionIndexLeb,
offset, offset,

View file

@ -1,5 +1,5 @@
#[repr(u8)] #[repr(u8)]
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub enum OpCode { pub enum OpCode {
UNREACHABLE = 0x00, UNREACHABLE = 0x00,
NOP = 0x01, NOP = 0x01,

View file

@ -293,16 +293,12 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
Apply { name, parts } Apply { name, parts }
} }
ast::TypeAnnotation::Record { ast::TypeAnnotation::Record { fields, ext } => {
fields,
ext,
final_comments: _,
} => {
let mut doc_fields = Vec::new(); let mut doc_fields = Vec::new();
let mut any_fields_include_private_tags = false; let mut any_fields_include_private_tags = false;
for field in fields { for field in fields.items {
match record_field_to_doc(in_func_type_ann, field.value) { match record_field_to_doc(in_func_type_ann, field.value) {
None => { None => {
any_fields_include_private_tags = true; any_fields_include_private_tags = true;

View file

@ -2630,7 +2630,7 @@ fn parse_header<'a>(
std::str::from_utf8_unchecked(&src_bytes[..chomped]) std::str::from_utf8_unchecked(&src_bytes[..chomped])
}; };
let packages = header.packages.into_bump_slice(); let packages = header.packages.items;
let info = HeaderInfo { let info = HeaderInfo {
loc_name: Located { loc_name: Located {

View file

@ -875,8 +875,8 @@ define_builtins! {
// used by the dev backend to store the pointer to where to store large return types // used by the dev backend to store the pointer to where to store large return types
23 RET_POINTER: "#ret_pointer" 23 RET_POINTER: "#ret_pointer"
// used in wasm dev backend to mark values in the VM stack that have no other Symbol // used in wasm dev backend to mark temporary values in the VM stack
24 WASM_ANONYMOUS_STACK_VALUE: "#wasm_anonymous_stack_value" 24 WASM_TMP: "#wasm_tmp"
} }
1 NUM: "Num" => { 1 NUM: "Num" => {
0 NUM_NUM: "Num" imported // the Num.Num type alias 0 NUM_NUM: "Num" imported // the Num.Num type alias
@ -1082,6 +1082,7 @@ define_builtins! {
2 RESULT_MAP_ERR: "mapErr" 2 RESULT_MAP_ERR: "mapErr"
3 RESULT_WITH_DEFAULT: "withDefault" 3 RESULT_WITH_DEFAULT: "withDefault"
4 RESULT_AFTER: "after" 4 RESULT_AFTER: "after"
5 RESULT_IS_OK: "isOk"
} }
6 DICT: "Dict" => { 6 DICT: "Dict" => {
0 DICT_DICT: "Dict" imported // the Dict.Dict type alias 0 DICT_DICT: "Dict" imported // the Dict.Dict type alias

View file

@ -5,6 +5,28 @@ use bumpalo::Bump;
use roc_module::operator::{BinOp, CalledVia, UnaryOp}; use roc_module::operator::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Loc, Position, Region}; use roc_region::all::{Loc, Position, Region};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Collection<'a, T> {
pub items: &'a [T],
pub final_comments: &'a [CommentOrNewline<'a>],
}
impl<'a, T> Collection<'a, T> {
pub fn empty() -> Collection<'a, T> {
Collection {
items: &[],
final_comments: &[],
}
}
pub fn with_items(items: &'a [T]) -> Collection<'a, T> {
Collection {
items,
final_comments: &[],
}
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Module<'a> { pub enum Module<'a> {
Interface { header: InterfaceHeader<'a> }, Interface { header: InterfaceHeader<'a> },
@ -231,11 +253,11 @@ pub enum TypeAnnotation<'a> {
), ),
Record { Record {
fields: &'a [Loc<AssignedField<'a, TypeAnnotation<'a>>>], fields: Collection<'a, Loc<AssignedField<'a, TypeAnnotation<'a>>>>,
/// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`. /// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`.
/// This is None if it's a closed record annotation like `{ name: Str }`. /// This is None if it's a closed record annotation like `{ name: Str }`.
ext: Option<&'a Loc<TypeAnnotation<'a>>>, ext: Option<&'a Loc<TypeAnnotation<'a>>>,
final_comments: &'a [CommentOrNewline<'a>], // final_comments: &'a [CommentOrNewline<'a>],
}, },
/// A tag union, e.g. `[ /// A tag union, e.g. `[

View file

@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Ident};
use crate::keyword; use crate::keyword;
use crate::parser::{ use crate::parser::{
self, backtrackable, optional, sep_by1, sep_by1_e, specialize, specialize_ref, then, self, backtrackable, optional, sep_by1, sep_by1_e, specialize, specialize_ref, then,
trailing_sep_by0, word1, word2, EExpr, EInParens, ELambda, EPattern, ERecord, EString, Either, trailing_sep_by0, word1, word2, EExpect, EExpr, EIf, EInParens, ELambda, EList, ENumber,
Expect, If, List, Number, ParseResult, Parser, State, Type, When, EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser, State,
}; };
use crate::pattern::loc_closure_param; use crate::pattern::loc_closure_param;
use crate::type_annotation; use crate::type_annotation;
@ -801,7 +801,7 @@ fn parse_defs_end<'a>(
Err((NoProgress, _, _)) => { Err((NoProgress, _, _)) => {
let start = state.get_position(); let start = state.get_position();
match crate::parser::keyword_e(crate::keyword::EXPECT, Expect::Expect) match crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect)
.parse(arena, state) .parse(arena, state)
{ {
Err((_, _, _)) => { Err((_, _, _)) => {
@ -861,8 +861,8 @@ fn parse_defs_end<'a>(
space0_before_e( space0_before_e(
type_annotation::located_help(min_indent + 1), type_annotation::located_help(min_indent + 1),
min_indent + 1, min_indent + 1,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
), ),
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -1099,8 +1099,8 @@ fn parse_expr_operator<'a>(
space0_before_e( space0_before_e(
type_annotation::located_help(indented_more), type_annotation::located_help(indented_more),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
), ),
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -1126,8 +1126,8 @@ fn parse_expr_operator<'a>(
space0_before_e( space0_before_e(
type_annotation::located_help(indented_more), type_annotation::located_help(indented_more),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
), ),
); );
@ -1651,21 +1651,21 @@ mod when {
pub fn expr_help<'a>( pub fn expr_help<'a>(
min_indent: u16, min_indent: u16,
options: ExprParseOptions, options: ExprParseOptions,
) -> impl Parser<'a, Expr<'a>, When<'a>> { ) -> impl Parser<'a, Expr<'a>, EWhen<'a>> {
then( then(
and!( and!(
when_with_indent(), when_with_indent(),
skip_second!( skip_second!(
space0_around_ee( space0_around_ee(
specialize_ref(When::Condition, move |arena, state| { specialize_ref(EWhen::Condition, move |arena, state| {
parse_loc_expr_with_options(min_indent, options, arena, state) parse_loc_expr_with_options(min_indent, options, arena, state)
}), }),
min_indent, min_indent,
When::Space, EWhen::Space,
When::IndentCondition, EWhen::IndentCondition,
When::IndentIs, EWhen::IndentIs,
), ),
parser::keyword_e(keyword::IS, When::Is) parser::keyword_e(keyword::IS, EWhen::Is)
) )
), ),
move |arena, state, progress, (case_indent, loc_condition)| { move |arena, state, progress, (case_indent, loc_condition)| {
@ -1673,7 +1673,7 @@ mod when {
return Err(( return Err((
progress, progress,
// TODO maybe pass case_indent here? // TODO maybe pass case_indent here?
When::PatternAlignment(5, state.line, state.column), EWhen::PatternAlignment(5, state.line, state.column),
state, state,
)); ));
} }
@ -1693,9 +1693,9 @@ mod when {
} }
/// Parsing when with indentation. /// Parsing when with indentation.
fn when_with_indent<'a>() -> impl Parser<'a, u16, When<'a>> { fn when_with_indent<'a>() -> impl Parser<'a, u16, EWhen<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| {
parser::keyword_e(keyword::WHEN, When::When) parser::keyword_e(keyword::WHEN, EWhen::When)
.parse(arena, state) .parse(arena, state)
.map(|(progress, (), state)| (progress, state.indent_col, state)) .map(|(progress, (), state)| (progress, state.indent_col, state))
} }
@ -1704,7 +1704,7 @@ mod when {
fn branches<'a>( fn branches<'a>(
min_indent: u16, min_indent: u16,
options: ExprParseOptions, options: ExprParseOptions,
) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, When<'a>> { ) -> impl Parser<'a, Vec<'a, &'a WhenBranch<'a>>, EWhen<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| {
let when_indent = state.indent_col; let when_indent = state.indent_col;
@ -1741,7 +1741,7 @@ mod when {
let indent = pattern_indent_level - indent_col; let indent = pattern_indent_level - indent_col;
Err(( Err((
MadeProgress, MadeProgress,
When::PatternAlignment(indent, state.line, state.column), EWhen::PatternAlignment(indent, state.line, state.column),
state, state,
)) ))
} }
@ -1799,7 +1799,7 @@ mod when {
(Col, Vec<'a, Located<Pattern<'a>>>), (Col, Vec<'a, Located<Pattern<'a>>>),
Option<Located<Expr<'a>>>, Option<Located<Expr<'a>>>,
), ),
When<'a>, EWhen<'a>,
> { > {
let options = ExprParseOptions { let options = ExprParseOptions {
check_for_arrow: false, check_for_arrow: false,
@ -1810,16 +1810,16 @@ mod when {
one_of![ one_of![
map!( map!(
skip_first!( skip_first!(
parser::keyword_e(keyword::IF, When::IfToken), parser::keyword_e(keyword::IF, EWhen::IfToken),
// TODO we should require space before the expression but not after // TODO we should require space before the expression but not after
space0_around_ee( space0_around_ee(
specialize_ref(When::IfGuard, move |arena, state| { specialize_ref(EWhen::IfGuard, move |arena, state| {
parse_loc_expr_with_options(min_indent + 1, options, arena, state) parse_loc_expr_with_options(min_indent + 1, options, arena, state)
}), }),
min_indent, min_indent,
When::Space, EWhen::Space,
When::IndentIfGuard, EWhen::IndentIfGuard,
When::IndentArrow, EWhen::IndentArrow,
) )
), ),
Some Some
@ -1831,17 +1831,17 @@ mod when {
fn branch_single_alternative<'a>( fn branch_single_alternative<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, Located<Pattern<'a>>, When<'a>> { ) -> impl Parser<'a, Located<Pattern<'a>>, EWhen<'a>> {
move |arena, state| { move |arena, state| {
let (_, spaces, state) = let (_, spaces, state) =
backtrackable(space0_e(min_indent, When::Space, When::IndentPattern)) backtrackable(space0_e(min_indent, EWhen::Space, EWhen::IndentPattern))
.parse(arena, state)?; .parse(arena, state)?;
let (_, loc_pattern, state) = space0_after_e( let (_, loc_pattern, state) = space0_after_e(
specialize(When::Pattern, crate::pattern::loc_pattern_help(min_indent)), specialize(EWhen::Pattern, crate::pattern::loc_pattern_help(min_indent)),
min_indent, min_indent,
When::Space, EWhen::Space,
When::IndentPattern, EWhen::IndentPattern,
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -1862,12 +1862,12 @@ mod when {
fn branch_alternatives_help<'a>( fn branch_alternatives_help<'a>(
min_indent: u16, min_indent: u16,
pattern_indent_level: Option<u16>, pattern_indent_level: Option<u16>,
) -> impl Parser<'a, (Col, Vec<'a, Located<Pattern<'a>>>), When<'a>> { ) -> impl Parser<'a, (Col, Vec<'a, Located<Pattern<'a>>>), EWhen<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| {
let initial = state; let initial = state;
// put no restrictions on the indent after the spaces; we'll check it manually // put no restrictions on the indent after the spaces; we'll check it manually
match space0_e(0, When::Space, When::IndentPattern).parse(arena, state) { match space0_e(0, EWhen::Space, EWhen::IndentPattern).parse(arena, state) {
Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)), Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)),
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)), Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
Ok((_progress, spaces, state)) => { Ok((_progress, spaces, state)) => {
@ -1876,7 +1876,7 @@ mod when {
// this branch is indented too much // this branch is indented too much
Err(( Err((
NoProgress, NoProgress,
When::IndentPattern(state.line, state.column), EWhen::IndentPattern(state.line, state.column),
initial, initial,
)) ))
} }
@ -1884,7 +1884,7 @@ mod when {
let indent = wanted - state.column; let indent = wanted - state.column;
Err(( Err((
NoProgress, NoProgress,
When::PatternAlignment(indent, state.line, state.column), EWhen::PatternAlignment(indent, state.line, state.column),
initial, initial,
)) ))
} }
@ -1896,7 +1896,7 @@ mod when {
let pattern_indent_col = state.column; let pattern_indent_col = state.column;
let parser = sep_by1( let parser = sep_by1(
word1(b'|', When::Bar), word1(b'|', EWhen::Bar),
branch_single_alternative(pattern_indent + 1), branch_single_alternative(pattern_indent + 1),
); );
@ -1930,16 +1930,16 @@ mod when {
} }
/// Parsing the righthandside of a branch in a when conditional. /// Parsing the righthandside of a branch in a when conditional.
fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located<Expr<'a>>, When<'a>> { fn branch_result<'a>(indent: u16) -> impl Parser<'a, Located<Expr<'a>>, EWhen<'a>> {
skip_first!( skip_first!(
word2(b'-', b'>', When::Arrow), word2(b'-', b'>', EWhen::Arrow),
space0_before_e( space0_before_e(
specialize_ref(When::Branch, move |arena, state| parse_loc_expr( specialize_ref(EWhen::Branch, move |arena, state| parse_loc_expr(
indent, arena, state indent, arena, state
)), )),
indent, indent,
When::Space, EWhen::Space,
When::IndentBranch, EWhen::IndentBranch,
) )
) )
} }
@ -1947,38 +1947,38 @@ mod when {
fn if_branch<'a>( fn if_branch<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), If<'a>> { ) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), EIf<'a>> {
move |arena, state| { move |arena, state| {
// NOTE: only parse spaces before the expression // NOTE: only parse spaces before the expression
let (_, cond, state) = space0_around_ee( let (_, cond, state) = space0_around_ee(
specialize_ref(If::Condition, move |arena, state| { specialize_ref(EIf::Condition, move |arena, state| {
parse_loc_expr(min_indent, arena, state) parse_loc_expr(min_indent, arena, state)
}), }),
min_indent, min_indent,
If::Space, EIf::Space,
If::IndentCondition, EIf::IndentCondition,
If::IndentThenToken, EIf::IndentThenToken,
) )
.parse(arena, state) .parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then) let (_, _, state) = parser::keyword_e(keyword::THEN, EIf::Then)
.parse(arena, state) .parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
let (_, then_branch, state) = space0_around_ee( let (_, then_branch, state) = space0_around_ee(
specialize_ref(If::ThenBranch, move |arena, state| { specialize_ref(EIf::ThenBranch, move |arena, state| {
parse_loc_expr(min_indent, arena, state) parse_loc_expr(min_indent, arena, state)
}), }),
min_indent, min_indent,
If::Space, EIf::Space,
If::IndentThenBranch, EIf::IndentThenBranch,
If::IndentElseToken, EIf::IndentElseToken,
) )
.parse(arena, state) .parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else) let (_, _, state) = parser::keyword_e(keyword::ELSE, EIf::Else)
.parse(arena, state) .parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
@ -1989,26 +1989,26 @@ fn if_branch<'a>(
fn expect_help<'a>( fn expect_help<'a>(
min_indent: u16, min_indent: u16,
options: ExprParseOptions, options: ExprParseOptions,
) -> impl Parser<'a, Expr<'a>, Expect<'a>> { ) -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
move |arena: &'a Bump, state: State<'a>| { move |arena: &'a Bump, state: State<'a>| {
let start = state.get_position(); let start = state.get_position();
let (_, _, state) = let (_, _, state) =
parser::keyword_e(keyword::EXPECT, Expect::Expect).parse(arena, state)?; parser::keyword_e(keyword::EXPECT, EExpect::Expect).parse(arena, state)?;
let (_, condition, state) = space0_before_e( let (_, condition, state) = space0_before_e(
specialize_ref(Expect::Condition, move |arena, state| { specialize_ref(EExpect::Condition, move |arena, state| {
parse_loc_expr_with_options(start.col + 1, options, arena, state) parse_loc_expr_with_options(start.col + 1, options, arena, state)
}), }),
start.col + 1, start.col + 1,
Expect::Space, EExpect::Space,
Expect::IndentCondition, EExpect::IndentCondition,
) )
.parse(arena, state) .parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
let parse_cont = specialize_ref( let parse_cont = specialize_ref(
Expect::Continuation, EExpect::Continuation,
space0_before_e( space0_before_e(
move |a, s| parse_loc_expr(min_indent, a, s), move |a, s| parse_loc_expr(min_indent, a, s),
min_indent, min_indent,
@ -2028,9 +2028,9 @@ fn expect_help<'a>(
fn if_expr_help<'a>( fn if_expr_help<'a>(
min_indent: u16, min_indent: u16,
options: ExprParseOptions, options: ExprParseOptions,
) -> impl Parser<'a, Expr<'a>, If<'a>> { ) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
move |arena: &'a Bump, state| { move |arena: &'a Bump, state| {
let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?; let (_, _, state) = parser::keyword_e(keyword::IF, EIf::If).parse(arena, state)?;
let mut branches = Vec::with_capacity_in(1, arena); let mut branches = Vec::with_capacity_in(1, arena);
@ -2044,8 +2044,8 @@ fn if_expr_help<'a>(
// try to parse another `if` // try to parse another `if`
// NOTE this drops spaces between the `else` and the `if` // NOTE this drops spaces between the `else` and the `if`
let optional_if = and!( let optional_if = and!(
backtrackable(space0_e(min_indent, If::Space, If::IndentIf)), backtrackable(space0_e(min_indent, EIf::Space, EIf::IndentIf)),
parser::keyword_e(keyword::IF, If::If) parser::keyword_e(keyword::IF, EIf::If)
); );
match optional_if.parse(arena, state) { match optional_if.parse(arena, state) {
@ -2058,12 +2058,12 @@ fn if_expr_help<'a>(
}; };
let (_, else_branch, state) = space0_before_e( let (_, else_branch, state) = space0_before_e(
specialize_ref(If::ElseBranch, move |arena, state| { specialize_ref(EIf::ElseBranch, move |arena, state| {
parse_loc_expr_with_options(min_indent, options, arena, state) parse_loc_expr_with_options(min_indent, options, arena, state)
}), }),
min_indent, min_indent,
If::Space, EIf::Space,
If::IndentElseBranch, EIf::IndentElseBranch,
) )
.parse(arena, state_final_else) .parse(arena, state_final_else)
.map_err(|(_, f, s)| (MadeProgress, f, s))?; .map_err(|(_, f, s)| (MadeProgress, f, s))?;
@ -2147,32 +2147,33 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
} }
} }
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> { fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EList<'a>> {
move |arena, state| { move |arena, state| {
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!( let (_, elements, state) = collection_trailing_sep_e!(
word1(b'[', List::Open), word1(b'[', EList::Open),
specialize_ref(List::Expr, move |a, s| parse_loc_expr_no_multi_backpassing( specialize_ref(
min_indent, a, s EList::Expr,
)), move |a, s| parse_loc_expr_no_multi_backpassing(min_indent, a, s)
word1(b',', List::End), ),
word1(b']', List::End), word1(b',', EList::End),
word1(b']', EList::End),
min_indent, min_indent,
List::Open, EList::Open,
List::Space, EList::Space,
List::IndentEnd, EList::IndentEnd,
Expr::SpaceBefore Expr::SpaceBefore
) )
.parse(arena, state)?; .parse(arena, state)?;
let mut allocated = Vec::with_capacity_in(parsed_elems.len(), arena); let mut allocated = Vec::with_capacity_in(elements.items.len(), arena);
for parsed_elem in parsed_elems { for parsed_elem in elements.items {
allocated.push(&*arena.alloc(parsed_elem)); allocated.push(parsed_elem);
} }
let expr = Expr::List { let expr = Expr::List {
items: allocated.into_bump_slice(), items: allocated.into_bump_slice(),
final_comments, final_comments: elements.final_comments,
}; };
Ok((MadeProgress, expr, state)) Ok((MadeProgress, expr, state))
@ -2341,7 +2342,7 @@ fn string_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> {
map!(crate::string_literal::parse(), Expr::Str) map!(crate::string_literal::parse(), Expr::Str)
} }
fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> { fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
map!( map!(
crate::number_literal::positive_number_literal(), crate::number_literal::positive_number_literal(),
|literal| { |literal| {
@ -2364,7 +2365,7 @@ fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
) )
} }
fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> { fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
map!(crate::number_literal::number_literal(), |literal| { map!(crate::number_literal::number_literal(), |literal| {
use crate::number_literal::NumLiteral::*; use crate::number_literal::NumLiteral::*;

View file

@ -1,4 +1,4 @@
use crate::ast::{CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation}; use crate::ast::{Collection, CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation};
use crate::blankspace::space0_e; use crate::blankspace::space0_e;
use crate::ident::lowercase_ident; use crate::ident::lowercase_ident;
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
@ -81,7 +81,7 @@ pub enum To<'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct AppHeader<'a> { pub struct AppHeader<'a> {
pub name: Loc<StrLiteral<'a>>, pub name: Loc<StrLiteral<'a>>,
pub packages: Vec<'a, Loc<PackageEntry<'a>>>, pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>, pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>, pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
pub to: Loc<To<'a>>, pub to: Loc<To<'a>>,
@ -146,7 +146,7 @@ pub struct PlatformHeader<'a> {
pub name: Loc<PackageName<'a>>, pub name: Loc<PackageName<'a>>,
pub requires: PlatformRequires<'a>, pub requires: PlatformRequires<'a>,
pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>, pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
pub packages: Vec<'a, Loc<PackageEntry<'a>>>, pub packages: Collection<'a, Loc<PackageEntry<'a>>>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>, pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>, pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
pub effects: Effects<'a>, pub effects: Effects<'a>,

View file

@ -1,4 +1,4 @@
use crate::ast::{CommentOrNewline, Def, Module}; use crate::ast::{Collection, CommentOrNewline, Def, Module};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e}; use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::header::{ use crate::header::{
package_entry, package_name, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry, package_entry, package_name, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry,
@ -203,7 +203,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
let (_, provides, state) = let (_, provides, state) =
specialize(EHeader::Provides, provides_to()).parse(arena, state)?; specialize(EHeader::Provides, provides_to()).parse(arena, state)?;
let (before_packages, after_packages, package_entries) = match opt_pkgs { let (before_packages, after_packages, packages) = match opt_pkgs {
Some(pkgs) => { Some(pkgs) => {
let pkgs: Packages<'a> = pkgs; // rustc must be told the type here let pkgs: Packages<'a> = pkgs; // rustc must be told the type here
@ -213,7 +213,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
pkgs.entries, pkgs.entries,
) )
} }
None => (&[] as _, &[] as _, Vec::new_in(arena)), None => (&[] as _, &[] as _, Collection::empty()),
}; };
// rustc must be told the type here // rustc must be told the type here
@ -229,7 +229,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
let header = AppHeader { let header = AppHeader {
name, name,
packages: package_entries, packages,
imports, imports,
provides: provides.entries, provides: provides.entries,
to: provides.to, to: provides.to,
@ -582,11 +582,9 @@ where
#[derive(Debug)] #[derive(Debug)]
struct Packages<'a> { struct Packages<'a> {
entries: Vec<'a, Located<PackageEntry<'a>>>, entries: Collection<'a, Located<PackageEntry<'a>>>,
before_packages_keyword: &'a [CommentOrNewline<'a>], before_packages_keyword: &'a [CommentOrNewline<'a>],
after_packages_keyword: &'a [CommentOrNewline<'a>], after_packages_keyword: &'a [CommentOrNewline<'a>],
final_comments: &'a [CommentOrNewline<'a>],
} }
#[inline(always)] #[inline(always)]
@ -615,12 +613,14 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
PackageEntry::SpaceBefore PackageEntry::SpaceBefore
) )
), ),
|((before_packages_keyword, after_packages_keyword), (entries, final_comments))| { |((before_packages_keyword, after_packages_keyword), entries): (
(_, _),
Collection<'a, _>
)| {
Packages { Packages {
entries, entries,
before_packages_keyword, before_packages_keyword,
after_packages_keyword, after_packages_keyword,
final_comments,
} }
} }
) )

View file

@ -1,5 +1,5 @@
use crate::ast::Base; use crate::ast::Base;
use crate::parser::{Number, ParseResult, Parser, Progress, State}; use crate::parser::{ENumber, ParseResult, Parser, Progress, State};
pub enum NumLiteral<'a> { pub enum NumLiteral<'a> {
Float(&'a str), Float(&'a str),
@ -11,7 +11,7 @@ pub enum NumLiteral<'a> {
}, },
} }
pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> { pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
move |_arena, state: State<'a>| { move |_arena, state: State<'a>| {
match state.bytes.get(0) { match state.bytes.get(0) {
Some(first_byte) if (*first_byte as char).is_ascii_digit() => { Some(first_byte) if (*first_byte as char).is_ascii_digit() => {
@ -19,13 +19,13 @@ pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number>
} }
_ => { _ => {
// this is not a number at all // this is not a number at all
Err((Progress::NoProgress, Number::End, state)) Err((Progress::NoProgress, ENumber::End, state))
} }
} }
} }
} }
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> { pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
move |_arena, state: State<'a>| { move |_arena, state: State<'a>| {
match state.bytes.get(0) { match state.bytes.get(0) {
Some(first_byte) if *first_byte == b'-' => { Some(first_byte) if *first_byte == b'-' => {
@ -37,7 +37,7 @@ pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
} }
_ => { _ => {
// this is not a number at all // this is not a number at all
Err((Progress::NoProgress, Number::End, state)) Err((Progress::NoProgress, ENumber::End, state))
} }
} }
} }
@ -47,7 +47,7 @@ fn parse_number_base<'a>(
is_negated: bool, is_negated: bool,
bytes: &'a [u8], bytes: &'a [u8],
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, NumLiteral<'a>, Number> { ) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
match bytes.get(0..2) { match bytes.get(0..2) {
Some(b"0b") => chomp_number_base(Base::Binary, is_negated, &bytes[2..], state), Some(b"0b") => chomp_number_base(Base::Binary, is_negated, &bytes[2..], state),
Some(b"0o") => chomp_number_base(Base::Octal, is_negated, &bytes[2..], state), Some(b"0o") => chomp_number_base(Base::Octal, is_negated, &bytes[2..], state),
@ -61,13 +61,13 @@ fn chomp_number_base<'a>(
is_negative: bool, is_negative: bool,
bytes: &'a [u8], bytes: &'a [u8],
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, NumLiteral<'a>, Number> { ) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
let (_is_float, chomped) = chomp_number(bytes); let (_is_float, chomped) = chomp_number(bytes);
let string = unsafe { std::str::from_utf8_unchecked(&bytes[..chomped]) }; let string = unsafe { std::str::from_utf8_unchecked(&bytes[..chomped]) };
let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_, _| { let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_, _| {
Number::LineTooLong ENumber::LineTooLong
})?; })?;
Ok(( Ok((
@ -85,24 +85,25 @@ fn chomp_number_dec<'a>(
is_negative: bool, is_negative: bool,
bytes: &'a [u8], bytes: &'a [u8],
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, NumLiteral<'a>, Number> { ) -> ParseResult<'a, NumLiteral<'a>, ENumber> {
let (is_float, chomped) = chomp_number(bytes); let (is_float, chomped) = chomp_number(bytes);
if is_negative && chomped == 0 { if is_negative && chomped == 0 {
// we're probably actually looking at unary negation here // we're probably actually looking at unary negation here
return Err((Progress::NoProgress, Number::End, state)); return Err((Progress::NoProgress, ENumber::End, state));
} }
if !bytes.get(0).copied().unwrap_or_default().is_ascii_digit() { if !bytes.get(0).copied().unwrap_or_default().is_ascii_digit() {
// we're probably actually looking at unary negation here // we're probably actually looking at unary negation here
return Err((Progress::NoProgress, Number::End, state)); return Err((Progress::NoProgress, ENumber::End, state));
} }
let string = let string =
unsafe { std::str::from_utf8_unchecked(&state.bytes[0..chomped + is_negative as usize]) }; unsafe { std::str::from_utf8_unchecked(&state.bytes[0..chomped + is_negative as usize]) };
let new = state let new = state.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| {
.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| Number::LineTooLong)?; ENumber::LineTooLong
})?;
Ok(( Ok((
Progress::MadeProgress, Progress::MadeProgress,

View file

@ -186,7 +186,7 @@ pub enum SyntaxError<'a> {
ArgumentsBeforeEquals(Region), ArgumentsBeforeEquals(Region),
NotYetImplemented(String), NotYetImplemented(String),
Todo, Todo,
Type(Type<'a>), Type(EType<'a>),
Pattern(EPattern<'a>), Pattern(EPattern<'a>),
Expr(EExpr<'a>), Expr(EExpr<'a>),
Header(EHeader<'a>), Header(EHeader<'a>),
@ -258,7 +258,7 @@ pub enum ETypedIdent<'a> {
HasType(Row, Col), HasType(Row, Col),
IndentHasType(Row, Col), IndentHasType(Row, Col),
Name(Row, Col), Name(Row, Col),
Type(Type<'a>, Row, Col), Type(EType<'a>, Row, Col),
IndentType(Row, Col), IndentType(Row, Col),
Identifier(Row, Col), Identifier(Row, Col),
} }
@ -394,7 +394,7 @@ pub enum EExpr<'a> {
DefMissingFinalExpr(Row, Col), DefMissingFinalExpr(Row, Col),
DefMissingFinalExpr2(&'a EExpr<'a>, Row, Col), DefMissingFinalExpr2(&'a EExpr<'a>, Row, Col),
Type(Type<'a>, Row, Col), Type(EType<'a>, Row, Col),
Pattern(&'a EPattern<'a>, Row, Col), Pattern(&'a EPattern<'a>, Row, Col),
IndentDefBody(Row, Col), IndentDefBody(Row, Col),
IndentEquals(Row, Col), IndentEquals(Row, Col),
@ -409,10 +409,10 @@ pub enum EExpr<'a> {
BackpassComma(Row, Col), BackpassComma(Row, Col),
BackpassArrow(Row, Col), BackpassArrow(Row, Col),
When(When<'a>, Row, Col), When(EWhen<'a>, Row, Col),
If(If<'a>, Row, Col), If(EIf<'a>, Row, Col),
Expect(Expect<'a>, Row, Col), Expect(EExpect<'a>, Row, Col),
Lambda(ELambda<'a>, Row, Col), Lambda(ELambda<'a>, Row, Col),
Underscore(Row, Col), Underscore(Row, Col),
@ -420,15 +420,15 @@ pub enum EExpr<'a> {
InParens(EInParens<'a>, Row, Col), InParens(EInParens<'a>, Row, Col),
Record(ERecord<'a>, Row, Col), Record(ERecord<'a>, Row, Col),
Str(EString<'a>, Row, Col), Str(EString<'a>, Row, Col),
Number(Number, Row, Col), Number(ENumber, Row, Col),
List(List<'a>, Row, Col), List(EList<'a>, Row, Col),
IndentStart(Row, Col), IndentStart(Row, Col),
IndentEnd(Row, Col), IndentEnd(Row, Col),
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Number { pub enum ENumber {
End, End,
LineTooLong, LineTooLong,
} }
@ -502,7 +502,7 @@ pub enum ELambda<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum List<'a> { pub enum EList<'a> {
Open(Row, Col), Open(Row, Col),
End(Row, Col), End(Row, Col),
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
@ -514,7 +514,7 @@ pub enum List<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum When<'a> { pub enum EWhen<'a> {
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
When(Row, Col), When(Row, Col),
Is(Row, Col), Is(Row, Col),
@ -538,7 +538,7 @@ pub enum When<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum If<'a> { pub enum EIf<'a> {
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
If(Row, Col), If(Row, Col),
Then(Row, Col), Then(Row, Col),
@ -557,7 +557,7 @@ pub enum If<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expect<'a> { pub enum EExpect<'a> {
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
Expect(Row, Col), Expect(Row, Col),
Condition(&'a EExpr<'a>, Row, Col), Condition(&'a EExpr<'a>, Row, Col),
@ -575,7 +575,7 @@ pub enum EPattern<'a> {
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
PInParens(PInParens<'a>, Row, Col), PInParens(PInParens<'a>, Row, Col),
NumLiteral(Number, Row, Col), NumLiteral(ENumber, Row, Col),
IndentStart(Row, Col), IndentStart(Row, Col),
IndentEnd(Row, Col), IndentEnd(Row, Col),
@ -614,11 +614,11 @@ pub enum PInParens<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type<'a> { pub enum EType<'a> {
TRecord(TRecord<'a>, Row, Col), TRecord(ETypeRecord<'a>, Row, Col),
TTagUnion(TTagUnion<'a>, Row, Col), TTagUnion(ETypeTagUnion<'a>, Row, Col),
TInParens(TInParens<'a>, Row, Col), TInParens(ETypeInParens<'a>, Row, Col),
TApply(TApply, Row, Col), TApply(ETypeApply, Row, Col),
TBadTypeVariable(Row, Col), TBadTypeVariable(Row, Col),
TWildcard(Row, Col), TWildcard(Row, Col),
/// ///
@ -633,14 +633,14 @@ pub enum Type<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum TRecord<'a> { pub enum ETypeRecord<'a> {
End(Row, Col), End(Row, Col),
Open(Row, Col), Open(Row, Col),
Field(Row, Col), Field(Row, Col),
Colon(Row, Col), Colon(Row, Col),
Optional(Row, Col), Optional(Row, Col),
Type(&'a Type<'a>, Row, Col), Type(&'a EType<'a>, Row, Col),
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
@ -651,11 +651,11 @@ pub enum TRecord<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum TTagUnion<'a> { pub enum ETypeTagUnion<'a> {
End(Row, Col), End(Row, Col),
Open(Row, Col), Open(Row, Col),
Type(&'a Type<'a>, Row, Col), Type(&'a EType<'a>, Row, Col),
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
@ -664,11 +664,11 @@ pub enum TTagUnion<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum TInParens<'a> { pub enum ETypeInParens<'a> {
End(Row, Col), End(Row, Col),
Open(Row, Col), Open(Row, Col),
/// ///
Type(&'a Type<'a>, Row, Col), Type(&'a EType<'a>, Row, Col),
/// ///
Space(BadInputError, Row, Col), Space(BadInputError, Row, Col),
@ -678,7 +678,7 @@ pub enum TInParens<'a> {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum TApply { pub enum ETypeApply {
/// ///
StartNotUppercase(Row, Col), StartNotUppercase(Row, Col),
End(Row, Col), End(Row, Col),
@ -1300,7 +1300,12 @@ macro_rules! collection_trailing_sep_e {
} }
} }
Ok((MadeProgress, (parsed_elems, final_comments), state)) let collection = $crate::ast::Collection {
items: parsed_elems.into_bump_slice(),
final_comments,
};
Ok((MadeProgress, collection, state))
} }
) )
}; };

View file

@ -316,7 +316,7 @@ fn lowercase_ident_pattern<'a>(
#[inline(always)] #[inline(always)]
fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRecord<'a>> { fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
move |arena, state| { move |arena, state| {
let (_, (fields, final_comments), state) = collection_trailing_sep_e!( let (_, fields, state) = collection_trailing_sep_e!(
// word1_check_indent!(b'{', PRecord::Open, min_indent, PRecord::IndentOpen), // word1_check_indent!(b'{', PRecord::Open, min_indent, PRecord::IndentOpen),
word1(b'{', PRecord::Open), word1(b'{', PRecord::Open),
record_pattern_field(min_indent), record_pattern_field(min_indent),
@ -332,9 +332,9 @@ fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRec
.parse(arena, state)?; .parse(arena, state)?;
// TODO // TODO
let _unused = final_comments; let _unused = fields.final_comments;
let result = Pattern::RecordDestructure(fields.into_bump_slice()); let result = Pattern::RecordDestructure(fields.items);
Ok((MadeProgress, result, state)) Ok((MadeProgress, result, state))
} }

View file

@ -1,63 +1,67 @@
use crate::ast::{AssignedField, Tag, TypeAnnotation}; use crate::ast::{AssignedField, Collection, Tag, TypeAnnotation};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e}; use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::keyword; use crate::keyword;
use crate::parser::{ use crate::parser::{
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, ParseResult, allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, EType,
Parser, ETypeApply, ETypeInParens, ETypeRecord, ETypeTagUnion, ParseResult, Parser,
Progress::{self, *}, Progress::{self, *},
State, TApply, TInParens, TRecord, TTagUnion, Type, State,
}; };
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
pub fn located_help<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { pub fn located_help<'a>(
min_indent: u16,
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
expression(min_indent) expression(min_indent)
} }
#[inline(always)] #[inline(always)]
fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TTagUnion<'a>> { fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
move |arena, state| { move |arena, state| {
let (_, (tags, final_comments), state) = collection_trailing_sep_e!( let (_, tags, state) = collection_trailing_sep_e!(
word1(b'[', TTagUnion::Open), word1(b'[', ETypeTagUnion::Open),
loc!(tag_type(min_indent)), loc!(tag_type(min_indent)),
word1(b',', TTagUnion::End), word1(b',', ETypeTagUnion::End),
word1(b']', TTagUnion::End), word1(b']', ETypeTagUnion::End),
min_indent, min_indent,
TTagUnion::Open, ETypeTagUnion::Open,
TTagUnion::Space, ETypeTagUnion::Space,
TTagUnion::IndentEnd, ETypeTagUnion::IndentEnd,
Tag::SpaceBefore Tag::SpaceBefore
) )
.parse(arena, state)?; .parse(arena, state)?;
// This could be an open tag union, e.g. `[ Foo, Bar ]a` // This could be an open tag union, e.g. `[ Foo, Bar ]a`
let (_, ext, state) = let (_, ext, state) = optional(allocated(specialize_ref(
optional(allocated(specialize_ref(TTagUnion::Type, term(min_indent)))) ETypeTagUnion::Type,
term(min_indent),
)))
.parse(arena, state)?; .parse(arena, state)?;
let result = TypeAnnotation::TagUnion { let result = TypeAnnotation::TagUnion {
tags: tags.into_bump_slice(), tags: tags.items,
ext, ext,
final_comments, final_comments: tags.final_comments,
}; };
Ok((MadeProgress, result, state)) Ok((MadeProgress, result, state))
} }
} }
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, Type<'a>> { fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|_arena, state: State<'a>| Err((NoProgress, Type::TStart(state.line, state.column), state)) |_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.line, state.column), state))
} }
fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
map_with_arena!( map_with_arena!(
and!( and!(
one_of!( one_of!(
loc_wildcard(), loc_wildcard(),
specialize(Type::TInParens, loc_type_in_parens(min_indent)), specialize(EType::TInParens, loc_type_in_parens(min_indent)),
loc!(specialize(Type::TRecord, record_type(min_indent))), loc!(specialize(EType::TRecord, record_type(min_indent))),
loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))), loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
loc!(applied_type(min_indent)), loc!(applied_type(min_indent)),
loc!(parse_type_variable), loc!(parse_type_variable),
fail_type_start(), fail_type_start(),
@ -67,14 +71,14 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Typ
map!( map!(
and!( and!(
skip_second!( skip_second!(
backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentEnd)), backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentEnd)),
crate::parser::keyword_e(keyword::AS, Type::TEnd) crate::parser::keyword_e(keyword::AS, EType::TEnd)
), ),
space0_before_e( space0_before_e(
term(min_indent), term(min_indent),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TAsIndentStart EType::TAsIndentStart
) )
), ),
Some Some
@ -103,24 +107,26 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Typ
} }
/// The `*` type variable, e.g. in (List *) Wildcard, /// The `*` type variable, e.g. in (List *) Wildcard,
fn loc_wildcard<'a>() -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { fn loc_wildcard<'a>() -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
map!(loc!(word1(b'*', Type::TWildcard)), |loc_val: Located<()>| { map!(loc!(word1(b'*', EType::TWildcard)), |loc_val: Located<
(),
>| {
loc_val.map(|_| TypeAnnotation::Wildcard) loc_val.map(|_| TypeAnnotation::Wildcard)
}) })
} }
fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
use crate::ast::Spaceable; use crate::ast::Spaceable;
map_with_arena!( map_with_arena!(
and!( and!(
backtrackable(space0_e(min_indent, Type::TSpace, Type::TIndentStart)), backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentStart)),
one_of!( one_of!(
loc_wildcard(), loc_wildcard(),
specialize(Type::TInParens, loc_type_in_parens(min_indent)), specialize(EType::TInParens, loc_type_in_parens(min_indent)),
loc!(specialize(Type::TRecord, record_type(min_indent))), loc!(specialize(EType::TRecord, record_type(min_indent))),
loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))), loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
loc!(specialize(Type::TApply, parse_concrete_type)), loc!(specialize(EType::TApply, parse_concrete_type)),
loc!(parse_type_variable) loc!(parse_type_variable)
) )
), ),
@ -137,28 +143,28 @@ fn loc_applied_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotatio
fn loc_type_in_parens<'a>( fn loc_type_in_parens<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> { ) -> impl Parser<'a, Located<TypeAnnotation<'a>>, ETypeInParens<'a>> {
between!( between!(
word1(b'(', TInParens::Open), word1(b'(', ETypeInParens::Open),
space0_around_ee( space0_around_ee(
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent)) move |arena, state| specialize_ref(ETypeInParens::Type, expression(min_indent))
.parse(arena, state), .parse(arena, state),
min_indent, min_indent,
TInParens::Space, ETypeInParens::Space,
TInParens::IndentOpen, ETypeInParens::IndentOpen,
TInParens::IndentEnd, ETypeInParens::IndentEnd,
), ),
word1(b')', TInParens::IndentEnd) word1(b')', ETypeInParens::IndentEnd)
) )
} }
#[inline(always)] #[inline(always)]
fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, TTagUnion<'a>> { fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| {
let (_, name, state) = loc!(parse_tag_name(TTagUnion::End)).parse(arena, state)?; let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?;
let (_, args, state) = let (_, args, state) = specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(min_indent))
specialize_ref(TTagUnion::Type, loc_applied_args_e(min_indent)).parse(arena, state)?; .parse(arena, state)?;
let result = if name.value.starts_with('@') { let result = if name.value.starts_with('@') {
Tag::Private { Tag::Private {
@ -190,7 +196,7 @@ where
fn record_type_field<'a>( fn record_type_field<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, TRecord<'a>> { ) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, ETypeRecord<'a>> {
use crate::ident::lowercase_ident; use crate::ident::lowercase_ident;
use crate::parser::Either::*; use crate::parser::Either::*;
use AssignedField::*; use AssignedField::*;
@ -201,29 +207,33 @@ fn record_type_field<'a>(
let row = state.line; let row = state.line;
let col = state.column; let col = state.column;
let (progress, loc_label, state) = loc!(specialize( let (progress, loc_label, state) = loc!(specialize(
move |_, _, _| TRecord::Field(row, col), move |_, _, _| ETypeRecord::Field(row, col),
lowercase_ident() lowercase_ident()
)) ))
.parse(arena, state)?; .parse(arena, state)?;
debug_assert_eq!(progress, MadeProgress); debug_assert_eq!(progress, MadeProgress);
let (_, spaces, state) = let (_, spaces, state) =
space0_e(min_indent, TRecord::Space, TRecord::IndentEnd).parse(arena, state)?; space0_e(min_indent, ETypeRecord::Space, ETypeRecord::IndentEnd).parse(arena, state)?;
// Having a value is optional; both `{ email }` and `{ email: blah }` work. // Having a value is optional; both `{ email }` and `{ email: blah }` work.
// (This is true in both literals and types.) // (This is true in both literals and types.)
let (_, opt_loc_val, state) = optional(either!( let (_, opt_loc_val, state) = optional(either!(
word1(b':', TRecord::Colon), word1(b':', ETypeRecord::Colon),
word1(b'?', TRecord::Optional) word1(b'?', ETypeRecord::Optional)
)) ))
.parse(arena, state)?; .parse(arena, state)?;
let val_parser = specialize_ref(TRecord::Type, term(min_indent)); let val_parser = specialize_ref(ETypeRecord::Type, term(min_indent));
match opt_loc_val { match opt_loc_val {
Some(First(_)) => { Some(First(_)) => {
let (_, loc_val, state) = let (_, loc_val, state) = space0_before_e(
space0_before_e(val_parser, min_indent, TRecord::Space, TRecord::IndentColon) val_parser,
min_indent,
ETypeRecord::Space,
ETypeRecord::IndentColon,
)
.parse(arena, state)?; .parse(arena, state)?;
Ok(( Ok((
@ -236,8 +246,8 @@ fn record_type_field<'a>(
let (_, loc_val, state) = space0_before_e( let (_, loc_val, state) = space0_before_e(
val_parser, val_parser,
min_indent, min_indent,
TRecord::Space, ETypeRecord::Space,
TRecord::IndentOptional, ETypeRecord::IndentOptional,
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -263,42 +273,44 @@ fn record_type_field<'a>(
} }
#[inline(always)] #[inline(always)]
fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TRecord<'a>> { fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
use crate::type_annotation::TypeAnnotation::*; use crate::type_annotation::TypeAnnotation::*;
move |arena, state| { move |arena, state| {
let (_, (fields, final_comments), state) = collection_trailing_sep_e!( let (_, fields, state) = collection_trailing_sep_e!(
// word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen), // word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen),
word1(b'{', TRecord::Open), word1(b'{', ETypeRecord::Open),
loc!(record_type_field(min_indent)), loc!(record_type_field(min_indent)),
word1(b',', TRecord::End), word1(b',', ETypeRecord::End),
// word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd), // word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd),
word1(b'}', TRecord::End), word1(b'}', ETypeRecord::End),
min_indent, min_indent,
TRecord::Open, ETypeRecord::Open,
TRecord::Space, ETypeRecord::Space,
TRecord::IndentEnd, ETypeRecord::IndentEnd,
AssignedField::SpaceBefore AssignedField::SpaceBefore
) )
.parse(arena, state)?; .parse(arena, state)?;
let field_term = specialize_ref(TRecord::Type, term(min_indent)); let field_term = specialize_ref(ETypeRecord::Type, term(min_indent));
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?; let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
let result = Record { let result = Record {
fields: fields.into_bump_slice(), fields: Collection {
items: fields.items,
final_comments: fields.final_comments,
},
ext, ext,
final_comments,
}; };
Ok((MadeProgress, result, state)) Ok((MadeProgress, result, state))
} }
} }
fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type<'a>> { fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
map!( map!(
and!( and!(
specialize(Type::TApply, parse_concrete_type), specialize(EType::TApply, parse_concrete_type),
// Optionally parse space-separated arguments for the constructor, // Optionally parse space-separated arguments for the constructor,
// e.g. `Str Float` in `Map Str Float` // e.g. `Str Float` in `Map Str Float`
loc_applied_args_e(min_indent) loc_applied_args_e(min_indent)
@ -322,33 +334,33 @@ fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, Type
fn loc_applied_args_e<'a>( fn loc_applied_args_e<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, Vec<'a, Located<TypeAnnotation<'a>>>, Type<'a>> { ) -> impl Parser<'a, Vec<'a, Located<TypeAnnotation<'a>>>, EType<'a>> {
zero_or_more!(loc_applied_arg(min_indent)) zero_or_more!(loc_applied_arg(min_indent))
} }
fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, EType<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| {
let (p1, first, state) = space0_before_e( let (p1, first, state) = space0_before_e(
term(min_indent), term(min_indent),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
) )
.parse(arena, state)?; .parse(arena, state)?;
let (p2, rest, state) = zero_or_more!(skip_first!( let (p2, rest, state) = zero_or_more!(skip_first!(
word1(b',', Type::TFunctionArgument), word1(b',', EType::TFunctionArgument),
one_of![ one_of![
space0_around_ee( space0_around_ee(
term(min_indent), term(min_indent),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
Type::TIndentEnd EType::TIndentEnd
), ),
|_, state: State<'a>| Err(( |_, state: State<'a>| Err((
NoProgress, NoProgress,
Type::TFunctionArgument(state.line, state.column), EType::TFunctionArgument(state.line, state.column),
state state
)) ))
] ]
@ -358,8 +370,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
// TODO this space0 is dropped, so newlines just before the function arrow when there // TODO this space0 is dropped, so newlines just before the function arrow when there
// is only one argument are not seen by the formatter. Can we do better? // is only one argument are not seen by the formatter. Can we do better?
let (p3, is_function, state) = optional(skip_first!( let (p3, is_function, state) = optional(skip_first!(
space0_e(min_indent, Type::TSpace, Type::TIndentStart), space0_e(min_indent, EType::TSpace, EType::TIndentStart),
word2(b'-', b'>', Type::TStart) word2(b'-', b'>', EType::TStart)
)) ))
.parse(arena, state)?; .parse(arena, state)?;
@ -367,8 +379,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
let (p4, return_type, state) = space0_before_e( let (p4, return_type, state) = space0_before_e(
term(min_indent), term(min_indent),
min_indent, min_indent,
Type::TSpace, EType::TSpace,
Type::TIndentStart, EType::TIndentStart,
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -416,7 +428,7 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
fn parse_concrete_type<'a>( fn parse_concrete_type<'a>(
arena: &'a Bump, arena: &'a Bump,
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, TypeAnnotation<'a>, TApply> { ) -> ParseResult<'a, TypeAnnotation<'a>, ETypeApply> {
let initial_bytes = state.bytes; let initial_bytes = state.bytes;
match crate::ident::concrete_type().parse(arena, state) { match crate::ident::concrete_type().parse(arena, state) {
@ -426,7 +438,7 @@ fn parse_concrete_type<'a>(
Ok((MadeProgress, answer, state)) Ok((MadeProgress, answer, state))
} }
Err((NoProgress, _, state)) => { Err((NoProgress, _, state)) => {
Err((NoProgress, TApply::End(state.line, state.column), state)) Err((NoProgress, ETypeApply::End(state.line, state.column), state))
} }
Err((MadeProgress, _, mut state)) => { Err((MadeProgress, _, mut state)) => {
// we made some progress, but ultimately failed. // we made some progress, but ultimately failed.
@ -437,7 +449,7 @@ fn parse_concrete_type<'a>(
unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) }; unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) };
state = state.advance_without_indenting_ee(chomped, |r, c| { state = state.advance_without_indenting_ee(chomped, |r, c| {
TApply::Space(crate::parser::BadInputError::LineTooLong, r, c) ETypeApply::Space(crate::parser::BadInputError::LineTooLong, r, c)
})?; })?;
Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state)) Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state))
@ -448,7 +460,7 @@ fn parse_concrete_type<'a>(
fn parse_type_variable<'a>( fn parse_type_variable<'a>(
arena: &'a Bump, arena: &'a Bump,
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, TypeAnnotation<'a>, Type<'a>> { ) -> ParseResult<'a, TypeAnnotation<'a>, EType<'a>> {
match crate::ident::lowercase_ident().parse(arena, state) { match crate::ident::lowercase_ident().parse(arena, state) {
Ok((_, name, state)) => { Ok((_, name, state)) => {
let answer = TypeAnnotation::BoundVariable(name); let answer = TypeAnnotation::BoundVariable(name);
@ -457,7 +469,7 @@ fn parse_type_variable<'a>(
} }
Err((progress, _, state)) => Err(( Err((progress, _, state)) => Err((
progress, progress,
Type::TBadTypeVariable(state.line, state.column), EType::TBadTypeVariable(state.line, state.column),
state, state,
)), )),
} }

View file

@ -23,7 +23,9 @@ mod test_parse {
use roc_parse::ast::Pattern::{self, *}; use roc_parse::ast::Pattern::{self, *};
use roc_parse::ast::StrLiteral::{self, *}; use roc_parse::ast::StrLiteral::{self, *};
use roc_parse::ast::StrSegment::*; use roc_parse::ast::StrSegment::*;
use roc_parse::ast::{self, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch}; use roc_parse::ast::{
self, Collection, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch,
};
use roc_parse::header::{ use roc_parse::header::{
AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To,
@ -2281,9 +2283,8 @@ mod test_parse {
6, 6,
TypeAnnotation::SpaceBefore( TypeAnnotation::SpaceBefore(
&TypeAnnotation::Record { &TypeAnnotation::Record {
fields: &[], fields: Collection::empty(),
ext: None, ext: None,
final_comments: &[],
}, },
&[Newline], &[Newline],
), ),
@ -2320,9 +2321,8 @@ mod test_parse {
6, 6,
TypeAnnotation::SpaceBefore( TypeAnnotation::SpaceBefore(
&TypeAnnotation::Record { &TypeAnnotation::Record {
fields: &[], fields: Collection::empty(),
ext: None, ext: None,
final_comments: &[],
}, },
&[LineComment(" comment")], &[LineComment(" comment")],
), ),
@ -3091,7 +3091,7 @@ mod test_parse {
#[test] #[test]
fn empty_app_header() { fn empty_app_header() {
let arena = Bump::new(); let arena = Bump::new();
let packages = Vec::new_in(&arena); let packages = Collection::empty();
let imports = Vec::new_in(&arena); let imports = Vec::new_in(&arena);
let provides = Vec::new_in(&arena); let provides = Vec::new_in(&arena);
let module_name = StrLiteral::PlainLine("test-app"); let module_name = StrLiteral::PlainLine("test-app");
@ -3131,7 +3131,7 @@ mod test_parse {
use PackageOrPath::Path; use PackageOrPath::Path;
let arena = Bump::new(); let arena = Bump::new();
let packages = Vec::new_in(&arena); let packages = Collection::empty();
let imports = Vec::new_in(&arena); let imports = Vec::new_in(&arena);
let provides = Vec::new_in(&arena); let provides = Vec::new_in(&arena);
let module_name = StrLiteral::PlainLine("test-app"); let module_name = StrLiteral::PlainLine("test-app");
@ -3180,7 +3180,7 @@ mod test_parse {
}; };
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
let arena = Bump::new(); let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry]; 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"), Vec::new_in(&arena));
let loc_import = Located::new(2, 2, 14, 25, import); let loc_import = Located::new(2, 2, 14, 25, import);
let imports = bumpalo::vec![in &arena; loc_import]; let imports = bumpalo::vec![in &arena; loc_import];
@ -3236,7 +3236,7 @@ mod test_parse {
}; };
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
let arena = Bump::new(); let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry]; 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"), Vec::new_in(&arena));
let loc_import = Located::new(2, 2, 14, 25, import); let loc_import = Located::new(2, 2, 14, 25, import);
let imports = bumpalo::vec![in &arena; loc_import]; let imports = bumpalo::vec![in &arena; loc_import];
@ -3309,9 +3309,8 @@ mod test_parse {
ann: Located::at( ann: Located::at(
region2, region2,
TypeAnnotation::Record { TypeAnnotation::Record {
fields: &[], fields: Collection::empty(),
ext: None, ext: None,
final_comments: &[],
}, },
), ),
}, },
@ -3324,7 +3323,7 @@ mod test_parse {
name: Located::new(0, 0, 9, 23, pkg_name), name: Located::new(0, 0, 9, 23, pkg_name),
requires, requires,
exposes: Vec::new_in(&arena), exposes: Vec::new_in(&arena),
packages: Vec::new_in(&arena), packages: Collection::empty(),
imports: Vec::new_in(&arena), imports: Vec::new_in(&arena),
provides: Vec::new_in(&arena), provides: Vec::new_in(&arena),
effects, effects,
@ -3367,7 +3366,7 @@ mod test_parse {
}; };
let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry); let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry);
let arena = Bump::new(); let arena = Bump::new();
let packages = bumpalo::vec![in &arena; loc_pkg_entry]; let packages = Collection::with_items(arena.alloc([loc_pkg_entry]));
let imports = Vec::new_in(&arena); let imports = Vec::new_in(&arena);
let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost")); let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost"));
let provides = bumpalo::vec![in &arena; provide_entry]; let provides = bumpalo::vec![in &arena; provide_entry];
@ -3395,9 +3394,8 @@ mod test_parse {
ann: Located::at( ann: Located::at(
region2, region2,
TypeAnnotation::Record { TypeAnnotation::Record {
fields: &[], fields: Collection::empty(),
ext: None, ext: None,
final_comments: &[],
}, },
), ),
}, },

View file

@ -1019,16 +1019,16 @@ fn to_list_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
context: Context, context: Context,
parse_problem: &roc_parse::parser::List<'a>, parse_problem: &roc_parse::parser::EList<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::List; use roc_parse::parser::EList;
match *parse_problem { match *parse_problem {
List::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), EList::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
List::Expr(expr, row, col) => to_expr_report( EList::Expr(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::ListElement, start_row, start_col, Box::new(context)), Context::InNode(Node::ListElement, start_row, start_col, Box::new(context)),
@ -1037,7 +1037,7 @@ fn to_list_report<'a>(
col, col,
), ),
List::Open(row, col) | List::End(row, col) => { EList::Open(row, col) | EList::End(row, col) => {
match what_is_next(alloc.src_lines, row, col) { match what_is_next(alloc.src_lines, row, col) {
Next::Other(Some(',')) => { Next::Other(Some(',')) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
@ -1098,7 +1098,7 @@ fn to_list_report<'a>(
} }
} }
List::IndentOpen(row, col) | List::IndentEnd(row, col) => { EList::IndentOpen(row, col) | EList::IndentEnd(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -1130,16 +1130,16 @@ fn to_if_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
context: Context, context: Context,
parse_problem: &roc_parse::parser::If<'a>, parse_problem: &roc_parse::parser::EIf<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::If; use roc_parse::parser::EIf;
match *parse_problem { match *parse_problem {
If::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), EIf::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
If::Condition(expr, row, col) => to_expr_report( EIf::Condition(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::IfCondition, start_row, start_col, Box::new(context)), Context::InNode(Node::IfCondition, start_row, start_col, Box::new(context)),
@ -1148,7 +1148,7 @@ fn to_if_report<'a>(
col, col,
), ),
If::ThenBranch(expr, row, col) => to_expr_report( EIf::ThenBranch(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::IfThenBranch, start_row, start_col, Box::new(context)), Context::InNode(Node::IfThenBranch, start_row, start_col, Box::new(context)),
@ -1157,7 +1157,7 @@ fn to_if_report<'a>(
col, col,
), ),
If::ElseBranch(expr, row, col) => to_expr_report( EIf::ElseBranch(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::IfElseBranch, start_row, start_col, Box::new(context)), Context::InNode(Node::IfElseBranch, start_row, start_col, Box::new(context)),
@ -1166,10 +1166,10 @@ fn to_if_report<'a>(
col, col,
), ),
If::If(_row, _col) => unreachable!("another branch would be taken"), EIf::If(_row, _col) => unreachable!("another branch would be taken"),
If::IndentIf(_row, _col) => unreachable!("another branch would be taken"), EIf::IndentIf(_row, _col) => unreachable!("another branch would be taken"),
If::Then(row, col) | If::IndentThenBranch(row, col) | If::IndentThenToken(row, col) => { EIf::Then(row, col) | EIf::IndentThenBranch(row, col) | EIf::IndentThenToken(row, col) => {
to_unfinished_if_report( to_unfinished_if_report(
alloc, alloc,
filename, filename,
@ -1185,7 +1185,7 @@ fn to_if_report<'a>(
) )
} }
If::Else(row, col) | If::IndentElseBranch(row, col) | If::IndentElseToken(row, col) => { EIf::Else(row, col) | EIf::IndentElseBranch(row, col) | EIf::IndentElseToken(row, col) => {
to_unfinished_if_report( to_unfinished_if_report(
alloc, alloc,
filename, filename,
@ -1201,7 +1201,7 @@ fn to_if_report<'a>(
) )
} }
If::IndentCondition(row, col) => to_unfinished_if_report( EIf::IndentCondition(row, col) => to_unfinished_if_report(
alloc, alloc,
filename, filename,
row, row,
@ -1249,14 +1249,14 @@ fn to_when_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
context: Context, context: Context,
parse_problem: &roc_parse::parser::When<'a>, parse_problem: &roc_parse::parser::EWhen<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::When; use roc_parse::parser::EWhen;
match *parse_problem { match *parse_problem {
When::IfGuard(nested, row, col) => match what_is_next(alloc.src_lines, row, col) { EWhen::IfGuard(nested, row, col) => match what_is_next(alloc.src_lines, row, col) {
Next::Token("->") => { Next::Token("->") => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -1287,7 +1287,7 @@ fn to_when_report<'a>(
col, col,
), ),
}, },
When::Arrow(row, col) => { EWhen::Arrow(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -1310,9 +1310,9 @@ fn to_when_report<'a>(
} }
} }
When::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), EWhen::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
When::Branch(expr, row, col) => to_expr_report( EWhen::Branch(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::WhenBranch, start_row, start_col, Box::new(context)), Context::InNode(Node::WhenBranch, start_row, start_col, Box::new(context)),
@ -1321,7 +1321,7 @@ fn to_when_report<'a>(
col, col,
), ),
When::Condition(expr, row, col) => to_expr_report( EWhen::Condition(expr, row, col) => to_expr_report(
alloc, alloc,
filename, filename,
Context::InNode(Node::WhenCondition, start_row, start_col, Box::new(context)), Context::InNode(Node::WhenCondition, start_row, start_col, Box::new(context)),
@ -1330,7 +1330,7 @@ fn to_when_report<'a>(
col, col,
), ),
When::Bar(row, col) => to_unfinished_when_report( EWhen::Bar(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1344,10 +1344,10 @@ fn to_when_report<'a>(
]), ]),
), ),
When::IfToken(_row, _col) => unreachable!("the if-token is optional"), EWhen::IfToken(_row, _col) => unreachable!("the if-token is optional"),
When::When(_row, _col) => unreachable!("another branch would be taken"), EWhen::When(_row, _col) => unreachable!("another branch would be taken"),
When::Is(row, col) | When::IndentIs(row, col) => to_unfinished_when_report( EWhen::Is(row, col) | EWhen::IndentIs(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1361,7 +1361,7 @@ fn to_when_report<'a>(
]), ]),
), ),
When::IndentCondition(row, col) => to_unfinished_when_report( EWhen::IndentCondition(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1373,7 +1373,7 @@ fn to_when_report<'a>(
]), ]),
), ),
When::IndentPattern(row, col) => to_unfinished_when_report( EWhen::IndentPattern(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1383,7 +1383,7 @@ fn to_when_report<'a>(
alloc.concat(vec![alloc.reflow(r"I was expecting to see a pattern next")]), alloc.concat(vec![alloc.reflow(r"I was expecting to see a pattern next")]),
), ),
When::IndentArrow(row, col) => to_unfinished_when_report( EWhen::IndentArrow(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1397,7 +1397,7 @@ fn to_when_report<'a>(
]), ]),
), ),
When::IndentIfGuard(row, col) => to_unfinished_when_report( EWhen::IndentIfGuard(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1411,7 +1411,7 @@ fn to_when_report<'a>(
]), ]),
), ),
When::IndentBranch(row, col) => to_unfinished_when_report( EWhen::IndentBranch(row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1424,7 +1424,7 @@ fn to_when_report<'a>(
]), ]),
), ),
When::PatternAlignment(indent, row, col) => to_unfinished_when_report( EWhen::PatternAlignment(indent, row, col) => to_unfinished_when_report(
alloc, alloc,
filename, filename,
row, row,
@ -1437,7 +1437,7 @@ fn to_when_report<'a>(
alloc.reflow(" spaces)"), alloc.reflow(" spaces)"),
]), ]),
), ),
When::Pattern(ref pat, row, col) => to_pattern_report(alloc, filename, pat, row, col), EWhen::Pattern(ref pat, row, col) => to_pattern_report(alloc, filename, pat, row, col),
} }
} }
@ -2000,23 +2000,23 @@ fn to_pattern_in_parens_report<'a>(
fn to_type_report<'a>( fn to_type_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
parse_problem: &roc_parse::parser::Type<'a>, parse_problem: &roc_parse::parser::EType<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::Type; use roc_parse::parser::EType;
match parse_problem { match parse_problem {
Type::TRecord(record, row, col) => to_trecord_report(alloc, filename, record, *row, *col), EType::TRecord(record, row, col) => to_trecord_report(alloc, filename, record, *row, *col),
Type::TTagUnion(tag_union, row, col) => { EType::TTagUnion(tag_union, row, col) => {
to_ttag_union_report(alloc, filename, tag_union, *row, *col) to_ttag_union_report(alloc, filename, tag_union, *row, *col)
} }
Type::TInParens(tinparens, row, col) => { EType::TInParens(tinparens, row, col) => {
to_tinparens_report(alloc, filename, tinparens, *row, *col) to_tinparens_report(alloc, filename, tinparens, *row, *col)
} }
Type::TApply(tapply, row, col) => to_tapply_report(alloc, filename, tapply, *row, *col), EType::TApply(tapply, row, col) => to_tapply_report(alloc, filename, tapply, *row, *col),
Type::TFunctionArgument(row, col) => match what_is_next(alloc.src_lines, *row, *col) { EType::TFunctionArgument(row, col) => match what_is_next(alloc.src_lines, *row, *col) {
Next::Other(Some(',')) => { Next::Other(Some(',')) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2037,7 +2037,7 @@ fn to_type_report<'a>(
_ => todo!(), _ => todo!(),
}, },
Type::TStart(row, col) => { EType::TStart(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2061,7 +2061,7 @@ fn to_type_report<'a>(
} }
} }
Type::TIndentStart(row, col) => { EType::TIndentStart(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2079,7 +2079,7 @@ fn to_type_report<'a>(
} }
} }
Type::TIndentEnd(row, col) => { EType::TIndentEnd(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2097,7 +2097,7 @@ fn to_type_report<'a>(
} }
} }
Type::TAsIndentStart(row, col) => { EType::TAsIndentStart(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2115,7 +2115,7 @@ fn to_type_report<'a>(
} }
} }
Type::TBadTypeVariable(row, col) => { EType::TBadTypeVariable(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col); let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col); let region = Region::from_row_col(*row, *col);
@ -2139,14 +2139,14 @@ fn to_type_report<'a>(
fn to_trecord_report<'a>( fn to_trecord_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
parse_problem: &roc_parse::parser::TRecord<'a>, parse_problem: &roc_parse::parser::ETypeRecord<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::TRecord; use roc_parse::parser::ETypeRecord;
match *parse_problem { match *parse_problem {
TRecord::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { ETypeRecord::Open(row, col) => match what_is_next(alloc.src_lines, row, col) {
Next::Keyword(keyword) => { Next::Keyword(keyword) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = to_keyword_region(row, col, keyword); let region = to_keyword_region(row, col, keyword);
@ -2191,7 +2191,7 @@ fn to_trecord_report<'a>(
} }
}, },
TRecord::End(row, col) => { ETypeRecord::End(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2237,7 +2237,7 @@ fn to_trecord_report<'a>(
} }
} }
TRecord::Field(row, col) => match what_is_next(alloc.src_lines, row, col) { ETypeRecord::Field(row, col) => match what_is_next(alloc.src_lines, row, col) {
Next::Keyword(keyword) => { Next::Keyword(keyword) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = to_keyword_region(row, col, keyword); let region = to_keyword_region(row, col, keyword);
@ -2286,16 +2286,16 @@ fn to_trecord_report<'a>(
} }
}, },
TRecord::Colon(_, _) => { ETypeRecord::Colon(_, _) => {
unreachable!("because `{ foo }` is a valid field; the colon is not required") unreachable!("because `{ foo }` is a valid field; the colon is not required")
} }
TRecord::Optional(_, _) => { ETypeRecord::Optional(_, _) => {
unreachable!("because `{ foo }` is a valid field; the question mark is not required") unreachable!("because `{ foo }` is a valid field; the question mark is not required")
} }
TRecord::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), ETypeRecord::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col),
TRecord::IndentOpen(row, col) => { ETypeRecord::IndentOpen(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2318,7 +2318,7 @@ fn to_trecord_report<'a>(
} }
} }
TRecord::IndentEnd(row, col) => { ETypeRecord::IndentEnd(row, col) => {
match next_line_starts_with_close_curly(alloc.src_lines, row) { match next_line_starts_with_close_curly(alloc.src_lines, row) {
Some((curly_row, curly_col)) => { Some((curly_row, curly_col)) => {
let surroundings = let surroundings =
@ -2370,29 +2370,29 @@ fn to_trecord_report<'a>(
} }
} }
TRecord::IndentColon(_, _) => { ETypeRecord::IndentColon(_, _) => {
unreachable!("because `{ foo }` is a valid field; the colon is not required") unreachable!("because `{ foo }` is a valid field; the colon is not required")
} }
TRecord::IndentOptional(_, _) => { ETypeRecord::IndentOptional(_, _) => {
unreachable!("because `{ foo }` is a valid field; the question mark is not required") unreachable!("because `{ foo }` is a valid field; the question mark is not required")
} }
TRecord::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), ETypeRecord::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
} }
} }
fn to_ttag_union_report<'a>( fn to_ttag_union_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
parse_problem: &roc_parse::parser::TTagUnion<'a>, parse_problem: &roc_parse::parser::ETypeTagUnion<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::TTagUnion; use roc_parse::parser::ETypeTagUnion;
match *parse_problem { match *parse_problem {
TTagUnion::Open(row, col) => match what_is_next(alloc.src_lines, row, col) { ETypeTagUnion::Open(row, col) => match what_is_next(alloc.src_lines, row, col) {
Next::Keyword(keyword) => { Next::Keyword(keyword) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = to_keyword_region(row, col, keyword); let region = to_keyword_region(row, col, keyword);
@ -2459,7 +2459,7 @@ fn to_ttag_union_report<'a>(
} }
}, },
TTagUnion::End(row, col) => { ETypeTagUnion::End(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2523,9 +2523,9 @@ fn to_ttag_union_report<'a>(
} }
} }
TTagUnion::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), ETypeTagUnion::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col),
TTagUnion::IndentOpen(row, col) => { ETypeTagUnion::IndentOpen(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2548,7 +2548,7 @@ fn to_ttag_union_report<'a>(
} }
} }
TTagUnion::IndentEnd(row, col) => { ETypeTagUnion::IndentEnd(row, col) => {
match next_line_starts_with_close_square_bracket(alloc.src_lines, row) { match next_line_starts_with_close_square_bracket(alloc.src_lines, row) {
Some((curly_row, curly_col)) => { Some((curly_row, curly_col)) => {
let surroundings = let surroundings =
@ -2600,21 +2600,21 @@ fn to_ttag_union_report<'a>(
} }
} }
TTagUnion::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), ETypeTagUnion::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
} }
} }
fn to_tinparens_report<'a>( fn to_tinparens_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
parse_problem: &roc_parse::parser::TInParens<'a>, parse_problem: &roc_parse::parser::ETypeInParens<'a>,
start_row: Row, start_row: Row,
start_col: Col, start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::TInParens; use roc_parse::parser::ETypeInParens;
match *parse_problem { match *parse_problem {
TInParens::Open(row, col) => { ETypeInParens::Open(row, col) => {
match what_is_next(alloc.src_lines, row, col) { match what_is_next(alloc.src_lines, row, col) {
Next::Keyword(keyword) => { Next::Keyword(keyword) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
@ -2686,7 +2686,7 @@ fn to_tinparens_report<'a>(
} }
} }
TInParens::End(row, col) => { ETypeInParens::End(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2734,9 +2734,9 @@ fn to_tinparens_report<'a>(
} }
} }
TInParens::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col), ETypeInParens::Type(tipe, row, col) => to_type_report(alloc, filename, tipe, row, col),
TInParens::IndentOpen(row, col) => { ETypeInParens::IndentOpen(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, row, col); let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
@ -2760,7 +2760,7 @@ fn to_tinparens_report<'a>(
} }
} }
TInParens::IndentEnd(row, col) => { ETypeInParens::IndentEnd(row, col) => {
match next_line_starts_with_close_parenthesis(alloc.src_lines, row) { match next_line_starts_with_close_parenthesis(alloc.src_lines, row) {
Some((curly_row, curly_col)) => { Some((curly_row, curly_col)) => {
let surroundings = let surroundings =
@ -2812,21 +2812,21 @@ fn to_tinparens_report<'a>(
} }
} }
TInParens::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), ETypeInParens::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
} }
} }
fn to_tapply_report<'a>( fn to_tapply_report<'a>(
alloc: &'a RocDocAllocator<'a>, alloc: &'a RocDocAllocator<'a>,
filename: PathBuf, filename: PathBuf,
parse_problem: &roc_parse::parser::TApply, parse_problem: &roc_parse::parser::ETypeApply,
_start_row: Row, _start_row: Row,
_start_col: Col, _start_col: Col,
) -> Report<'a> { ) -> Report<'a> {
use roc_parse::parser::TApply; use roc_parse::parser::ETypeApply;
match *parse_problem { match *parse_problem {
TApply::DoubleDot(row, col) => { ETypeApply::DoubleDot(row, col) => {
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
@ -2842,7 +2842,7 @@ fn to_tapply_report<'a>(
severity: Severity::RuntimeError, severity: Severity::RuntimeError,
} }
} }
TApply::TrailingDot(row, col) => { ETypeApply::TrailingDot(row, col) => {
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
@ -2864,7 +2864,7 @@ fn to_tapply_report<'a>(
severity: Severity::RuntimeError, severity: Severity::RuntimeError,
} }
} }
TApply::StartIsNumber(row, col) => { ETypeApply::StartIsNumber(row, col) => {
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
@ -2886,7 +2886,7 @@ fn to_tapply_report<'a>(
severity: Severity::RuntimeError, severity: Severity::RuntimeError,
} }
} }
TApply::StartNotUppercase(row, col) => { ETypeApply::StartNotUppercase(row, col) => {
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
@ -2909,7 +2909,7 @@ fn to_tapply_report<'a>(
} }
} }
TApply::End(row, col) => { ETypeApply::End(row, col) => {
let region = Region::from_row_col(row, col); let region = Region::from_row_col(row, col);
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
@ -2927,7 +2927,7 @@ fn to_tapply_report<'a>(
} }
} }
TApply::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col), ETypeApply::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
} }
} }

View file

@ -1,19 +1,16 @@
#![cfg(not(feature = "gen-wasm"))]
#[cfg(feature = "gen-llvm")] #[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_evals_to; use crate::helpers::llvm::assert_evals_to;
#[cfg(feature = "gen-dev")] #[cfg(feature = "gen-dev")]
use crate::helpers::dev::assert_evals_to; use crate::helpers::dev::assert_evals_to;
// #[cfg(feature = "gen-wasm")] #[cfg(feature = "gen-wasm")]
// use crate::helpers::wasm::assert_evals_to; use crate::helpers::wasm::assert_evals_to;
// use crate::assert_wasm_evals_to as assert_evals_to;
use indoc::indoc; use indoc::indoc;
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn eq_i64() { fn eq_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -30,7 +27,7 @@ fn eq_i64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn neq_i64() { fn neq_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -47,7 +44,7 @@ fn neq_i64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn eq_u64() { fn eq_u64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -64,7 +61,7 @@ fn eq_u64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn neq_u64() { fn neq_u64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -81,7 +78,7 @@ fn neq_u64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn eq_f64() { fn eq_f64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -98,7 +95,7 @@ fn eq_f64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn neq_f64() { fn neq_f64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -115,7 +112,7 @@ fn neq_f64() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn eq_bool_tag() { fn eq_bool_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -132,7 +129,7 @@ fn eq_bool_tag() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn neq_bool_tag() { fn neq_bool_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -163,7 +160,7 @@ fn unit() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn newtype() { fn newtype() {
assert_evals_to!("Identity 42 == Identity 42", true, bool); assert_evals_to!("Identity 42 == Identity 42", true, bool);
assert_evals_to!("Identity 42 != Identity 42", false, bool); assert_evals_to!("Identity 42 != Identity 42", false, bool);

View file

@ -571,7 +571,7 @@ fn abs_min_int_overflow() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn gen_if_fn() { fn gen_if_fn() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(

View file

@ -85,7 +85,7 @@ fn branch_third_float() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn branch_first_int() { fn branch_first_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -101,7 +101,7 @@ fn branch_first_int() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn branch_second_int() { fn branch_second_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -134,7 +134,7 @@ fn branch_third_int() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn branch_store_variable() { fn branch_store_variable() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -221,7 +221,7 @@ fn gen_when_one_branch() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn gen_large_when_int() { fn gen_large_when_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -243,31 +243,31 @@ fn gen_large_when_int() {
); );
} }
// #[test] #[test]
// #[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-wasm"))]
// fn gen_large_when_float() { fn gen_large_when_float() {
// assert_evals_to!( assert_evals_to!(
// indoc!( indoc!(
// r#" r#"
// foo = \num -> foo = \num ->
// when num is when num is
// 0.5 -> 200.1 0.5 -> 200.1
// -3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here -3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here
// 3.6 -> 789.5 3.6 -> 789.5
// 1.7 -> 123.3 1.7 -> 123.3
// 2.8 -> 456.4 2.8 -> 456.4
// _ -> 1000.6 _ -> 1000.6
// foo -3.6 foo -3.6
// "# "#
// ), ),
// 111.2, 111.2,
// f64 f64
// ); );
// } }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn or_pattern() { fn or_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -337,7 +337,7 @@ fn return_unnamed_fn() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn gen_when_fn() { fn gen_when_fn() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -504,7 +504,7 @@ fn gen_multiple_defs() {
// } // }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn factorial() { fn factorial() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(

View file

@ -159,3 +159,33 @@ fn err_empty_tag_union() {
i64 i64
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn is_ok() {
assert_evals_to!(
indoc!(
r#"
result : Result I64 {}
result = Ok 2
Result.isOk result
"#
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
result : Result I64 {}
result = Err {}
Result.isOk result
"#
),
false,
bool
);
}

View file

@ -127,7 +127,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
let src_hash = hash_state.finish(); let src_hash = hash_state.finish();
// Filename contains a hash of the Roc test source code. Helpful when comparing across commits. // Filename contains a hash of the Roc test source code. Helpful when comparing across commits.
let dir = "/tmp/roc/compiler/gen_wasm/output"; let dir = "/tmp/roc/gen_wasm";
std::fs::create_dir_all(dir).unwrap(); std::fs::create_dir_all(dir).unwrap();
let path = format!("{}/test-{:016x}.wasm", dir, src_hash); let path = format!("{}/test-{:016x}.wasm", dir, src_hash);

View file

@ -10,6 +10,7 @@ pub mod gen_list;
pub mod gen_num; pub mod gen_num;
pub mod gen_primitives; pub mod gen_primitives;
pub mod gen_records; pub mod gen_records;
pub mod gen_result;
pub mod gen_set; pub mod gen_set;
pub mod gen_str; pub mod gen_str;
pub mod gen_tags; pub mod gen_tags;