Merge remote-tracking branch 'origin/trunk' into tag-union-imitate-rust

This commit is contained in:
Folkert 2021-11-13 01:06:31 +01:00
commit e706c3eb0a
15 changed files with 389 additions and 360 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

@ -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

@ -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

@ -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

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,19 +2147,20 @@ 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 (_, elements, 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)?;
@ -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,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),

View file

@ -2,38 +2,42 @@ 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, 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 {
@ -46,18 +50,18 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TT
} }
} }
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,26 +273,26 @@ 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, 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 {
@ -297,10 +307,10 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TReco
} }
} }
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)
@ -324,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
)) ))
] ]
@ -360,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)?;
@ -369,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)?;
@ -418,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) {
@ -428,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.
@ -439,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))
@ -450,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);
@ -459,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

@ -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

@ -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);