mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
WIP Merge remote-tracking branch 'remote/main' into rebuild-platform
This commit is contained in:
commit
e3afeaa7ff
138 changed files with 3544 additions and 4651 deletions
|
@ -618,6 +618,16 @@ pub fn listDropAt(
|
|||
) callconv(.C) RocList {
|
||||
const size = list.len();
|
||||
const size_u64 = @as(u64, @intCast(size));
|
||||
|
||||
// NOTE
|
||||
// we need to return an empty list explicitly,
|
||||
// because we rely on the pointer field being null if the list is empty
|
||||
// which also requires duplicating the utils.decref call to spend the RC token
|
||||
if (size <= 1) {
|
||||
list.decref(alignment, element_width, elements_refcounted, dec);
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
// If droping the first or last element, return a seamless slice.
|
||||
// For simplicity, do this by calling listSublist.
|
||||
// In the future, we can test if it is faster to manually inline the important parts here.
|
||||
|
@ -638,25 +648,16 @@ pub fn listDropAt(
|
|||
// were >= than `size`, and we know `size` fits in usize.
|
||||
const drop_index: usize = @intCast(drop_index_u64);
|
||||
|
||||
if (elements_refcounted) {
|
||||
const element = source_ptr + drop_index * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// we need to return an empty list explicitly,
|
||||
// because we rely on the pointer field being null if the list is empty
|
||||
// which also requires duplicating the utils.decref call to spend the RC token
|
||||
if (size < 2) {
|
||||
list.decref(alignment, element_width, elements_refcounted, dec);
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
if (list.isUnique()) {
|
||||
var i = drop_index;
|
||||
const copy_target = source_ptr;
|
||||
if (elements_refcounted) {
|
||||
const element = source_ptr + drop_index * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
const copy_target = source_ptr + (drop_index * element_width);
|
||||
const copy_source = copy_target + element_width;
|
||||
std.mem.copyForwards(u8, copy_target[i..size], copy_source[i..size]);
|
||||
const copy_size = (size - drop_index - 1) * element_width;
|
||||
std.mem.copyForwards(u8, copy_target[0..copy_size], copy_source[0..copy_size]);
|
||||
|
||||
var new_list = list;
|
||||
|
||||
|
|
|
@ -509,33 +509,33 @@ removeHelper = \buckets, bucketIndex, distAndFingerprint, data, key ->
|
|||
## is missing. This is more efficient than doing both a `Dict.get` and then a
|
||||
## `Dict.insert` call, and supports being piped.
|
||||
## ```roc
|
||||
## alterValue : [Present Bool, Missing] -> [Present Bool, Missing]
|
||||
## alterValue : Result Bool [Missing] -> Result Bool [Missing]
|
||||
## alterValue = \possibleValue ->
|
||||
## when possibleValue is
|
||||
## Missing -> Present Bool.false
|
||||
## Present value -> if value then Missing else Present Bool.true
|
||||
## Err -> Ok Bool.false
|
||||
## Ok value -> if value then Err Missing else Ok Bool.true
|
||||
##
|
||||
## expect Dict.update (Dict.empty {}) "a" alterValue == Dict.single "a" Bool.false
|
||||
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
||||
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty {}
|
||||
## ```
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v
|
||||
update : Dict k v, k, (Result v [Missing] -> Result v [Missing]) -> Dict k v
|
||||
update = \@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }, key, alter ->
|
||||
{ bucketIndex, result } = find (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key
|
||||
when result is
|
||||
Ok value ->
|
||||
when alter (Present value) is
|
||||
Present newValue ->
|
||||
when alter (Ok value) is
|
||||
Ok newValue ->
|
||||
bucket = listGetUnsafe buckets bucketIndex
|
||||
newData = List.set data (Num.toU64 bucket.dataIndex) (key, newValue)
|
||||
@Dict { buckets, data: newData, maxBucketCapacity, maxLoadFactor, shifts }
|
||||
|
||||
Missing ->
|
||||
Err Missing ->
|
||||
removeBucket (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) bucketIndex
|
||||
|
||||
Err KeyNotFound ->
|
||||
when alter Missing is
|
||||
Present newValue ->
|
||||
when alter (Err Missing) is
|
||||
Ok newValue ->
|
||||
if List.len data >= maxBucketCapacity then
|
||||
# Need to reallocate let regular insert handle that.
|
||||
insert (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key newValue
|
||||
|
@ -556,7 +556,7 @@ update = \@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }, key
|
|||
distAndFingerprint = incrementDistN baseDistAndFingerprint (Num.toU32 dist)
|
||||
insertHelper buckets data bucketIndex distAndFingerprint key newValue maxBucketCapacity maxLoadFactor shifts
|
||||
|
||||
Missing ->
|
||||
Err Missing ->
|
||||
@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }
|
||||
|
||||
circularDist = \start, end, size ->
|
||||
|
@ -1216,8 +1216,8 @@ expect
|
|||
List.walk badKeys (Dict.empty {}) \acc, k ->
|
||||
Dict.update acc k \val ->
|
||||
when val is
|
||||
Present p -> Present (p |> Num.addWrap 1)
|
||||
Missing -> Present 0
|
||||
Ok p -> Ok (p |> Num.addWrap 1)
|
||||
Err Missing -> Ok 0
|
||||
|
||||
allInsertedCorrectly =
|
||||
List.walk badKeys Bool.true \acc, k ->
|
||||
|
|
|
@ -548,6 +548,23 @@ tau = 2 * pi
|
|||
## [F64] or [F32] value, the returned string will be `"NaN"`, `"∞"`, or `"-∞"`.
|
||||
##
|
||||
toStr : Num * -> Str
|
||||
|
||||
## Convert an [Int] to a new [Int] of the expected type:
|
||||
##
|
||||
## ```roc
|
||||
## # Casts a U8 to a U16
|
||||
## x : U16
|
||||
## x = Num.intCast 255u8
|
||||
## ```
|
||||
##
|
||||
## In the case of downsizing, information is lost:
|
||||
##
|
||||
## ```roc
|
||||
## # returns 0, as the bits were truncated.
|
||||
## x : U8
|
||||
## x = Num.intCast 256u16
|
||||
## ```
|
||||
##
|
||||
intCast : Int a -> Int b
|
||||
|
||||
compare : Num a, Num a -> [LT, EQ, GT]
|
||||
|
|
|
@ -367,6 +367,8 @@ module [
|
|||
withCapacity,
|
||||
withPrefix,
|
||||
contains,
|
||||
dropPrefix,
|
||||
dropSuffix,
|
||||
]
|
||||
|
||||
import Bool exposing [Bool]
|
||||
|
@ -1052,3 +1054,37 @@ contains = \haystack, needle ->
|
|||
when firstMatch haystack needle is
|
||||
Some _index -> Bool.true
|
||||
None -> Bool.false
|
||||
|
||||
## Drops the given prefix [Str] from the start of a [Str]
|
||||
## If the prefix is not found, returns the original string.
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.dropPrefix "bar" "foo" == "bar"
|
||||
## expect Str.dropPrefix "foobar" "foo" == "bar"
|
||||
## ```
|
||||
dropPrefix : Str, Str -> Str
|
||||
dropPrefix = \haystack, prefix ->
|
||||
if Str.startsWith haystack prefix then
|
||||
start = Str.countUtf8Bytes prefix
|
||||
len = Num.subWrap (Str.countUtf8Bytes haystack) start
|
||||
|
||||
substringUnsafe haystack start len
|
||||
else
|
||||
haystack
|
||||
|
||||
## Drops the given suffix [Str] from the end of a [Str]
|
||||
## If the suffix is not found, returns the original string.
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.dropSuffix "bar" "foo" == "bar"
|
||||
## expect Str.dropSuffix "barfoo" "foo" == "bar"
|
||||
## ```
|
||||
dropSuffix : Str, Str -> Str
|
||||
dropSuffix = \haystack, suffix ->
|
||||
if Str.endsWith haystack suffix then
|
||||
start = 0
|
||||
len = Num.subWrap (Str.countUtf8Bytes haystack) (Str.countUtf8Bytes suffix)
|
||||
|
||||
substringUnsafe haystack start len
|
||||
else
|
||||
haystack
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@ use roc_collections::{MutMap, VecSet};
|
|||
use roc_module::ident::{Ident, ModuleName};
|
||||
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol};
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_region::all::{LineInfo, Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
/// The canonicalization environment for a particular module.
|
||||
|
@ -44,11 +44,19 @@ pub struct Env<'a> {
|
|||
pub arena: &'a Bump,
|
||||
|
||||
pub opt_shorthand: Option<&'a str>,
|
||||
|
||||
pub src: &'a str,
|
||||
|
||||
/// Lazily calculated line info. This data is only needed if the code contains calls to `dbg`,
|
||||
/// otherwise we can leave it as `None` and never pay the cost of scanning the source an extra
|
||||
/// time.
|
||||
line_info: &'a mut Option<LineInfo>,
|
||||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
src: &'a str,
|
||||
home: ModuleId,
|
||||
module_path: &'a Path,
|
||||
dep_idents: &'a IdentIdsByModule,
|
||||
|
@ -57,6 +65,7 @@ impl<'a> Env<'a> {
|
|||
) -> Env<'a> {
|
||||
Env {
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
module_path,
|
||||
dep_idents,
|
||||
|
@ -69,6 +78,7 @@ impl<'a> Env<'a> {
|
|||
top_level_symbols: VecSet::default(),
|
||||
home_params_record: None,
|
||||
opt_shorthand,
|
||||
line_info: arena.alloc(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,4 +229,11 @@ impl<'a> Env<'a> {
|
|||
pub fn problem(&mut self, problem: Problem) {
|
||||
self.problems.push(problem)
|
||||
}
|
||||
|
||||
pub fn line_info(&mut self) -> &LineInfo {
|
||||
if self.line_info.is_none() {
|
||||
*self.line_info = Some(LineInfo::new(self.src));
|
||||
}
|
||||
self.line_info.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1013,11 +1013,8 @@ pub fn canonicalize_expr<'a>(
|
|||
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
|
||||
})
|
||||
}
|
||||
ast::Expr::OldRecordBuilder(_) => {
|
||||
internal_error!("Old record builder should have been desugared by now")
|
||||
}
|
||||
ast::Expr::RecordBuilder { .. } => {
|
||||
internal_error!("New record builder should have been desugared by now")
|
||||
internal_error!("Record builder should have been desugared by now")
|
||||
}
|
||||
ast::Expr::Backpassing(_, _, _) => {
|
||||
internal_error!("Backpassing should have been desugared by now")
|
||||
|
@ -1209,8 +1206,20 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::Dbg | ast::Expr::DbgStmt(_, _) => {
|
||||
internal_error!("Dbg should have been desugared by now")
|
||||
ast::Expr::Dbg => {
|
||||
// Dbg was not desugared as either part of an `Apply` or a `Pizza` binop, so it's
|
||||
// invalid.
|
||||
env.problem(Problem::UnappliedDbg { region });
|
||||
|
||||
let invalid_dbg_expr = crate::desugar::desugar_invalid_dbg_expr(env, scope, region);
|
||||
|
||||
let (loc_expr, output) =
|
||||
canonicalize_expr(env, var_store, scope, region, invalid_dbg_expr);
|
||||
|
||||
(loc_expr.value, output)
|
||||
}
|
||||
ast::Expr::DbgStmt(_, _) => {
|
||||
internal_error!("DbgStmt should have been desugared by now")
|
||||
}
|
||||
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
|
||||
let mut output = Output::default();
|
||||
|
@ -1249,7 +1258,11 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::If(if_thens, final_else_branch) => {
|
||||
ast::Expr::If {
|
||||
if_thens,
|
||||
final_else: final_else_branch,
|
||||
..
|
||||
} => {
|
||||
let mut branches = Vec::with_capacity(if_thens.len());
|
||||
let mut output = Output::default();
|
||||
|
||||
|
@ -1340,22 +1353,6 @@ pub fn canonicalize_expr<'a>(
|
|||
use roc_problem::can::RuntimeError::*;
|
||||
(RuntimeError(MalformedSuffixed(region)), Output::default())
|
||||
}
|
||||
ast::Expr::MultipleOldRecordBuilders(sub_expr) => {
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
|
||||
let problem = MultipleOldRecordBuilders(sub_expr.region);
|
||||
env.problem(Problem::RuntimeError(problem.clone()));
|
||||
|
||||
(RuntimeError(problem), Output::default())
|
||||
}
|
||||
ast::Expr::UnappliedOldRecordBuilder(sub_expr) => {
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
|
||||
let problem = UnappliedOldRecordBuilder(sub_expr.region);
|
||||
env.problem(Problem::RuntimeError(problem.clone()));
|
||||
|
||||
(RuntimeError(problem), Output::default())
|
||||
}
|
||||
ast::Expr::EmptyRecordBuilder(sub_expr) => {
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
|
||||
|
@ -2536,8 +2533,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
.iter()
|
||||
.all(|loc_field| is_valid_interpolation(&loc_field.value)),
|
||||
ast::Expr::MalformedSuffixed(loc_expr)
|
||||
| ast::Expr::MultipleOldRecordBuilders(loc_expr)
|
||||
| ast::Expr::UnappliedOldRecordBuilder(loc_expr)
|
||||
| ast::Expr::EmptyRecordBuilder(loc_expr)
|
||||
| ast::Expr::SingleFieldRecordBuilder(loc_expr)
|
||||
| ast::Expr::OptionalFieldInRecordBuilder(_, loc_expr)
|
||||
|
@ -2560,7 +2555,11 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
.iter()
|
||||
.all(|(loc_expr, _binop)| is_valid_interpolation(&loc_expr.value))
|
||||
}
|
||||
ast::Expr::If(branches, final_branch) => {
|
||||
ast::Expr::If {
|
||||
if_thens: branches,
|
||||
final_else: final_branch,
|
||||
..
|
||||
} => {
|
||||
is_valid_interpolation(&final_branch.value)
|
||||
&& branches.iter().all(|(loc_before, loc_after)| {
|
||||
is_valid_interpolation(&loc_before.value)
|
||||
|
@ -2583,27 +2582,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::AssignedField::SpaceAfter(_, _) => false,
|
||||
})
|
||||
}
|
||||
ast::Expr::OldRecordBuilder(fields) => {
|
||||
fields.iter().all(|loc_field| match loc_field.value {
|
||||
ast::OldRecordBuilderField::Value(_label, comments, loc_expr) => {
|
||||
comments.is_empty() && is_valid_interpolation(&loc_expr.value)
|
||||
}
|
||||
ast::OldRecordBuilderField::ApplyValue(
|
||||
_label,
|
||||
comments_before,
|
||||
comments_after,
|
||||
loc_expr,
|
||||
) => {
|
||||
comments_before.is_empty()
|
||||
&& comments_after.is_empty()
|
||||
&& is_valid_interpolation(&loc_expr.value)
|
||||
}
|
||||
ast::OldRecordBuilderField::Malformed(_)
|
||||
| ast::OldRecordBuilderField::LabelOnly(_) => true,
|
||||
ast::OldRecordBuilderField::SpaceBefore(_, _)
|
||||
| ast::OldRecordBuilderField::SpaceAfter(_, _) => false,
|
||||
})
|
||||
}
|
||||
ast::Expr::RecordBuilder { mapper, fields } => {
|
||||
is_valid_interpolation(&mapper.value)
|
||||
&& fields.iter().all(|loc_field| match loc_field.value {
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::path::Path;
|
|||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||
use crate::desugar::desugar_record_destructures;
|
||||
use crate::env::Env;
|
||||
use crate::expr::{
|
||||
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
||||
|
@ -240,6 +241,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
arena.alloc(Path::new(module_path)),
|
||||
dep_idents,
|
||||
|
@ -266,16 +268,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
|
||||
crate::desugar::desugar_defs_node_values(
|
||||
arena,
|
||||
var_store,
|
||||
loc_defs,
|
||||
src,
|
||||
&mut None,
|
||||
module_path,
|
||||
true,
|
||||
&mut env.problems,
|
||||
);
|
||||
crate::desugar::desugar_defs_node_values(&mut env, &mut scope, loc_defs, true);
|
||||
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
|
@ -334,13 +327,16 @@ pub fn canonicalize_module_defs<'a>(
|
|||
before_arrow: _,
|
||||
after_arrow: _,
|
||||
}| {
|
||||
let desugared_patterns =
|
||||
desugar_record_destructures(&mut env, &mut scope, pattern.value);
|
||||
|
||||
let (destructs, _) = canonicalize_record_destructs(
|
||||
&mut env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
&mut output,
|
||||
PatternType::ModuleParams,
|
||||
&pattern.value,
|
||||
&desugared_patterns,
|
||||
pattern.region,
|
||||
PermitShadows(false),
|
||||
);
|
||||
|
|
|
@ -914,7 +914,10 @@ pub fn canonicalize_record_destructs<'a>(
|
|||
}
|
||||
};
|
||||
}
|
||||
_ => unreachable!("Any other pattern should have given a parse error"),
|
||||
_ => unreachable!(
|
||||
"Any other pattern should have given a parse error: {:?}",
|
||||
loc_pattern.value
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -466,7 +466,7 @@ impl Scope {
|
|||
self.home.register_debug_idents(&self.locals.ident_ids)
|
||||
}
|
||||
|
||||
/// Generates a unique, new symbol like "$1" or "$5",
|
||||
/// Generates a unique, new symbol like "1" or "5",
|
||||
/// using the home module as the module_id.
|
||||
///
|
||||
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||
|
@ -475,6 +475,12 @@ impl Scope {
|
|||
Symbol::new(self.home, self.locals.gen_unique())
|
||||
}
|
||||
|
||||
/// Generates a unique new symbol and return the symbol's unqualified identifier name.
|
||||
pub fn gen_unique_symbol_name(&mut self) -> &str {
|
||||
let ident_id = self.locals.gen_unique();
|
||||
self.locals.ident_ids.get_name(ident_id).unwrap()
|
||||
}
|
||||
|
||||
/// Introduce a new ignored variable (variable starting with an underscore).
|
||||
/// The underscore itself should not be included in `ident`.
|
||||
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {
|
||||
|
|
|
@ -131,7 +131,7 @@ pub fn unwrap_suffixed_expression<'a>(
|
|||
|
||||
Expr::When(..) => unwrap_suffixed_expression_when_help(arena, loc_expr, maybe_def_pat),
|
||||
|
||||
Expr::If(..) => {
|
||||
Expr::If { .. } => {
|
||||
unwrap_suffixed_expression_if_then_else_help(arena, loc_expr, maybe_def_pat)
|
||||
}
|
||||
|
||||
|
@ -325,7 +325,14 @@ pub fn unwrap_suffixed_expression_apply_help<'a>(
|
|||
|
||||
let new_apply = arena.alloc(Loc::at(loc_expr.region, Expr::Apply(unwrapped_function, local_args, called_via)));
|
||||
|
||||
return init_unwrapped_err(arena, new_apply, maybe_def_pat, target);
|
||||
match maybe_def_pat {
|
||||
Some(..) => {
|
||||
return Err(EUnwrapped::UnwrappedDefExpr { loc_expr: new_apply, target });
|
||||
}
|
||||
None => {
|
||||
return init_unwrapped_err(arena, new_apply, maybe_def_pat, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// function is another expression
|
||||
|
@ -357,7 +364,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
maybe_def_pat: Option<&'a Loc<Pattern<'a>>>,
|
||||
) -> Result<&'a Loc<Expr<'a>>, EUnwrapped<'a>> {
|
||||
match loc_expr.value {
|
||||
Expr::If(if_thens, final_else_branch) => {
|
||||
Expr::If {
|
||||
if_thens,
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
} => {
|
||||
for (index, if_then) in if_thens.iter().enumerate() {
|
||||
let (current_if_then_statement, current_if_then_expression) = if_then;
|
||||
|
||||
|
@ -376,10 +387,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let new_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(
|
||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else_branch,
|
||||
),
|
||||
Expr::If {
|
||||
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||
|
@ -411,10 +423,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let new_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(
|
||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else_branch,
|
||||
),
|
||||
Expr::If {
|
||||
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||
|
@ -439,10 +452,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let new_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(
|
||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else_branch,
|
||||
),
|
||||
Expr::If {
|
||||
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||
|
@ -465,10 +479,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let new_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(
|
||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else_branch,
|
||||
),
|
||||
Expr::If {
|
||||
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
let unwrapped_if_then = apply_try_function(
|
||||
|
@ -494,10 +509,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let after_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(
|
||||
arena.alloc_slice_copy(after_if_thens.as_slice()),
|
||||
final_else_branch,
|
||||
),
|
||||
Expr::If {
|
||||
if_thens: arena.alloc_slice_copy(after_if_thens.as_slice()),
|
||||
final_else: final_else_branch,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
let after_if_then = apply_try_function(
|
||||
|
@ -512,7 +528,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let before_if_then = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(before, after_if_then),
|
||||
Expr::If {
|
||||
if_thens: before,
|
||||
final_else: after_if_then,
|
||||
indented_else: false,
|
||||
},
|
||||
));
|
||||
|
||||
return unwrap_suffixed_expression(
|
||||
|
@ -532,7 +552,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
Ok(unwrapped_final_else) => {
|
||||
return Ok(arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(if_thens, unwrapped_final_else),
|
||||
Expr::If {
|
||||
if_thens,
|
||||
final_else: unwrapped_final_else,
|
||||
indented_else,
|
||||
},
|
||||
)));
|
||||
}
|
||||
Err(EUnwrapped::UnwrappedDefExpr { .. }) => {
|
||||
|
@ -556,7 +580,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
|||
|
||||
let new_if = arena.alloc(Loc::at(
|
||||
loc_expr.region,
|
||||
Expr::If(if_thens, unwrapped_final_else),
|
||||
Expr::If {
|
||||
if_thens,
|
||||
final_else: unwrapped_final_else,
|
||||
indented_else,
|
||||
},
|
||||
));
|
||||
|
||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||
|
|
|
@ -46,6 +46,24 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
let var = var_store.fresh();
|
||||
let qualified_module_ids = PackageModuleIds::default();
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
expr_str,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
|
@ -53,22 +71,8 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
scope.add_alias(
|
||||
Symbol::NUM_INT,
|
||||
Region::zero(),
|
||||
|
@ -81,15 +85,6 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
roc_types::types::AliasKind::Structural,
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
let (loc_expr, output) = canonicalize_expr(
|
||||
&mut env,
|
||||
&mut var_store,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 449
|
||||
assertion_line: 463
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
|
@ -44,7 +44,7 @@ Defs {
|
|||
value_defs: [
|
||||
Body(
|
||||
@15-26 Identifier {
|
||||
ident: "64",
|
||||
ident: "1",
|
||||
},
|
||||
@15-26 ParensAround(
|
||||
Defs(
|
||||
|
@ -66,7 +66,7 @@ Defs {
|
|||
value_defs: [
|
||||
Body(
|
||||
@20-25 Identifier {
|
||||
ident: "63",
|
||||
ident: "0",
|
||||
},
|
||||
@20-25 Apply(
|
||||
@22-23 Var {
|
||||
|
@ -101,14 +101,14 @@ Defs {
|
|||
[
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
ident: "0",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
ident: "0",
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -129,14 +129,14 @@ Defs {
|
|||
[
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "64",
|
||||
ident: "1",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "64",
|
||||
ident: "1",
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
@ -63,8 +63,8 @@ Defs {
|
|||
),
|
||||
],
|
||||
},
|
||||
@66-130 If(
|
||||
[
|
||||
@66-130 If {
|
||||
if_thens: [
|
||||
(
|
||||
@69-70 Var {
|
||||
module_name: "",
|
||||
|
@ -76,11 +76,12 @@ Defs {
|
|||
},
|
||||
),
|
||||
],
|
||||
@128-130 Var {
|
||||
final_else: @128-130 Var {
|
||||
module_name: "",
|
||||
ident: "c",
|
||||
},
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
|
|
|
@ -136,8 +136,8 @@ Defs {
|
|||
ident: "#!1_arg",
|
||||
},
|
||||
],
|
||||
@109-298 If(
|
||||
[
|
||||
@109-298 If {
|
||||
if_thens: [
|
||||
(
|
||||
@112-122 Apply(
|
||||
@112-113 Var {
|
||||
|
@ -244,7 +244,7 @@ Defs {
|
|||
),
|
||||
),
|
||||
],
|
||||
Apply(
|
||||
final_else: Apply(
|
||||
Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
|
@ -269,8 +269,8 @@ Defs {
|
|||
ident: "#!3_arg",
|
||||
},
|
||||
],
|
||||
@109-298 If(
|
||||
[
|
||||
@109-298 If {
|
||||
if_thens: [
|
||||
(
|
||||
@187-209 ParensAround(
|
||||
Var {
|
||||
|
@ -366,7 +366,7 @@ Defs {
|
|||
),
|
||||
),
|
||||
],
|
||||
@283-298 Apply(
|
||||
final_else: @283-298 Apply(
|
||||
@283-298 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
|
@ -380,12 +380,14 @@ Defs {
|
|||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
BangSuffix,
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
BangSuffix,
|
||||
|
|
|
@ -101,8 +101,8 @@ Defs {
|
|||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
@76-189 If(
|
||||
[
|
||||
@76-189 If {
|
||||
if_thens: [
|
||||
(
|
||||
@79-87 Var {
|
||||
module_name: "",
|
||||
|
@ -124,7 +124,7 @@ Defs {
|
|||
),
|
||||
),
|
||||
],
|
||||
@125-132 Apply(
|
||||
final_else: @125-132 Apply(
|
||||
@125-132 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
|
@ -140,8 +140,8 @@ Defs {
|
|||
ident: "#!1_arg",
|
||||
},
|
||||
],
|
||||
@76-189 If(
|
||||
[
|
||||
@76-189 If {
|
||||
if_thens: [
|
||||
(
|
||||
@125-132 Var {
|
||||
module_name: "",
|
||||
|
@ -163,7 +163,7 @@ Defs {
|
|||
),
|
||||
),
|
||||
],
|
||||
@178-189 Apply(
|
||||
final_else: @178-189 Apply(
|
||||
@178-182 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
|
@ -177,12 +177,14 @@ Defs {
|
|||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
BangSuffix,
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
BangSuffix,
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
Index(2147483649),
|
||||
Index(2147483650),
|
||||
],
|
||||
regions: [
|
||||
@0-80,
|
||||
@82-227,
|
||||
@229-266,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 0, length = 2),
|
||||
Slice(start = 2, length = 2),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 2, length = 0),
|
||||
Slice(start = 4, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
Newline,
|
||||
Newline,
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-3 Identifier {
|
||||
ident: "inc",
|
||||
},
|
||||
@6-80 Closure(
|
||||
[
|
||||
@7-8 Identifier {
|
||||
ident: "i",
|
||||
},
|
||||
],
|
||||
@16-80 If {
|
||||
if_thens: [
|
||||
(
|
||||
@19-24 Apply(
|
||||
@21-22 Var {
|
||||
module_name: "Num",
|
||||
ident: "isGt",
|
||||
},
|
||||
[
|
||||
@19-20 Var {
|
||||
module_name: "",
|
||||
ident: "i",
|
||||
},
|
||||
@23-24 Num(
|
||||
"2",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
GreaterThan,
|
||||
),
|
||||
),
|
||||
@38-52 Apply(
|
||||
@38-41 Tag(
|
||||
"Err",
|
||||
),
|
||||
[
|
||||
@42-52 Tag(
|
||||
"MaxReached",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
final_else: @70-80 Apply(
|
||||
@70-72 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@74-79 ParensAround(
|
||||
Apply(
|
||||
@76-77 Var {
|
||||
module_name: "Num",
|
||||
ident: "add",
|
||||
},
|
||||
[
|
||||
@74-75 Var {
|
||||
module_name: "",
|
||||
ident: "i",
|
||||
},
|
||||
@78-79 Num(
|
||||
"1",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Plus,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
),
|
||||
Expect {
|
||||
condition: @93-227 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
Index(2147483649),
|
||||
],
|
||||
regions: [
|
||||
@99-189,
|
||||
@203-208,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 1, length = 0),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@93-96 Identifier {
|
||||
ident: "run",
|
||||
},
|
||||
@99-189 Closure(
|
||||
[
|
||||
@100-101 Identifier {
|
||||
ident: "i",
|
||||
},
|
||||
],
|
||||
@132-172 Apply(
|
||||
@132-172 Var {
|
||||
module_name: "Result",
|
||||
ident: "try",
|
||||
},
|
||||
[
|
||||
@132-152 Apply(
|
||||
@132-152 Var {
|
||||
module_name: "",
|
||||
ident: "inc",
|
||||
},
|
||||
[
|
||||
@132-133 Var {
|
||||
module_name: "",
|
||||
ident: "i",
|
||||
},
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
@132-172 Closure(
|
||||
[
|
||||
@132-152 Identifier {
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
@132-172 Apply(
|
||||
@132-172 Var {
|
||||
module_name: "Result",
|
||||
ident: "try",
|
||||
},
|
||||
[
|
||||
@132-172 Apply(
|
||||
@132-172 Var {
|
||||
module_name: "",
|
||||
ident: "inc",
|
||||
},
|
||||
[
|
||||
@132-152 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
@132-172 Closure(
|
||||
[
|
||||
@113-117 Identifier {
|
||||
ident: "newi",
|
||||
},
|
||||
],
|
||||
@182-189 Apply(
|
||||
@182-184 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@185-189 Var {
|
||||
module_name: "",
|
||||
ident: "newi",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
QuestionSuffix,
|
||||
),
|
||||
),
|
||||
],
|
||||
QuestionSuffix,
|
||||
),
|
||||
),
|
||||
),
|
||||
Body(
|
||||
@194-200 Identifier {
|
||||
ident: "result",
|
||||
},
|
||||
@203-208 Apply(
|
||||
@203-206 Var {
|
||||
module_name: "",
|
||||
ident: "run",
|
||||
},
|
||||
[
|
||||
@207-208 Num(
|
||||
"0",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@213-227 Apply(
|
||||
@220-222 Var {
|
||||
module_name: "Bool",
|
||||
ident: "isEq",
|
||||
},
|
||||
[
|
||||
@213-219 Var {
|
||||
module_name: "",
|
||||
ident: "result",
|
||||
},
|
||||
@223-227 Apply(
|
||||
@223-225 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@226-227 Num(
|
||||
"2",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Equals,
|
||||
),
|
||||
),
|
||||
),
|
||||
preceding_comment: @82-82,
|
||||
},
|
||||
Body(
|
||||
@229-233 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@240-266 Apply(
|
||||
@240-266 Var {
|
||||
module_name: "Stdout",
|
||||
ident: "line",
|
||||
},
|
||||
[
|
||||
@253-266 Str(
|
||||
PlainLine(
|
||||
"Hello world",
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
Index(2147483649),
|
||||
],
|
||||
regions: [
|
||||
@0-33,
|
||||
@35-45,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 0, length = 2),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
Slice(start = 2, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
AnnotatedBody {
|
||||
ann_pattern: @0-3 Identifier {
|
||||
ident: "run",
|
||||
},
|
||||
ann_type: @6-15 Apply(
|
||||
"",
|
||||
"Task",
|
||||
[
|
||||
@11-13 Record {
|
||||
fields: [],
|
||||
ext: None,
|
||||
},
|
||||
@14-15 Inferred,
|
||||
],
|
||||
),
|
||||
lines_between: [
|
||||
Newline,
|
||||
],
|
||||
body_pattern: @16-19 Identifier {
|
||||
ident: "run",
|
||||
},
|
||||
body_expr: @22-33 Apply(
|
||||
@22-33 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
},
|
||||
[
|
||||
@28-33 Str(
|
||||
PlainLine(
|
||||
"foo",
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
},
|
||||
Body(
|
||||
@35-39 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@42-45 Var {
|
||||
module_name: "",
|
||||
ident: "run",
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 459
|
||||
assertion_line: 473
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
|
@ -8,7 +8,7 @@ Defs {
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-19,
|
||||
@0-51,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -25,13 +25,13 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-19 Defs(
|
||||
@11-51 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-12,
|
||||
@11-40,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -43,36 +43,98 @@ Defs {
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@11-12 Identifier {
|
||||
ident: "63",
|
||||
@11-40 Identifier {
|
||||
ident: "1",
|
||||
},
|
||||
@11-12 Num(
|
||||
"1",
|
||||
@11-40 Apply(
|
||||
@31-38 Var {
|
||||
module_name: "Num",
|
||||
ident: "add",
|
||||
},
|
||||
[
|
||||
@11-23 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@11-12 Identifier {
|
||||
ident: "0",
|
||||
},
|
||||
@11-12 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-23 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
" ",
|
||||
),
|
||||
@11-12 Apply(
|
||||
@11-12 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
),
|
||||
),
|
||||
@39-40 Num(
|
||||
"2",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-19 LowLevelDbg(
|
||||
@11-51 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
" ",
|
||||
" main =\n 1\n ",
|
||||
),
|
||||
@11-12 Apply(
|
||||
@11-12 Var {
|
||||
@11-40 Apply(
|
||||
@11-40 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-12 Var {
|
||||
@11-40 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
ident: "1",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@11-12 Var {
|
||||
@11-40 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
ident: "1",
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
@ -19,7 +19,6 @@ mod test_can {
|
|||
use roc_can::expr::{ClosureData, IntValue, Recursive};
|
||||
use roc_can::pattern::Pattern;
|
||||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
@ -653,101 +652,6 @@ mod test_can {
|
|||
}
|
||||
|
||||
// RECORD BUILDERS
|
||||
#[test]
|
||||
fn old_record_builder_desugar() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
succeed = \_ -> crash "succeed"
|
||||
apply = \_ -> crash "get"
|
||||
|
||||
d = 3
|
||||
|
||||
succeed {
|
||||
a: 1,
|
||||
b: <- apply "b",
|
||||
c: <- apply "c",
|
||||
d
|
||||
}
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems.len(), 0);
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// (apply "c") ((apply "b") (succeed \b -> \c -> { a: 1, b, c, d }))
|
||||
|
||||
// (apply "c") ..
|
||||
let (apply_c, c_to_b) = simplify_curried_call(&out.loc_expr.value);
|
||||
assert_apply_call(apply_c, "c", &out.interns);
|
||||
|
||||
// (apply "b") ..
|
||||
let (apply_b, b_to_succeed) = simplify_curried_call(c_to_b);
|
||||
assert_apply_call(apply_b, "b", &out.interns);
|
||||
|
||||
// (succeed ..)
|
||||
let (succeed, b_closure) = simplify_curried_call(b_to_succeed);
|
||||
|
||||
match succeed {
|
||||
Var(sym, _) => assert_eq!(sym.as_str(&out.interns), "succeed"),
|
||||
_ => panic!("Not calling succeed: {:?}", succeed),
|
||||
}
|
||||
|
||||
// \b -> ..
|
||||
let (b_sym, c_closure) = simplify_builder_closure(b_closure);
|
||||
|
||||
// \c -> ..
|
||||
let (c_sym, c_body) = simplify_builder_closure(c_closure);
|
||||
|
||||
// { a: 1, b, c, d }
|
||||
match c_body {
|
||||
Record { fields, .. } => {
|
||||
match get_field_expr(fields, "a") {
|
||||
Num(_, num_str, _, _) => {
|
||||
assert_eq!(num_str.to_string(), "1");
|
||||
}
|
||||
expr => panic!("a is not a Num: {:?}", expr),
|
||||
}
|
||||
|
||||
assert_eq!(get_field_var_sym(fields, "b"), b_sym);
|
||||
assert_eq!(get_field_var_sym(fields, "c"), c_sym);
|
||||
assert_eq!(get_field_var_sym(fields, "d").as_str(&out.interns), "d");
|
||||
}
|
||||
_ => panic!("Closure body wasn't a Record: {:?}", c_body),
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_curried_call(expr: &Expr) -> (&Expr, &Expr) {
|
||||
match expr {
|
||||
LetNonRec(_, loc_expr) => simplify_curried_call(&loc_expr.value),
|
||||
Call(fun, args, _) => (&fun.1.value, &args[0].1.value),
|
||||
_ => panic!("Final Expr is not a Call: {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_apply_call(expr: &Expr, expected: &str, interns: &roc_module::symbol::Interns) {
|
||||
match simplify_curried_call(expr) {
|
||||
(Var(sym, _), Str(val)) => {
|
||||
assert_eq!(sym.as_str(interns), "apply");
|
||||
assert_eq!(val.to_string(), expected);
|
||||
}
|
||||
call => panic!("Not a valid (get {}) call: {:?}", expected, call),
|
||||
};
|
||||
}
|
||||
|
||||
fn simplify_builder_closure(expr: &Expr) -> (Symbol, &Expr) {
|
||||
use roc_can::pattern::Pattern::*;
|
||||
|
||||
match expr {
|
||||
Closure(closure) => match &closure.arguments[0].2.value {
|
||||
Identifier(sym) => (*sym, &closure.loc_body.value),
|
||||
pattern => panic!("Not an identifier pattern: {:?}", pattern),
|
||||
},
|
||||
_ => panic!("Not a closure: {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field_expr<'a>(
|
||||
fields: &'a roc_collections::SendMap<roc_module::ident::Lowercase, roc_can::expr::Field>,
|
||||
|
@ -769,97 +673,7 @@ mod test_can {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn old_record_builder_field_names_do_not_shadow() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
succeed = \_ -> crash "succeed"
|
||||
parse = \_ -> crash "parse"
|
||||
|
||||
number = "42"
|
||||
|
||||
succeed {
|
||||
number: <- parse number,
|
||||
raw: number,
|
||||
}
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems.len(), 0);
|
||||
|
||||
let (_, number_to_succeed) = simplify_curried_call(&out.loc_expr.value);
|
||||
let (_, number_closure) = simplify_curried_call(number_to_succeed);
|
||||
let (apply_number_sym, record) = simplify_builder_closure(number_closure);
|
||||
|
||||
match record {
|
||||
Record { fields, .. } => {
|
||||
assert_eq!(get_field_var_sym(fields, "number"), apply_number_sym);
|
||||
|
||||
match get_field_expr(fields, "raw") {
|
||||
Var(number_sym, _) => {
|
||||
assert_ne!(number_sym.ident_id(), apply_number_sym.ident_id());
|
||||
assert_eq!(number_sym.as_str(&out.interns), "number")
|
||||
}
|
||||
expr => panic!("a is not a Num: {:?}", expr),
|
||||
}
|
||||
}
|
||||
_ => panic!("Closure body wasn't a Record: {:?}", record),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_old_record_builders_error() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
succeed
|
||||
{ a: <- apply "a" }
|
||||
{ b: <- apply "b" }
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let CanExprOut {
|
||||
problems, loc_expr, ..
|
||||
} = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(problems.len(), 1);
|
||||
assert!(problems.iter().all(|problem| matches!(
|
||||
problem,
|
||||
Problem::RuntimeError(roc_problem::can::RuntimeError::MultipleOldRecordBuilders { .. })
|
||||
)));
|
||||
|
||||
assert!(matches!(
|
||||
loc_expr.value,
|
||||
Expr::RuntimeError(roc_problem::can::RuntimeError::MultipleOldRecordBuilders { .. })
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hanging_old_record_builder() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
{ a: <- apply "a" }
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let CanExprOut {
|
||||
problems, loc_expr, ..
|
||||
} = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(problems.len(), 1);
|
||||
assert!(problems.iter().all(|problem| matches!(
|
||||
problem,
|
||||
Problem::RuntimeError(roc_problem::can::RuntimeError::UnappliedOldRecordBuilder { .. })
|
||||
)));
|
||||
|
||||
assert!(matches!(
|
||||
loc_expr.value,
|
||||
Expr::RuntimeError(roc_problem::can::RuntimeError::UnappliedOldRecordBuilder { .. })
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_record_builder_desugar() {
|
||||
fn record_builder_desugar() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
map2 = \a, b, combine -> combine a b
|
||||
|
|
|
@ -6,25 +6,39 @@ mod suffixed_tests {
|
|||
use bumpalo::Bump;
|
||||
use insta::assert_snapshot;
|
||||
use roc_can::desugar::desugar_defs_node_values;
|
||||
use roc_can::env::Env;
|
||||
use roc_can::scope::Scope;
|
||||
use roc_module::symbol::{IdentIds, ModuleIds, PackageModuleIds};
|
||||
use roc_parse::test_helpers::parse_defs_with;
|
||||
use roc_types::subs::VarStore;
|
||||
use std::path::Path;
|
||||
|
||||
macro_rules! run_test {
|
||||
($src:expr) => {{
|
||||
let arena = &Bump::new();
|
||||
let mut var_store = VarStore::default();
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&mut defs,
|
||||
$src,
|
||||
&mut None,
|
||||
"test.roc",
|
||||
true,
|
||||
&mut Default::default(),
|
||||
let home = ModuleIds::default().get_or_insert(&"Test".into());
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let qualified_module_ids = PackageModuleIds::default();
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
$src,
|
||||
home,
|
||||
Path::new("test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(&mut env, &mut scope, &mut defs, true);
|
||||
|
||||
let snapshot = format!("{:#?}", &defs);
|
||||
println!("{}", snapshot);
|
||||
assert_snapshot!(snapshot);
|
||||
|
@ -454,6 +468,19 @@ mod suffixed_tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pizza_dbg() {
|
||||
run_test!(
|
||||
r#"
|
||||
main =
|
||||
1
|
||||
|> dbg
|
||||
|> Num.add 2
|
||||
|> dbg
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_argument_single() {
|
||||
run_test!(
|
||||
|
@ -579,6 +606,44 @@ mod suffixed_tests {
|
|||
"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_7081() {
|
||||
run_test!(
|
||||
r##"
|
||||
inc = \i ->
|
||||
if i > 2 then
|
||||
Err MaxReached
|
||||
else
|
||||
Ok (i + 1)
|
||||
|
||||
expect
|
||||
run = \i ->
|
||||
newi =
|
||||
i
|
||||
|> inc?
|
||||
|> inc?
|
||||
Ok newi
|
||||
result = run 0
|
||||
result == Ok 2
|
||||
|
||||
main =
|
||||
Stdout.line! "Hello world"
|
||||
"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_7103() {
|
||||
run_test!(
|
||||
r##"
|
||||
run : Task {} _
|
||||
run = line! "foo"
|
||||
|
||||
main = run
|
||||
"##
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
243
crates/compiler/checkmate/www/package-lock.json
generated
243
crates/compiler/checkmate/www/package-lock.json
generated
|
@ -5917,9 +5917,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
|
@ -5930,7 +5930,7 @@
|
|||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
|
@ -6091,13 +6091,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"set-function-length": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
@ -7249,6 +7255,23 @@
|
|||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
|
@ -7597,9 +7620,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
|
@ -7704,6 +7727,27 @@
|
|||
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
|
||||
|
@ -8646,37 +8690,37 @@
|
|||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
|
||||
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.2",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
|
@ -8883,13 +8927,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
|
@ -9249,10 +9293,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/function.prototype.name": {
|
||||
"version": "1.1.5",
|
||||
|
@ -9300,15 +9347,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
|
||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3"
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
@ -9590,12 +9641,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
|
||||
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.1"
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
@ -9640,6 +9691,18 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
|
@ -13153,10 +13216,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
||||
"dev": true
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
|
@ -13538,10 +13604,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
||||
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
|
@ -13889,9 +13958,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
|
@ -15501,12 +15570,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
|
@ -16265,9 +16334,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.79.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
|
||||
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
|
||||
"version": "2.79.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
|
@ -16560,9 +16629,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
|
@ -16598,6 +16667,15 @@
|
|||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
@ -16692,20 +16770,37 @@
|
|||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
|
@ -16743,14 +16838,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
};
|
||||
use roc_parse::ast::{
|
||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, ImplementsAbilities,
|
||||
ImplementsAbility, ImplementsClause, OldRecordBuilderField, Tag, TypeAnnotation, TypeHeader,
|
||||
ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
@ -524,101 +524,6 @@ fn format_assigned_field_help<T>(
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for OldRecordBuilderField<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
is_multiline_record_builder_field_help(self)
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, _parens: Parens, newlines: Newlines, indent: u16) {
|
||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
||||
format_record_builder_field_help(self, buf, indent, newlines == Newlines::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_multiline_record_builder_field_help(afield: &OldRecordBuilderField<'_>) -> bool {
|
||||
use self::OldRecordBuilderField::*;
|
||||
|
||||
match afield {
|
||||
Value(_, spaces, ann) => !spaces.is_empty() || ann.value.is_multiline(),
|
||||
ApplyValue(_, colon_spaces, arrow_spaces, ann) => {
|
||||
!colon_spaces.is_empty() || !arrow_spaces.is_empty() || ann.value.is_multiline()
|
||||
}
|
||||
LabelOnly(_) => false,
|
||||
SpaceBefore(_, _) | SpaceAfter(_, _) => true,
|
||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_record_builder_field_help(
|
||||
zelf: &OldRecordBuilderField,
|
||||
buf: &mut Buf,
|
||||
indent: u16,
|
||||
is_multiline: bool,
|
||||
) {
|
||||
use self::OldRecordBuilderField::*;
|
||||
|
||||
match zelf {
|
||||
Value(name, spaces, ann) => {
|
||||
if is_multiline {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
|
||||
if !spaces.is_empty() {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
}
|
||||
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
}
|
||||
ApplyValue(name, colon_spaces, arrow_spaces, ann) => {
|
||||
if is_multiline {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
|
||||
buf.push_str(name.value);
|
||||
|
||||
if !colon_spaces.is_empty() {
|
||||
fmt_spaces(buf, colon_spaces.iter(), indent);
|
||||
}
|
||||
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
|
||||
if !arrow_spaces.is_empty() {
|
||||
fmt_spaces(buf, arrow_spaces.iter(), indent);
|
||||
}
|
||||
|
||||
buf.push_str("<-");
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
}
|
||||
LabelOnly(name) => {
|
||||
if is_multiline {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
|
||||
buf.push_str(name.value);
|
||||
}
|
||||
SpaceBefore(sub_field, spaces) => {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
format_record_builder_field_help(sub_field, buf, indent, is_multiline);
|
||||
}
|
||||
SpaceAfter(sub_field, spaces) => {
|
||||
format_record_builder_field_help(sub_field, buf, indent, is_multiline);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
buf.push_str(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for Tag<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
use self::Tag::*;
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::Buf;
|
|||
use roc_module::called_via::{self, BinOp};
|
||||
use roc_parse::ast::{
|
||||
is_expr_suffixed, AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces,
|
||||
OldRecordBuilderField, Pattern, TryTarget, WhenBranch,
|
||||
Pattern, TryTarget, WhenBranch,
|
||||
};
|
||||
use roc_parse::ast::{StrLiteral, StrSegment};
|
||||
use roc_parse::ident::Accessor;
|
||||
|
@ -71,7 +71,11 @@ impl<'a> Formattable for Expr<'a> {
|
|||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
),
|
||||
|
||||
If(branches, final_else) => {
|
||||
If {
|
||||
if_thens: branches,
|
||||
final_else,
|
||||
..
|
||||
} => {
|
||||
final_else.is_multiline()
|
||||
|| branches
|
||||
.iter()
|
||||
|
@ -87,8 +91,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| PrecedenceConflict(roc_parse::ast::PrecedenceConflict {
|
||||
expr: loc_subexpr, ..
|
||||
})
|
||||
| MultipleOldRecordBuilders(loc_subexpr)
|
||||
| UnappliedOldRecordBuilder(loc_subexpr)
|
||||
| EmptyRecordBuilder(loc_subexpr)
|
||||
| SingleFieldRecordBuilder(loc_subexpr)
|
||||
| OptionalFieldInRecordBuilder(_, loc_subexpr) => loc_subexpr.is_multiline(),
|
||||
|
@ -114,7 +116,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Record(fields) => is_collection_multiline(fields),
|
||||
Tuple(fields) => is_collection_multiline(fields),
|
||||
RecordUpdate { fields, .. } => is_collection_multiline(fields),
|
||||
OldRecordBuilder(fields) => is_collection_multiline(fields),
|
||||
RecordBuilder { fields, .. } => is_collection_multiline(fields),
|
||||
}
|
||||
}
|
||||
|
@ -240,10 +241,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
a.extract_spaces().item.is_multiline()
|
||||
&& matches!(
|
||||
a.value.extract_spaces().item,
|
||||
Expr::Tuple(_)
|
||||
| Expr::List(_)
|
||||
| Expr::Record(_)
|
||||
| Expr::OldRecordBuilder(_)
|
||||
Expr::Tuple(_) | Expr::List(_) | Expr::Record(_)
|
||||
)
|
||||
&& a.extract_spaces().before == [CommentOrNewline::Newline]
|
||||
})
|
||||
|
@ -388,16 +386,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
assigned_field_to_space_before,
|
||||
);
|
||||
}
|
||||
OldRecordBuilder(fields) => {
|
||||
fmt_record_like(
|
||||
buf,
|
||||
None,
|
||||
*fields,
|
||||
indent,
|
||||
format_record_builder_field_multiline,
|
||||
record_builder_field_to_space_before,
|
||||
);
|
||||
}
|
||||
Closure(loc_patterns, loc_ret) => {
|
||||
fmt_closure(buf, loc_patterns, loc_ret, indent);
|
||||
}
|
||||
|
@ -464,8 +452,19 @@ impl<'a> Formattable for Expr<'a> {
|
|||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
),
|
||||
If(branches, final_else) => {
|
||||
fmt_if(buf, branches, final_else, self.is_multiline(), indent);
|
||||
If {
|
||||
if_thens: branches,
|
||||
final_else,
|
||||
indented_else,
|
||||
} => {
|
||||
fmt_if(
|
||||
buf,
|
||||
branches,
|
||||
final_else,
|
||||
self.is_multiline(),
|
||||
*indented_else,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
||||
Tuple(items) => fmt_collection(buf, indent, Braces::Round, *items, Newlines::No),
|
||||
|
@ -548,8 +547,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
MalformedClosure => {}
|
||||
PrecedenceConflict { .. } => {}
|
||||
MultipleOldRecordBuilders { .. } => {}
|
||||
UnappliedOldRecordBuilder { .. } => {}
|
||||
EmptyRecordBuilder { .. } => {}
|
||||
SingleFieldRecordBuilder { .. } => {}
|
||||
OptionalFieldInRecordBuilder(_, _) => {}
|
||||
|
@ -610,11 +607,7 @@ pub(crate) fn format_sq_literal(buf: &mut Buf, s: &str) {
|
|||
fn is_outdentable(expr: &Expr) -> bool {
|
||||
matches!(
|
||||
expr.extract_spaces().item,
|
||||
Expr::Tuple(_)
|
||||
| Expr::List(_)
|
||||
| Expr::Record(_)
|
||||
| Expr::OldRecordBuilder(_)
|
||||
| Expr::Closure(..)
|
||||
Expr::Tuple(_) | Expr::List(_) | Expr::Record(_) | Expr::Closure(..)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1076,6 +1069,7 @@ fn fmt_if<'a>(
|
|||
branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
||||
final_else: &'a Loc<Expr<'a>>,
|
||||
is_multiline: bool,
|
||||
indented_else: bool,
|
||||
indent: u16,
|
||||
) {
|
||||
// let is_multiline_then = loc_then.is_multiline();
|
||||
|
@ -1208,16 +1202,22 @@ fn fmt_if<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
if is_multiline {
|
||||
if indented_else {
|
||||
buf.indent(indent + INDENT);
|
||||
buf.push_str("else");
|
||||
buf.newline();
|
||||
buf.newline();
|
||||
} else if is_multiline {
|
||||
buf.indent(indent);
|
||||
buf.push_str("else");
|
||||
buf.newline();
|
||||
} else {
|
||||
buf.indent(indent);
|
||||
buf.push_str(" else");
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
final_else.format(buf, return_indent);
|
||||
let indent = if indented_else { indent } else { return_indent };
|
||||
final_else.format(buf, indent);
|
||||
}
|
||||
|
||||
fn fmt_closure<'a>(
|
||||
|
@ -1622,113 +1622,6 @@ fn assigned_field_to_space_before<'a, T>(
|
|||
}
|
||||
}
|
||||
|
||||
fn format_record_builder_field_multiline(
|
||||
buf: &mut Buf,
|
||||
field: &OldRecordBuilderField,
|
||||
indent: u16,
|
||||
separator_prefix: &str,
|
||||
) {
|
||||
use self::OldRecordBuilderField::*;
|
||||
match field {
|
||||
Value(name, spaces, ann) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
|
||||
if !spaces.is_empty() {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
buf.indent(indent);
|
||||
}
|
||||
|
||||
buf.push_str(separator_prefix);
|
||||
buf.push_str(":");
|
||||
|
||||
if ann.value.is_multiline() {
|
||||
buf.newline();
|
||||
ann.value.format(buf, indent + INDENT);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
}
|
||||
|
||||
buf.push(',');
|
||||
}
|
||||
ApplyValue(name, colon_spaces, arrow_spaces, ann) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
|
||||
if !colon_spaces.is_empty() {
|
||||
fmt_spaces(buf, colon_spaces.iter(), indent);
|
||||
buf.indent(indent);
|
||||
}
|
||||
|
||||
buf.push_str(separator_prefix);
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
|
||||
if !arrow_spaces.is_empty() {
|
||||
fmt_spaces(buf, arrow_spaces.iter(), indent);
|
||||
buf.indent(indent + INDENT);
|
||||
}
|
||||
|
||||
buf.push_str("<-");
|
||||
|
||||
if ann.value.is_multiline() {
|
||||
buf.newline();
|
||||
ann.value.format(buf, indent + INDENT);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
}
|
||||
buf.push(',');
|
||||
}
|
||||
LabelOnly(name) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
buf.push(',');
|
||||
}
|
||||
SpaceBefore(sub_field, _spaces) => {
|
||||
// We have something like that:
|
||||
// ```
|
||||
// # comment
|
||||
// field,
|
||||
// ```
|
||||
// we'd like to preserve this
|
||||
|
||||
format_record_builder_field_multiline(buf, sub_field, indent, separator_prefix);
|
||||
}
|
||||
SpaceAfter(sub_field, spaces) => {
|
||||
// We have something like that:
|
||||
// ```
|
||||
// field # comment
|
||||
// , otherfield
|
||||
// ```
|
||||
// we'd like to transform it into:
|
||||
// ```
|
||||
// field,
|
||||
// # comment
|
||||
// otherfield
|
||||
// ```
|
||||
format_record_builder_field_multiline(buf, sub_field, indent, separator_prefix);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Top, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
buf.push_str(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_builder_field_to_space_before<'a>(
|
||||
field: &'a OldRecordBuilderField<'a>,
|
||||
) -> Option<(&OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>])> {
|
||||
match field {
|
||||
OldRecordBuilderField::SpaceBefore(sub_field, spaces) => Some((sub_field, spaces)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
||||
match expr {
|
||||
Expr::BinOps(left_side, _) => {
|
||||
|
@ -1753,7 +1646,7 @@ fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
|||
| BinOp::Pizza => true,
|
||||
})
|
||||
}
|
||||
Expr::If(_, _) => true,
|
||||
Expr::If { .. } => true,
|
||||
Expr::SpaceBefore(e, _) => sub_expr_requests_parens(e),
|
||||
Expr::SpaceAfter(e, _) => sub_expr_requests_parens(e),
|
||||
_ => false,
|
||||
|
|
|
@ -2915,130 +2915,108 @@ fn list_literal<'a, 'ctx>(
|
|||
let list_length = elems.len();
|
||||
let list_length_intval = env.ptr_int().const_int(list_length as _, false);
|
||||
|
||||
// TODO re-enable, currently causes morphic segfaults because it tries to update
|
||||
// constants in-place...
|
||||
// if element_type.is_int_type() {
|
||||
if false {
|
||||
let element_type = element_type.into_int_type();
|
||||
let is_refcounted = layout_interner.contains_refcounted(element_layout);
|
||||
let is_all_constant = elems.iter().all(|e| e.is_literal());
|
||||
|
||||
if is_all_constant && !is_refcounted {
|
||||
// Build a global literal in-place instead of GEPing and storing individual elements.
|
||||
// Exceptions:
|
||||
// - Anything that is refcounted has nested pointers,
|
||||
// and nested pointers in globals will break the surgical linker.
|
||||
// Ignore such cases for now.
|
||||
|
||||
let element_width = layout_interner.stack_size(element_layout);
|
||||
let size = list_length * element_width as usize;
|
||||
|
||||
let alignment = layout_interner
|
||||
.alignment_bytes(element_layout)
|
||||
.max(env.target.ptr_width() as u32);
|
||||
|
||||
let mut is_all_constant = true;
|
||||
let zero_elements =
|
||||
(env.target.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
|
||||
let refcount_slot_bytes = alignment as usize;
|
||||
|
||||
// runtime-evaluated elements
|
||||
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena);
|
||||
let refcount_slot_elements =
|
||||
(refcount_slot_bytes as f64 / element_width as f64).ceil() as usize;
|
||||
|
||||
// set up a global that contains all the literal elements of the array
|
||||
// any variables or expressions are represented as `undef`
|
||||
let global = {
|
||||
let mut global_elements = Vec::with_capacity_in(list_length, env.arena);
|
||||
let data_bytes = list_length * element_width as usize;
|
||||
|
||||
// Add zero bytes that represent the refcount
|
||||
//
|
||||
// - if all elements are const, then we store the whole list as a constant.
|
||||
// It then needs a refcount before the first element.
|
||||
// - but if the list is not all constants, then we will just copy the constant values,
|
||||
// and we do not need that refcount at the start
|
||||
//
|
||||
// In the latter case, we won't store the zeros in the globals
|
||||
// (we slice them off again below)
|
||||
for _ in 0..zero_elements {
|
||||
global_elements.push(element_type.const_zero());
|
||||
assert!(refcount_slot_elements > 0);
|
||||
|
||||
let global = if element_type.is_int_type() {
|
||||
let element_type = element_type.into_int_type();
|
||||
let mut bytes = Vec::with_capacity_in(refcount_slot_elements + data_bytes, env.arena);
|
||||
|
||||
// Fill the refcount slot with nulls
|
||||
for _ in 0..(refcount_slot_elements) {
|
||||
bytes.push(element_type.const_zero());
|
||||
}
|
||||
|
||||
// Copy the elements from the list literal into the array
|
||||
for (index, element) in elems.iter().enumerate() {
|
||||
match element {
|
||||
ListLiteralElement::Literal(literal) => {
|
||||
let val = build_exp_literal(env, layout_interner, element_layout, literal);
|
||||
global_elements.push(val.into_int_value());
|
||||
}
|
||||
ListLiteralElement::Symbol(symbol) => {
|
||||
let val = scope.load_symbol(symbol);
|
||||
|
||||
// here we'd like to furthermore check for intval.is_const().
|
||||
// if all elements are const for LLVM, we could make the array a constant.
|
||||
// BUT morphic does not know about this, and could allow us to modify that
|
||||
// array in-place. That would cause a segfault. So, we'll have to find
|
||||
// constants ourselves and cannot lean on LLVM here.
|
||||
|
||||
is_all_constant = false;
|
||||
|
||||
runtime_evaluated_elements.push((index, val));
|
||||
|
||||
global_elements.push(element_type.get_undef());
|
||||
}
|
||||
};
|
||||
for element in elems.iter() {
|
||||
let literal = element.get_literal().expect("is_all_constant is true");
|
||||
let val = build_exp_literal(env, layout_interner, element_layout, &literal);
|
||||
bytes.push(val.into_int_value());
|
||||
}
|
||||
|
||||
let const_elements = if is_all_constant {
|
||||
global_elements.into_bump_slice()
|
||||
} else {
|
||||
&global_elements[zero_elements..]
|
||||
};
|
||||
|
||||
// use None for the address space (e.g. Const does not work)
|
||||
let typ = element_type.array_type(const_elements.len() as u32);
|
||||
let typ = element_type.array_type(bytes.len() as u32);
|
||||
let global = env.module.add_global(typ, None, "roc__list_literal");
|
||||
|
||||
global.set_constant(true);
|
||||
global.set_alignment(alignment);
|
||||
global.set_unnamed_addr(true);
|
||||
global.set_linkage(inkwell::module::Linkage::Private);
|
||||
global.set_initializer(&element_type.const_array(bytes.into_bump_slice()));
|
||||
global
|
||||
} else if element_type.is_float_type() {
|
||||
let element_type = element_type.into_float_type();
|
||||
let mut bytes = Vec::with_capacity_in(refcount_slot_elements + data_bytes, env.arena);
|
||||
|
||||
global.set_initializer(&element_type.const_array(const_elements));
|
||||
global.as_pointer_value()
|
||||
};
|
||||
|
||||
if is_all_constant {
|
||||
// all elements are constants, so we can use the memory in the constants section directly
|
||||
// here we make a pointer to the first actual element (skipping the 0 bytes that
|
||||
// represent the refcount)
|
||||
let zero = env.ptr_int().const_zero();
|
||||
let offset = env.ptr_int().const_int(zero_elements as _, false);
|
||||
|
||||
let ptr = unsafe {
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
element_type,
|
||||
global,
|
||||
&[zero, offset],
|
||||
"first_element_pointer",
|
||||
)
|
||||
};
|
||||
|
||||
super::build_list::store_list(env, ptr, list_length_intval).into()
|
||||
} else {
|
||||
// some of our elements are non-constant, so we must allocate space on the heap
|
||||
let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
||||
|
||||
// then, copy the relevant segment from the constant section into the heap
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
ptr,
|
||||
alignment,
|
||||
global,
|
||||
alignment,
|
||||
env.ptr_int().const_int(size as _, false),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// then replace the `undef`s with the values that we evaluate at runtime
|
||||
for (index, val) in runtime_evaluated_elements {
|
||||
let index_val = ctx.i64_type().const_int(index as u64, false);
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr, &[index_val], "index")
|
||||
};
|
||||
|
||||
builder.new_build_store(elem_ptr, val);
|
||||
// Fill the refcount slot with nulls
|
||||
for _ in 0..(refcount_slot_elements) {
|
||||
bytes.push(element_type.const_zero());
|
||||
}
|
||||
|
||||
super::build_list::store_list(env, ptr, list_length_intval).into()
|
||||
}
|
||||
// Copy the elements from the list literal into the array
|
||||
for element in elems.iter() {
|
||||
let literal = element.get_literal().expect("is_all_constant is true");
|
||||
let val = build_exp_literal(env, layout_interner, element_layout, &literal);
|
||||
bytes.push(val.into_float_value());
|
||||
}
|
||||
|
||||
let typ = element_type.array_type(bytes.len() as u32);
|
||||
let global = env.module.add_global(typ, None, "roc__list_literal");
|
||||
|
||||
global.set_initializer(&element_type.const_array(bytes.into_bump_slice()));
|
||||
global
|
||||
} else {
|
||||
internal_error!("unexpected element type: {:?}", element_type);
|
||||
};
|
||||
|
||||
global.set_constant(true);
|
||||
global.set_alignment(alignment);
|
||||
global.set_unnamed_addr(true);
|
||||
global.set_linkage(inkwell::module::Linkage::Private);
|
||||
|
||||
// Refcount the global itself in a new allocation.
|
||||
// Necessary because morphic MAY attempt to update the global in-place, which is
|
||||
// illegal if the global is in the read-only section.
|
||||
let with_rc_ptr = global.as_pointer_value();
|
||||
|
||||
let const_data_ptr = unsafe {
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
element_type,
|
||||
with_rc_ptr,
|
||||
&[env
|
||||
.ptr_int()
|
||||
.const_int(refcount_slot_elements as u64, false)],
|
||||
"get_data_ptr",
|
||||
)
|
||||
};
|
||||
|
||||
let data_ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
||||
|
||||
let byte_size = env
|
||||
.ptr_int()
|
||||
.const_int(list_length as u64 * element_width as u64, false);
|
||||
builder
|
||||
.build_memcpy(data_ptr, alignment, const_data_ptr, alignment, byte_size)
|
||||
.unwrap();
|
||||
|
||||
super::build_list::store_list(env, data_ptr, list_length_intval).into()
|
||||
} else {
|
||||
let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
||||
|
||||
|
|
|
@ -282,16 +282,9 @@ pub(crate) struct RocUnion<'ctx> {
|
|||
tag_type: Option<TagType>,
|
||||
}
|
||||
|
||||
fn is_multiple_of(big: u32, small: u32) -> bool {
|
||||
match small {
|
||||
0 => true, // 0 is a multiple of all n, because n * 0 = 0
|
||||
n => big % n == 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> RocUnion<'ctx> {
|
||||
pub const TAG_ID_INDEX: u32 = 2;
|
||||
pub const TAG_DATA_INDEX: u32 = 1;
|
||||
pub const TAG_ID_INDEX: u32 = 1;
|
||||
pub const TAG_DATA_INDEX: u32 = 0;
|
||||
|
||||
fn new(
|
||||
context: &'ctx Context,
|
||||
|
@ -301,45 +294,24 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
) -> Self {
|
||||
let bytes = round_up_to_alignment(data_width, data_align);
|
||||
|
||||
let byte_array_type = if is_multiple_of(bytes, 8) && is_multiple_of(data_align, 8) {
|
||||
context
|
||||
.i64_type()
|
||||
.array_type(bytes / 8)
|
||||
.as_basic_type_enum()
|
||||
} else {
|
||||
context.i8_type().array_type(bytes).as_basic_type_enum()
|
||||
};
|
||||
|
||||
let alignment_array_type = alignment_type(context, data_align)
|
||||
.array_type(0)
|
||||
let align_type = alignment_type(context, data_align);
|
||||
let byte_array_type = align_type
|
||||
.array_type(bytes / data_align)
|
||||
.as_basic_type_enum();
|
||||
|
||||
let struct_type = if let Some(tag_type) = tag_type {
|
||||
let tag_width = match tag_type {
|
||||
TagType::I8 => 1,
|
||||
TagType::I16 => 2,
|
||||
};
|
||||
|
||||
let tag_padding = round_up_to_alignment(tag_width, data_align) - tag_width;
|
||||
let tag_padding_type = context
|
||||
.i8_type()
|
||||
.array_type(tag_padding)
|
||||
.as_basic_type_enum();
|
||||
|
||||
context.struct_type(
|
||||
&[
|
||||
alignment_array_type,
|
||||
byte_array_type,
|
||||
match tag_type {
|
||||
TagType::I8 => context.i8_type().into(),
|
||||
TagType::I16 => context.i16_type().into(),
|
||||
},
|
||||
tag_padding_type,
|
||||
],
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
context.struct_type(&[alignment_array_type, byte_array_type], false)
|
||||
context.struct_type(&[byte_array_type], false)
|
||||
};
|
||||
|
||||
Self {
|
||||
|
|
|
@ -161,23 +161,6 @@ pub fn can_expr_with<'a>(
|
|||
// ensure the Test module is accessible in our tests
|
||||
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
// If we did this *during* canonicalization, then each time we
|
||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
|
@ -188,12 +171,23 @@ pub fn can_expr_with<'a>(
|
|||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
expr_str,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
// If we did this *during* canonicalization, then each time we
|
||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
|
||||
let (loc_expr, output) = canonicalize_expr(
|
||||
&mut env,
|
||||
&mut var_store,
|
||||
|
|
|
@ -4299,8 +4299,9 @@ mod test_reporting {
|
|||
4│ f :: I64
|
||||
^^
|
||||
|
||||
I have no specific suggestion for this operator, see TODO for the full
|
||||
list of operators in Roc.
|
||||
I have no specific suggestion for this operator, see
|
||||
https://www.roc-lang.org/tutorial#operator-desugaring-table for the
|
||||
full list of operators in Roc.
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -4339,6 +4340,14 @@ mod test_reporting {
|
|||
|
||||
However, I already saw the final expression in that series of
|
||||
definitions.
|
||||
|
||||
Tip: An expression like `4`, `"hello"`, or `functionCall MyThing` is
|
||||
like `return 4` in other programming languages. To me, it seems like
|
||||
you did `return 4` followed by more code in the lines after, that code
|
||||
would never be executed!
|
||||
|
||||
Tip: If you are working with `Task`, this error can happen if you
|
||||
forgot a `!` somewhere.
|
||||
"###
|
||||
);
|
||||
|
||||
|
@ -4972,30 +4981,6 @@ mod test_reporting {
|
|||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
record_builder_in_module_params,
|
||||
indoc!(
|
||||
r"
|
||||
import Menu {
|
||||
echo,
|
||||
name: <- applyName
|
||||
}
|
||||
"
|
||||
),@r###"
|
||||
── OLD-STYLE RECORD BUILDER IN MODULE PARAMS in ...r_in_module_params/Test.roc ─
|
||||
|
||||
I was partway through parsing module params, but I got stuck here:
|
||||
|
||||
4│ import Menu {
|
||||
5│ echo,
|
||||
6│ name: <- applyName
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This looks like an old-style record builder field, but those are not
|
||||
allowed in module params.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
record_update_in_module_params,
|
||||
indoc!(
|
||||
|
@ -6068,8 +6053,9 @@ All branches in an `if` must have the same type!
|
|||
5│ 5 ** 3
|
||||
^^
|
||||
|
||||
I have no specific suggestion for this operator, see TODO for the full
|
||||
list of operators in Roc.
|
||||
I have no specific suggestion for this operator, see
|
||||
https://www.roc-lang.org/tutorial#operator-desugaring-table for the
|
||||
full list of operators in Roc.
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -10661,163 +10647,6 @@ All branches in an `if` must have the same type!
|
|||
|
||||
// Record Builders
|
||||
|
||||
test_report!(
|
||||
optional_field_in_old_record_builder,
|
||||
indoc!(
|
||||
r#"
|
||||
{
|
||||
a: <- apply "a",
|
||||
b,
|
||||
c ? "optional"
|
||||
}
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── BAD OLD-STYLE RECORD BUILDER in ...nal_field_in_old_record_builder/Test.roc ─
|
||||
|
||||
I am partway through parsing a record builder, and I found an optional
|
||||
field:
|
||||
|
||||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ {
|
||||
5│ a: <- apply "a",
|
||||
6│ b,
|
||||
7│ c ? "optional"
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Optional fields can only appear when you destructure a record.
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
record_update_old_builder,
|
||||
indoc!(
|
||||
r#"
|
||||
{ rec &
|
||||
a: <- apply "a",
|
||||
b: 3
|
||||
}
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── BAD RECORD UPDATE in tmp/record_update_old_builder/Test.roc ─────────────────
|
||||
|
||||
I am partway through parsing a record update, and I found an old-style
|
||||
record builder field:
|
||||
|
||||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ { rec &
|
||||
5│ a: <- apply "a",
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Old-style record builders cannot be updated like records.
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
multiple_old_record_builders,
|
||||
indoc!(
|
||||
r#"
|
||||
succeed
|
||||
{ a: <- apply "a" }
|
||||
{ b: <- apply "b" }
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── MULTIPLE OLD-STYLE RECORD BUILDERS in /code/proj/Main.roc ───────────────────
|
||||
|
||||
This function is applied to multiple old-style record builders:
|
||||
|
||||
4│> succeed
|
||||
5│> { a: <- apply "a" }
|
||||
6│> { b: <- apply "b" }
|
||||
|
||||
Note: Functions can only take at most one old-style record builder!
|
||||
|
||||
Tip: You can combine them or apply them separately.
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
unapplied_old_record_builder,
|
||||
indoc!(
|
||||
r#"
|
||||
{ a: <- apply "a" }
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── UNAPPLIED OLD-STYLE RECORD BUILDER in /code/proj/Main.roc ───────────────────
|
||||
|
||||
This old-style record builder was not applied to a function:
|
||||
|
||||
4│ { a: <- apply "a" }
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
However, we need a function to construct the record.
|
||||
|
||||
Note: Functions must be applied directly. The pipe operator (|>) cannot be used.
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
old_record_builder_apply_non_function,
|
||||
indoc!(
|
||||
r#"
|
||||
succeed = \_ -> crash ""
|
||||
|
||||
succeed {
|
||||
a: <- "a",
|
||||
}
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── TOO MANY ARGS in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This value is not a function, but it was given 1 argument:
|
||||
|
||||
7│ a: <- "a",
|
||||
^^^
|
||||
|
||||
Tip: Remove <- to assign the field directly.
|
||||
"#
|
||||
);
|
||||
|
||||
// Skipping test because opaque types defined in the same module
|
||||
// do not fail with the special opaque type error
|
||||
//
|
||||
// test_report!(
|
||||
// record_builder_apply_opaque,
|
||||
// indoc!(
|
||||
// r#"
|
||||
// succeed = \_ -> crash ""
|
||||
|
||||
// Decode := {}
|
||||
|
||||
// get : Str -> Decode
|
||||
// get = \_ -> @Decode {}
|
||||
|
||||
// succeed {
|
||||
// a: <- get "a",
|
||||
// # missing |> apply ^
|
||||
// }
|
||||
// "#
|
||||
// ),
|
||||
// @r#"
|
||||
// ── TOO MANY ARGS in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
// This value is an opaque type, so it cannot be called with an argument:
|
||||
|
||||
// 12│ a: <- get "a",
|
||||
// ^^^^^^^
|
||||
|
||||
// Hint: Did you mean to apply it to a function first?
|
||||
// "#
|
||||
// );
|
||||
|
||||
test_report!(
|
||||
empty_record_builder,
|
||||
indoc!(
|
||||
|
@ -14521,7 +14350,7 @@ All branches in an `if` must have the same type!
|
|||
4│ 1 + dbg + 2
|
||||
^^^
|
||||
|
||||
This `63` value is a:
|
||||
This value is a:
|
||||
|
||||
{}
|
||||
|
||||
|
@ -14555,7 +14384,7 @@ All branches in an `if` must have the same type!
|
|||
4│ 1 + dbg "" "" + 2
|
||||
^^^^^^^^^
|
||||
|
||||
This `63` value is a:
|
||||
This value is a:
|
||||
|
||||
{}
|
||||
|
||||
|
|
|
@ -784,7 +784,7 @@ impl<'a> State<'a> {
|
|||
number_of_workers: usize,
|
||||
exec_mode: ExecutionMode,
|
||||
) -> Self {
|
||||
let cache_dir = roc_packaging::cache::roc_cache_dir();
|
||||
let cache_dir = roc_packaging::cache::roc_cache_packages_dir();
|
||||
let dependencies = Dependencies::new(exec_mode.goal_phase());
|
||||
|
||||
Self {
|
||||
|
@ -1665,7 +1665,7 @@ fn state_thread_step<'a>(
|
|||
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
||||
}
|
||||
Msg::FailedToReadFile { filename, error } => {
|
||||
let buf = to_file_problem_report_string(filename, error);
|
||||
let buf = to_file_problem_report_string(filename, error, true);
|
||||
Err(LoadingProblem::FormattedReport(buf))
|
||||
}
|
||||
|
||||
|
@ -1839,7 +1839,7 @@ pub fn report_loading_problem(
|
|||
}
|
||||
LoadingProblem::FormattedReport(report) => report,
|
||||
LoadingProblem::FileProblem { filename, error } => {
|
||||
to_file_problem_report_string(filename, error)
|
||||
to_file_problem_report_string(filename, error, true)
|
||||
}
|
||||
LoadingProblem::NoPlatformPackage {
|
||||
filename,
|
||||
|
|
|
@ -75,10 +75,6 @@ pub enum CalledVia {
|
|||
/// e.g. "$(first) $(last)" is transformed into Str.concat (Str.concat first " ") last.
|
||||
StringInterpolation,
|
||||
|
||||
/// This call is the result of desugaring an old style Record Builder field.
|
||||
/// e.g. succeed { a <- get "a" } is transformed into (get "a") (succeed \a -> { a })
|
||||
OldRecordBuilder,
|
||||
|
||||
/// This call is the result of desugaring a map2-based Record Builder field. e.g.
|
||||
/// ```roc
|
||||
/// { Task.parallel <-
|
||||
|
|
|
@ -123,6 +123,10 @@ impl Symbol {
|
|||
.any(|(_, (s, _))| *s == self)
|
||||
}
|
||||
|
||||
pub fn is_generated(self, interns: &Interns) -> bool {
|
||||
self.ident_ids(interns).is_generated_id(self.ident_id())
|
||||
}
|
||||
|
||||
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
|
||||
interns
|
||||
.module_ids
|
||||
|
@ -137,24 +141,15 @@ impl Symbol {
|
|||
}
|
||||
|
||||
pub fn as_str(self, interns: &Interns) -> &str {
|
||||
let ident_ids = interns
|
||||
.all_ident_ids
|
||||
.get(&self.module_id())
|
||||
self.ident_ids(interns)
|
||||
.get_name(self.ident_id())
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||
self.module_id(),
|
||||
interns
|
||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||
self.ident_id().0,
|
||||
self.module_id()
|
||||
)
|
||||
});
|
||||
|
||||
ident_ids.get_name(self.ident_id()).unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||
self.ident_id().0,
|
||||
self.module_id()
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn as_u64(self) -> u64 {
|
||||
|
@ -186,6 +181,19 @@ impl Symbol {
|
|||
pub fn contains(self, needle: &str) -> bool {
|
||||
format!("{self:?}").contains(needle)
|
||||
}
|
||||
|
||||
fn ident_ids(self, interns: &Interns) -> &IdentIds {
|
||||
interns
|
||||
.all_ident_ids
|
||||
.get(&self.module_id())
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||
self.module_id(),
|
||||
interns
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
|
@ -438,13 +446,6 @@ impl fmt::Debug for ModuleId {
|
|||
}
|
||||
}
|
||||
|
||||
/// pf.Task
|
||||
/// 1. build mapping from short name to package
|
||||
/// 2. when adding new modules from package we need to register them in some other map (this module id goes with short name) (shortname, module-name) -> moduleId
|
||||
/// 3. pass this around to other modules getting headers parsed. when parsing interfaces we need to use this map to reference shortnames
|
||||
/// 4. throw away short names. stash the module id in the can env under the resolved module name
|
||||
/// 5. test:
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum PackageQualified<'a, T> {
|
||||
Unqualified(T),
|
||||
|
@ -707,6 +708,12 @@ impl IdentIds {
|
|||
IdentId(self.interner.insert_index_str() as u32)
|
||||
}
|
||||
|
||||
pub fn is_generated_id(&self, id: IdentId) -> bool {
|
||||
self.interner
|
||||
.try_get(id.0 as usize)
|
||||
.map_or(false, |str| str.starts_with(|c: char| c.is_ascii_digit()))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
|
||||
self.interner
|
||||
|
@ -1373,6 +1380,8 @@ define_builtins! {
|
|||
46 STR_REPLACE_FIRST: "replaceFirst"
|
||||
47 STR_REPLACE_LAST: "replaceLast"
|
||||
48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity"
|
||||
49 STR_DROP_PREFIX: "dropPrefix"
|
||||
50 STR_DROP_SUFFIX: "dropSuffix"
|
||||
}
|
||||
6 LIST: "List" => {
|
||||
0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias
|
||||
|
|
|
@ -396,7 +396,7 @@ impl<'state, 'a> State<'state, 'a> {
|
|||
None => unreachable!(
|
||||
"\n\tNo borrow signature for {name:?} layout.\n\n\t\
|
||||
Tip 1: This can happen when you call a function with less arguments than it expects.\n\t\
|
||||
Like `Arg.list!` instead of `Arg.list! {{}}`.\n\t
|
||||
Like `Arg.list!` instead of `Arg.list! {{}}`.\n\t\
|
||||
Tip 2: `roc check yourfile.roc` can sometimes give you a helpful error.
|
||||
"
|
||||
)
|
||||
|
|
|
@ -49,6 +49,17 @@ impl<'a> ListLiteralElement<'a> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_literal(&self) -> Option<Literal<'a>> {
|
||||
match self {
|
||||
Self::Literal(l) => Some(*l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_literal(&self) -> bool {
|
||||
matches!(self, Self::Literal(_))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NumLiteral {
|
||||
|
|
|
@ -456,13 +456,6 @@ pub enum Expr<'a> {
|
|||
|
||||
Tuple(Collection<'a, &'a Loc<Expr<'a>>>),
|
||||
|
||||
// Record Builders
|
||||
/// Applicative record builders, e.g.
|
||||
/// build {
|
||||
/// foo: <- getData Foo,
|
||||
/// bar: <- getData Bar,
|
||||
/// }
|
||||
OldRecordBuilder(Collection<'a, Loc<OldRecordBuilderField<'a>>>),
|
||||
/// Mapper-based record builders, e.g.
|
||||
/// { Task.parallel <-
|
||||
/// foo: Task.getData Foo,
|
||||
|
@ -512,7 +505,11 @@ pub enum Expr<'a> {
|
|||
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
||||
|
||||
// Conditionals
|
||||
If(&'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)], &'a Loc<Expr<'a>>),
|
||||
If {
|
||||
if_thens: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
||||
final_else: &'a Loc<Expr<'a>>,
|
||||
indented_else: bool,
|
||||
},
|
||||
When(
|
||||
/// The condition
|
||||
&'a Loc<Expr<'a>>,
|
||||
|
@ -537,8 +534,6 @@ pub enum Expr<'a> {
|
|||
// Both operators were non-associative, e.g. (True == False == False).
|
||||
// We should tell the author to disambiguate by grouping them with parens.
|
||||
PrecedenceConflict(&'a PrecedenceConflict<'a>),
|
||||
MultipleOldRecordBuilders(&'a Loc<Expr<'a>>),
|
||||
UnappliedOldRecordBuilder(&'a Loc<Expr<'a>>),
|
||||
EmptyRecordBuilder(&'a Loc<Expr<'a>>),
|
||||
SingleFieldRecordBuilder(&'a Loc<Expr<'a>>),
|
||||
OptionalFieldInRecordBuilder(&'a Loc<&'a str>, &'a Loc<Expr<'a>>),
|
||||
|
@ -608,7 +603,11 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
}
|
||||
|
||||
// expression in a if-then-else, `if isOk! then "ok" else doSomething!`
|
||||
Expr::If(if_thens, final_else) => {
|
||||
Expr::If {
|
||||
if_thens,
|
||||
final_else,
|
||||
..
|
||||
} => {
|
||||
let any_if_thens_suffixed = if_thens.iter().any(|(if_then, else_expr)| {
|
||||
is_expr_suffixed(&if_then.value) || is_expr_suffixed(&else_expr.value)
|
||||
});
|
||||
|
@ -655,9 +654,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
.iter()
|
||||
.any(|field| is_assigned_value_suffixed(&field.value)),
|
||||
Expr::Tuple(items) => items.iter().any(|x| is_expr_suffixed(&x.value)),
|
||||
Expr::OldRecordBuilder(items) => items
|
||||
.iter()
|
||||
.any(|rbf| is_record_builder_field_suffixed(&rbf.value)),
|
||||
Expr::RecordBuilder { mapper: _, fields } => fields
|
||||
.iter()
|
||||
.any(|field| is_assigned_value_suffixed(&field.value)),
|
||||
|
@ -680,8 +676,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::MalformedClosure => false,
|
||||
Expr::MalformedSuffixed(_) => false,
|
||||
Expr::PrecedenceConflict(_) => false,
|
||||
Expr::MultipleOldRecordBuilders(_) => false,
|
||||
Expr::UnappliedOldRecordBuilder(_) => false,
|
||||
Expr::EmptyRecordBuilder(_) => false,
|
||||
Expr::SingleFieldRecordBuilder(_) => false,
|
||||
Expr::OptionalFieldInRecordBuilder(_, _) => false,
|
||||
|
@ -709,17 +703,6 @@ fn is_assigned_value_suffixed<'a>(value: &AssignedField<'a, Expr<'a>>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_record_builder_field_suffixed(field: &OldRecordBuilderField<'_>) -> bool {
|
||||
match field {
|
||||
OldRecordBuilderField::Value(_, _, a) => is_expr_suffixed(&a.value),
|
||||
OldRecordBuilderField::ApplyValue(_, _, _, a) => is_expr_suffixed(&a.value),
|
||||
OldRecordBuilderField::LabelOnly(_) => false,
|
||||
OldRecordBuilderField::SpaceBefore(a, _) => is_record_builder_field_suffixed(a),
|
||||
OldRecordBuilderField::SpaceAfter(a, _) => is_record_builder_field_suffixed(a),
|
||||
OldRecordBuilderField::Malformed(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_around<T>(items: &[T], target: usize) -> (&[T], &[T]) {
|
||||
let (before, rest) = items.split_at(target);
|
||||
let after = &rest[1..];
|
||||
|
@ -927,26 +910,6 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&loc_expr.value);
|
||||
}
|
||||
}
|
||||
OldRecordBuilder(fields) => {
|
||||
expr_stack.reserve(fields.len());
|
||||
for loc_record_builder_field in fields.items {
|
||||
let mut current_field = loc_record_builder_field.value;
|
||||
|
||||
loop {
|
||||
use OldRecordBuilderField::*;
|
||||
|
||||
match current_field {
|
||||
Value(_, _, loc_val) => break expr_stack.push(&loc_val.value),
|
||||
ApplyValue(_, _, _, loc_val) => {
|
||||
break expr_stack.push(&loc_val.value)
|
||||
}
|
||||
SpaceBefore(next_field, _) => current_field = *next_field,
|
||||
SpaceAfter(next_field, _) => current_field = *next_field,
|
||||
LabelOnly(_) | Malformed(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RecordBuilder {
|
||||
mapper: map2,
|
||||
fields,
|
||||
|
@ -993,14 +956,18 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&expr.value);
|
||||
}
|
||||
UnaryOp(expr, _) => expr_stack.push(&expr.value),
|
||||
If(ifs, alternate) => {
|
||||
expr_stack.reserve(ifs.len() * 2 + 1);
|
||||
If {
|
||||
if_thens,
|
||||
final_else,
|
||||
..
|
||||
} => {
|
||||
expr_stack.reserve(if_thens.len() * 2 + 1);
|
||||
|
||||
for (condition, consequent) in ifs.iter() {
|
||||
for (condition, consequent) in if_thens.iter() {
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&consequent.value);
|
||||
}
|
||||
expr_stack.push(&alternate.value);
|
||||
expr_stack.push(&final_else.value);
|
||||
}
|
||||
When(condition, branches) => {
|
||||
expr_stack.reserve(branches.len() + 1);
|
||||
|
@ -1027,9 +994,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| SpaceAfter(expr, _)
|
||||
| ParensAround(expr) => expr_stack.push(expr),
|
||||
|
||||
MultipleOldRecordBuilders(loc_expr)
|
||||
| UnappliedOldRecordBuilder(loc_expr)
|
||||
| EmptyRecordBuilder(loc_expr)
|
||||
EmptyRecordBuilder(loc_expr)
|
||||
| SingleFieldRecordBuilder(loc_expr)
|
||||
| OptionalFieldInRecordBuilder(_, loc_expr) => expr_stack.push(&loc_expr.value),
|
||||
|
||||
|
@ -1655,30 +1620,6 @@ impl<'a, Val> AssignedField<'a, Val> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum OldRecordBuilderField<'a> {
|
||||
// A field with a value, e.g. `{ name: "blah" }`
|
||||
Value(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
||||
|
||||
// A field with a function we can apply to build part of the record, e.g. `{ name: <- apply getName }`
|
||||
ApplyValue(
|
||||
Loc<&'a str>,
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a Loc<Expr<'a>>,
|
||||
),
|
||||
|
||||
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
||||
LabelOnly(Loc<&'a str>),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
||||
/// A malformed assigned field, which will code gen to a runtime error
|
||||
Malformed(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CommentOrNewline<'a> {
|
||||
Newline,
|
||||
|
@ -2213,15 +2154,6 @@ impl<'a, Val> Spaceable<'a> for AssignedField<'a, Val> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for OldRecordBuilderField<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
OldRecordBuilderField::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
OldRecordBuilderField::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for Tag<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Tag::SpaceBefore(self, spaces)
|
||||
|
@ -2524,7 +2456,6 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Record(items) => items.is_malformed(),
|
||||
Tuple(items) => items.is_malformed(),
|
||||
|
||||
OldRecordBuilder(items) => items.is_malformed(),
|
||||
RecordBuilder { mapper: map2, fields } => map2.is_malformed() || fields.is_malformed(),
|
||||
|
||||
Closure(args, body) => args.iter().any(|arg| arg.is_malformed()) || body.is_malformed(),
|
||||
|
@ -2537,7 +2468,7 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
||||
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
||||
UnaryOp(expr, _) => expr.is_malformed(),
|
||||
If(chain, els) => chain.iter().any(|(cond, body)| cond.is_malformed() || body.is_malformed()) || els.is_malformed(),
|
||||
If { if_thens, final_else, ..} => if_thens.iter().any(|(cond, body)| cond.is_malformed() || body.is_malformed()) || final_else.is_malformed(),
|
||||
When(cond, branches) => cond.is_malformed() || branches.iter().any(|branch| branch.is_malformed()),
|
||||
|
||||
SpaceBefore(expr, _) |
|
||||
|
@ -2548,8 +2479,6 @@ impl<'a> Malformed for Expr<'a> {
|
|||
MalformedClosure |
|
||||
MalformedSuffixed(..) |
|
||||
PrecedenceConflict(_) |
|
||||
MultipleOldRecordBuilders(_) |
|
||||
UnappliedOldRecordBuilder(_) |
|
||||
EmptyRecordBuilder(_) |
|
||||
SingleFieldRecordBuilder(_) |
|
||||
OptionalFieldInRecordBuilder(_, _) => true,
|
||||
|
@ -2629,19 +2558,6 @@ impl<'a, T: Malformed> Malformed for AssignedField<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for OldRecordBuilderField<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
OldRecordBuilderField::Value(_, _, expr)
|
||||
| OldRecordBuilderField::ApplyValue(_, _, _, expr) => expr.is_malformed(),
|
||||
OldRecordBuilderField::LabelOnly(_) => false,
|
||||
OldRecordBuilderField::SpaceBefore(field, _)
|
||||
| OldRecordBuilderField::SpaceAfter(field, _) => field.is_malformed(),
|
||||
OldRecordBuilderField::Malformed(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for Pattern<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
use Pattern::*;
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::ast::{
|
|||
is_expr_suffixed, AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces,
|
||||
Implements, ImplementsAbilities, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
||||
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
||||
ModuleImportParams, OldRecordBuilderField, Pattern, Spaceable, Spaced, Spaces, SpacesBefore,
|
||||
TryTarget, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
ModuleImportParams, Pattern, Spaceable, Spaced, Spaces, SpacesBefore, TryTarget,
|
||||
TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
loc_space0_e, require_newline_or_eof, space0_after_e, space0_around_ee, space0_before_e,
|
||||
|
@ -925,15 +925,11 @@ fn import_params<'a>() -> impl Parser<'a, ModuleImportParams<'a>, EImportParams<
|
|||
.fields
|
||||
.map_items_result(arena, |loc_field| {
|
||||
match loc_field.value.to_assigned_field(arena) {
|
||||
Ok(AssignedField::IgnoredValue(_, _, _)) => Err((
|
||||
AssignedField::IgnoredValue(_, _, _) => Err((
|
||||
MadeProgress,
|
||||
EImportParams::RecordIgnoredFieldFound(loc_field.region),
|
||||
)),
|
||||
Ok(field) => Ok(Loc::at(loc_field.region, field)),
|
||||
Err(FoundApplyValue) => Err((
|
||||
MadeProgress,
|
||||
EImportParams::RecordApplyFound(loc_field.region),
|
||||
)),
|
||||
field => Ok(Loc::at(loc_field.region, field)),
|
||||
}
|
||||
})?;
|
||||
|
||||
|
@ -2170,7 +2166,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::Backpassing(_, _, _)
|
||||
| Expr::BinOps { .. }
|
||||
| Expr::Defs(_, _)
|
||||
| Expr::If(_, _)
|
||||
| Expr::If { .. }
|
||||
| Expr::When(_, _)
|
||||
| Expr::Expect(_, _)
|
||||
| Expr::Dbg
|
||||
|
@ -2179,8 +2175,6 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::MalformedClosure
|
||||
| Expr::MalformedSuffixed(..)
|
||||
| Expr::PrecedenceConflict { .. }
|
||||
| Expr::MultipleOldRecordBuilders { .. }
|
||||
| Expr::UnappliedOldRecordBuilder { .. }
|
||||
| Expr::EmptyRecordBuilder(_)
|
||||
| Expr::SingleFieldRecordBuilder(_)
|
||||
| Expr::OptionalFieldInRecordBuilder(_, _)
|
||||
|
@ -2189,7 +2183,6 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::UnaryOp(_, _)
|
||||
| Expr::TrySuffix { .. }
|
||||
| Expr::Crash
|
||||
| Expr::OldRecordBuilder(..)
|
||||
| Expr::RecordBuilder { .. } => return Err(()),
|
||||
|
||||
Expr::Str(string) => Pattern::StrLiteral(string),
|
||||
|
@ -2704,6 +2697,8 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
|||
let (_, _, state) =
|
||||
parser::keyword(keyword::IF, EIf::If).parse(arena, state, min_indent)?;
|
||||
|
||||
let if_indent = state.line_indent();
|
||||
|
||||
let mut branches = Vec::with_capacity_in(1, arena);
|
||||
|
||||
let mut loop_state = state;
|
||||
|
@ -2730,16 +2725,37 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
|||
}
|
||||
};
|
||||
|
||||
let (_, else_branch, state) = parse_block(
|
||||
let else_indent = state_final_else.line_indent();
|
||||
let indented_else = else_indent > if_indent;
|
||||
|
||||
let min_indent = if !indented_else {
|
||||
else_indent + 1
|
||||
} else {
|
||||
if_indent
|
||||
};
|
||||
|
||||
let (_, loc_first_space, state_final_else) =
|
||||
loc_space0_e(EIf::IndentElseBranch).parse(arena, state_final_else, min_indent)?;
|
||||
|
||||
let allow_defs = !loc_first_space.value.is_empty();
|
||||
|
||||
// use parse_block_inner so we can set min_indent
|
||||
let (_, else_branch, state) = parse_block_inner(
|
||||
options,
|
||||
arena,
|
||||
state_final_else,
|
||||
true,
|
||||
min_indent,
|
||||
EIf::IndentElseBranch,
|
||||
EIf::ElseBranch,
|
||||
loc_first_space,
|
||||
allow_defs,
|
||||
)?;
|
||||
|
||||
let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch));
|
||||
let expr = Expr::If {
|
||||
if_thens: branches.into_bump_slice(),
|
||||
final_else: arena.alloc(else_branch),
|
||||
indented_else,
|
||||
};
|
||||
|
||||
Ok((MadeProgress, expr, state))
|
||||
}
|
||||
|
@ -3367,38 +3383,12 @@ pub enum RecordField<'a> {
|
|||
LabelOnly(Loc<&'a str>),
|
||||
SpaceBefore(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
||||
ApplyValue(
|
||||
Loc<&'a str>,
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a Loc<Expr<'a>>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FoundApplyValue;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NotOldBuilderFieldValue {
|
||||
FoundOptionalValue,
|
||||
FoundIgnoredValue,
|
||||
}
|
||||
|
||||
impl<'a> RecordField<'a> {
|
||||
fn is_apply_value(&self) -> bool {
|
||||
let mut current = self;
|
||||
|
||||
loop {
|
||||
match current {
|
||||
RecordField::ApplyValue(_, _, _, _) => break true,
|
||||
RecordField::SpaceBefore(field, _) | RecordField::SpaceAfter(field, _) => {
|
||||
current = *field;
|
||||
}
|
||||
_ => break false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ignored_value(&self) -> bool {
|
||||
let mut current = self;
|
||||
|
||||
|
@ -3413,74 +3403,34 @@ impl<'a> RecordField<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_assigned_field(
|
||||
self,
|
||||
arena: &'a Bump,
|
||||
) -> Result<AssignedField<'a, Expr<'a>>, FoundApplyValue> {
|
||||
pub fn to_assigned_field(self, arena: &'a Bump) -> AssignedField<'a, Expr<'a>> {
|
||||
use AssignedField::*;
|
||||
|
||||
match self {
|
||||
RecordField::RequiredValue(loc_label, spaces, loc_expr) => {
|
||||
Ok(RequiredValue(loc_label, spaces, loc_expr))
|
||||
RequiredValue(loc_label, spaces, loc_expr)
|
||||
}
|
||||
|
||||
RecordField::OptionalValue(loc_label, spaces, loc_expr) => {
|
||||
Ok(OptionalValue(loc_label, spaces, loc_expr))
|
||||
OptionalValue(loc_label, spaces, loc_expr)
|
||||
}
|
||||
|
||||
RecordField::IgnoredValue(loc_label, spaces, loc_expr) => {
|
||||
Ok(IgnoredValue(loc_label, spaces, loc_expr))
|
||||
IgnoredValue(loc_label, spaces, loc_expr)
|
||||
}
|
||||
|
||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
||||
|
||||
RecordField::ApplyValue(_, _, _, _) => Err(FoundApplyValue),
|
||||
RecordField::LabelOnly(loc_label) => LabelOnly(loc_label),
|
||||
|
||||
RecordField::SpaceBefore(field, spaces) => {
|
||||
let assigned_field = field.to_assigned_field(arena)?;
|
||||
let assigned_field = field.to_assigned_field(arena);
|
||||
|
||||
Ok(SpaceBefore(arena.alloc(assigned_field), spaces))
|
||||
SpaceBefore(arena.alloc(assigned_field), spaces)
|
||||
}
|
||||
|
||||
RecordField::SpaceAfter(field, spaces) => {
|
||||
let assigned_field = field.to_assigned_field(arena)?;
|
||||
let assigned_field = field.to_assigned_field(arena);
|
||||
|
||||
Ok(SpaceAfter(arena.alloc(assigned_field), spaces))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_builder_field(
|
||||
self,
|
||||
arena: &'a Bump,
|
||||
) -> Result<OldRecordBuilderField<'a>, NotOldBuilderFieldValue> {
|
||||
use OldRecordBuilderField::*;
|
||||
|
||||
match self {
|
||||
RecordField::RequiredValue(loc_label, spaces, loc_expr) => {
|
||||
Ok(Value(loc_label, spaces, loc_expr))
|
||||
}
|
||||
|
||||
RecordField::OptionalValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundOptionalValue),
|
||||
|
||||
RecordField::IgnoredValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundIgnoredValue),
|
||||
|
||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
||||
|
||||
RecordField::ApplyValue(loc_label, colon_spaces, arrow_spaces, loc_expr) => {
|
||||
Ok(ApplyValue(loc_label, colon_spaces, arrow_spaces, loc_expr))
|
||||
}
|
||||
|
||||
RecordField::SpaceBefore(field, spaces) => {
|
||||
let builder_field = field.to_builder_field(arena)?;
|
||||
|
||||
Ok(SpaceBefore(arena.alloc(builder_field), spaces))
|
||||
}
|
||||
|
||||
RecordField::SpaceAfter(field, spaces) => {
|
||||
let builder_field = field.to_builder_field(arena)?;
|
||||
|
||||
Ok(SpaceAfter(arena.alloc(builder_field), spaces))
|
||||
SpaceAfter(arena.alloc(assigned_field), spaces)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3534,14 +3484,10 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
|||
match field_data {
|
||||
Either::First((loc_label, (spaces, opt_loc_val))) => {
|
||||
match opt_loc_val {
|
||||
Some(Either::First((_, RecordFieldExpr::Value(loc_val)))) => {
|
||||
Some(Either::First((_, loc_val))) => {
|
||||
RequiredValue(loc_label, spaces, arena.alloc(loc_val))
|
||||
}
|
||||
|
||||
Some(Either::First((_, RecordFieldExpr::Apply(arrow_spaces, loc_val)))) => {
|
||||
ApplyValue(loc_label, spaces, arrow_spaces, arena.alloc(loc_val))
|
||||
}
|
||||
|
||||
Some(Either::Second((_, loc_val))) => {
|
||||
OptionalValue(loc_label, spaces, arena.alloc(loc_val))
|
||||
}
|
||||
|
@ -3568,34 +3514,17 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
|||
)
|
||||
}
|
||||
|
||||
enum RecordFieldExpr<'a> {
|
||||
Apply(&'a [CommentOrNewline<'a>], Loc<Expr<'a>>),
|
||||
Value(Loc<Expr<'a>>),
|
||||
}
|
||||
|
||||
fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> {
|
||||
fn record_field_expr<'a>() -> impl Parser<'a, Loc<Expr<'a>>, ERecord<'a>> {
|
||||
map_with_arena(
|
||||
and(
|
||||
spaces(),
|
||||
either(
|
||||
and(
|
||||
two_bytes(b'<', b'-', ERecord::Arrow),
|
||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||
),
|
||||
specialize_err_ref(ERecord::Expr, loc_expr(false)),
|
||||
),
|
||||
),
|
||||
|arena: &'a bumpalo::Bump, (spaces, either)| match either {
|
||||
Either::First((_, loc_expr)) => RecordFieldExpr::Apply(spaces, loc_expr),
|
||||
Either::Second(loc_expr) => RecordFieldExpr::Value({
|
||||
if spaces.is_empty() {
|
||||
loc_expr
|
||||
} else {
|
||||
arena
|
||||
.alloc(loc_expr.value)
|
||||
.with_spaces_before(spaces, loc_expr.region)
|
||||
}
|
||||
}),
|
||||
and(spaces(), specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||
|arena: &'a bumpalo::Bump, (spaces, loc_expr)| {
|
||||
if spaces.is_empty() {
|
||||
loc_expr
|
||||
} else {
|
||||
arena
|
||||
.alloc(loc_expr.value)
|
||||
.with_spaces_before(spaces, loc_expr.region)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -3663,13 +3592,11 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
|||
record_update_help(arena, update, record.fields)
|
||||
}
|
||||
Some((mapper, RecordHelpPrefix::Mapper)) => {
|
||||
new_record_builder_help(arena, mapper, record.fields)
|
||||
record_builder_help(arena, mapper, record.fields)
|
||||
}
|
||||
None => {
|
||||
let special_field_found = record.fields.iter().find_map(|field| {
|
||||
if field.value.is_apply_value() {
|
||||
Some(old_record_builder_help(arena, record.fields))
|
||||
} else if field.value.is_ignored_value() {
|
||||
if field.value.is_ignored_value() {
|
||||
Some(Err(EExpr::RecordUpdateIgnoredField(field.region)))
|
||||
} else {
|
||||
None
|
||||
|
@ -3678,7 +3605,7 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
|||
|
||||
special_field_found.unwrap_or_else(|| {
|
||||
let fields = record.fields.map_items(arena, |loc_field| {
|
||||
loc_field.map(|field| field.to_assigned_field(arena).unwrap())
|
||||
loc_field.map(|field| field.to_assigned_field(arena))
|
||||
});
|
||||
|
||||
Ok(Expr::Record(fields))
|
||||
|
@ -3705,14 +3632,13 @@ fn record_update_help<'a>(
|
|||
) -> Result<Expr<'a>, EExpr<'a>> {
|
||||
let result = fields.map_items_result(arena, |loc_field| {
|
||||
match loc_field.value.to_assigned_field(arena) {
|
||||
Ok(AssignedField::IgnoredValue(_, _, _)) => {
|
||||
AssignedField::IgnoredValue(_, _, _) => {
|
||||
Err(EExpr::RecordUpdateIgnoredField(loc_field.region))
|
||||
}
|
||||
Ok(builder_field) => Ok(Loc {
|
||||
builder_field => Ok(Loc {
|
||||
region: loc_field.region,
|
||||
value: builder_field,
|
||||
}),
|
||||
Err(FoundApplyValue) => Err(EExpr::RecordUpdateOldBuilderField(loc_field.region)),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3722,19 +3648,18 @@ fn record_update_help<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
fn new_record_builder_help<'a>(
|
||||
fn record_builder_help<'a>(
|
||||
arena: &'a Bump,
|
||||
mapper: Loc<Expr<'a>>,
|
||||
fields: Collection<'a, Loc<RecordField<'a>>>,
|
||||
) -> Result<Expr<'a>, EExpr<'a>> {
|
||||
let result = fields.map_items_result(arena, |loc_field| {
|
||||
match loc_field.value.to_assigned_field(arena) {
|
||||
Ok(builder_field) => Ok(Loc {
|
||||
region: loc_field.region,
|
||||
value: builder_field,
|
||||
}),
|
||||
Err(FoundApplyValue) => Err(EExpr::RecordBuilderOldBuilderField(loc_field.region)),
|
||||
}
|
||||
let builder_field = loc_field.value.to_assigned_field(arena);
|
||||
|
||||
Ok(Loc {
|
||||
region: loc_field.region,
|
||||
value: builder_field,
|
||||
})
|
||||
});
|
||||
|
||||
result.map(|fields| Expr::RecordBuilder {
|
||||
|
@ -3743,28 +3668,6 @@ fn new_record_builder_help<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
fn old_record_builder_help<'a>(
|
||||
arena: &'a Bump,
|
||||
fields: Collection<'a, Loc<RecordField<'a>>>,
|
||||
) -> Result<Expr<'a>, EExpr<'a>> {
|
||||
let result = fields.map_items_result(arena, |loc_field| {
|
||||
match loc_field.value.to_builder_field(arena) {
|
||||
Ok(builder_field) => Ok(Loc {
|
||||
region: loc_field.region,
|
||||
value: builder_field,
|
||||
}),
|
||||
Err(NotOldBuilderFieldValue::FoundOptionalValue) => {
|
||||
Err(EExpr::OptionalValueInOldRecordBuilder(loc_field.region))
|
||||
}
|
||||
Err(NotOldBuilderFieldValue::FoundIgnoredValue) => {
|
||||
Err(EExpr::IgnoredValueInOldRecordBuilder(loc_field.region))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
result.map(Expr::OldRecordBuilder)
|
||||
}
|
||||
|
||||
fn apply_expr_access_chain<'a>(
|
||||
arena: &'a Bump,
|
||||
value: Expr<'a>,
|
||||
|
|
|
@ -1258,13 +1258,13 @@ pub struct PlatformHeader<'a> {
|
|||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ImportsEntry<'a> {
|
||||
/// e.g. `Task` or `Task.{ Task, after }`
|
||||
/// e.g. `Hello` or `Hello exposing [hello]` see roc-lang.org/examples/MultipleRocFiles/README.html
|
||||
Module(
|
||||
ModuleName<'a>,
|
||||
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||
),
|
||||
|
||||
/// e.g. `pf.Task` or `pf.Task.{ after }` or `pf.{ Task.{ Task, after } }`
|
||||
/// e.g. `pf.Stdout` or `pf.Stdout exposing [line]`
|
||||
Package(
|
||||
&'a str,
|
||||
ModuleName<'a>,
|
||||
|
|
|
@ -1,905 +0,0 @@
|
|||
use crate::ast::{Collection, CommentOrNewline, Defs, Header, Module, Spaced, Spaces};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::expr::merge_spaces;
|
||||
use crate::header::{
|
||||
package_entry, package_name, AppHeader, ExposedName, ExposesKeyword, HostedHeader,
|
||||
ImportsCollection, ImportsEntry, ImportsKeyword, ImportsKeywordItem, Keyword, KeywordItem,
|
||||
ModuleHeader, ModuleName, ModuleParams, PackageEntry, PackageHeader, PackagesKeyword,
|
||||
PlatformHeader, PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword,
|
||||
TypedIdent,
|
||||
};
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map,
|
||||
map_with_arena, optional, reset_min_indent, skip_first, skip_second, specialize_err, succeed,
|
||||
two_bytes, zero_or_more, EExposes, EHeader, EImports, EPackages, EParams, EProvides, ERequires,
|
||||
ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||
};
|
||||
use crate::pattern::record_pattern_fields;
|
||||
use crate::state::State;
|
||||
use crate::string_literal::{self, parse_str_literal};
|
||||
use crate::type_annotation;
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||
|_arena, state: State<'a>, _min_indent: u32| {
|
||||
if state.has_reached_end() {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
Err((NoProgress, SyntaxError::NotEndOfFile(state.pos())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_module_defs<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
defs: Defs<'a>,
|
||||
) -> Result<Defs<'a>, SyntaxError<'a>> {
|
||||
let min_indent = 0;
|
||||
match crate::expr::parse_top_level_defs(arena, state.clone(), defs) {
|
||||
Ok((_, defs, state)) => match end_of_file().parse(arena, state, min_indent) {
|
||||
Ok(_) => Ok(defs),
|
||||
Err((_, fail)) => Err(fail),
|
||||
},
|
||||
Err((_, fail)) => Err(SyntaxError::Expr(fail, state.pos())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_header<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
) -> Result<(Module<'a>, State<'a>), SourceError<'a, EHeader<'a>>> {
|
||||
let min_indent = 0;
|
||||
match header().parse(arena, state.clone(), min_indent) {
|
||||
Ok((_, module, state)) => Ok((module, state)),
|
||||
Err((_, fail)) => Err(SourceError::new(fail, &state)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
||||
use crate::parser::keyword;
|
||||
|
||||
record!(Module {
|
||||
comments: space0_e(EHeader::IndentStart),
|
||||
header: one_of![
|
||||
map(
|
||||
skip_first(
|
||||
keyword("module", EHeader::Start),
|
||||
increment_min_indent(module_header())
|
||||
),
|
||||
Header::Module
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("interface", EHeader::Start),
|
||||
increment_min_indent(interface_header())
|
||||
),
|
||||
Header::Module
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("app", EHeader::Start),
|
||||
increment_min_indent(one_of![app_header(), old_app_header()])
|
||||
),
|
||||
Header::App
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("package", EHeader::Start),
|
||||
increment_min_indent(one_of![package_header(), old_package_header()])
|
||||
),
|
||||
Header::Package
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("platform", EHeader::Start),
|
||||
increment_min_indent(platform_header())
|
||||
),
|
||||
Header::Platform
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("hosted", EHeader::Start),
|
||||
increment_min_indent(hosted_header())
|
||||
),
|
||||
Header::Hosted
|
||||
),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn module_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
record!(ModuleHeader {
|
||||
after_keyword: space0_e(EHeader::IndentStart),
|
||||
params: optional(specialize_err(EHeader::Params, module_params())),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()),
|
||||
interface_imports: succeed(None)
|
||||
})
|
||||
.trace("module_header")
|
||||
}
|
||||
|
||||
fn module_params<'a>() -> impl Parser<'a, ModuleParams<'a>, EParams<'a>> {
|
||||
record!(ModuleParams {
|
||||
params: specialize_err(EParams::Pattern, record_pattern_fields()),
|
||||
before_arrow: skip_second(
|
||||
space0_e(EParams::BeforeArrow),
|
||||
loc(two_bytes(b'-', b'>', EParams::Arrow))
|
||||
),
|
||||
after_arrow: space0_e(EParams::AfterArrow),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO does this need to be a macro?
|
||||
macro_rules! merge_n_spaces {
|
||||
($arena:expr, $($slice:expr),*) => {
|
||||
{
|
||||
let mut merged = bumpalo::collections::Vec::with_capacity_in(0 $(+ $slice.len())*, $arena);
|
||||
$(merged.extend_from_slice($slice);)*
|
||||
merged.into_bump_slice()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse old interface headers so we can format them into module headers
|
||||
#[inline(always)]
|
||||
fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
let after_keyword = map_with_arena(
|
||||
and(
|
||||
skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
loc(module_name_help(EHeader::ModuleName)),
|
||||
),
|
||||
specialize_err(EHeader::Exposes, exposes_kw()),
|
||||
),
|
||||
|arena: &'a bumpalo::Bump,
|
||||
(before_name, kw): (&'a [CommentOrNewline<'a>], Spaces<'a, ExposesKeyword>)| {
|
||||
merge_n_spaces!(arena, before_name, kw.before, kw.after)
|
||||
},
|
||||
);
|
||||
|
||||
record!(ModuleHeader {
|
||||
after_keyword: after_keyword,
|
||||
params: succeed(None),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()).trace("exposes_list"),
|
||||
interface_imports: map(
|
||||
specialize_err(EHeader::Imports, imports()),
|
||||
imports_none_if_empty
|
||||
)
|
||||
.trace("imports"),
|
||||
})
|
||||
.trace("interface_header")
|
||||
}
|
||||
|
||||
fn imports_none_if_empty(value: ImportsKeywordItem<'_>) -> Option<ImportsKeywordItem<'_>> {
|
||||
if value.item.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|
||||
record!(HostedHeader {
|
||||
before_name: space0_e(EHeader::IndentStart),
|
||||
name: loc(module_name_help(EHeader::ModuleName)),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_values_kw()),
|
||||
imports: specialize_err(EHeader::Imports, imports()),
|
||||
})
|
||||
.trace("hosted_header")
|
||||
}
|
||||
|
||||
fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
use encode_unicode::CharExt;
|
||||
|
||||
let mut chomped = 0;
|
||||
|
||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if first_letter.is_uppercase() {
|
||||
chomped += width;
|
||||
} else {
|
||||
return Err(Progress::NoProgress);
|
||||
}
|
||||
}
|
||||
|
||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
// After the first character, only these are allowed:
|
||||
//
|
||||
// * Unicode alphabetic chars - you might include `鹏` if that's clear to your readers
|
||||
// * ASCII digits - e.g. `1` but not `¾`, both of which pass .is_numeric()
|
||||
// * A '.' separating module parts
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
||||
chomped += width;
|
||||
} else if ch == '.' {
|
||||
chomped += width;
|
||||
|
||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if first_letter.is_uppercase() {
|
||||
chomped += width;
|
||||
} else if first_letter == '{' {
|
||||
// the .{ starting a `Foo.{ bar, baz }` importing clauses
|
||||
chomped -= width;
|
||||
break;
|
||||
} else {
|
||||
return Err(Progress::MadeProgress);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we're done
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let name = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|
||||
|_, mut state: State<'a>, _min_indent: u32| match chomp_module_name(state.bytes()) {
|
||||
Ok(name) => {
|
||||
let width = name.len();
|
||||
state = state.advance(width);
|
||||
|
||||
Ok((MadeProgress, ModuleName::new(name), state))
|
||||
}
|
||||
Err(progress) => Err((progress, ())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||
record!(AppHeader {
|
||||
before_provides: space0_e(EHeader::IndentStart),
|
||||
provides: specialize_err(EHeader::Exposes, exposes_list()),
|
||||
before_packages: space0_e(EHeader::IndentStart),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
||||
old_imports: succeed(None),
|
||||
old_provides_to_new_package: succeed(None),
|
||||
})
|
||||
.trace("app_header")
|
||||
}
|
||||
|
||||
struct OldAppHeader<'a> {
|
||||
pub before_name: &'a [CommentOrNewline<'a>],
|
||||
pub packages: Option<Loc<OldAppPackages<'a>>>,
|
||||
pub imports: Option<KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>>,
|
||||
pub provides: ProvidesTo<'a>,
|
||||
}
|
||||
|
||||
type OldAppPackages<'a> =
|
||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>;
|
||||
|
||||
#[inline(always)]
|
||||
fn old_app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||
let old = record!(OldAppHeader {
|
||||
before_name: skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
loc(crate::parser::specialize_err(
|
||||
EHeader::AppName,
|
||||
string_literal::parse_str_literal()
|
||||
))
|
||||
),
|
||||
packages: optional(specialize_err(EHeader::Packages, loc(packages()))),
|
||||
imports: optional(specialize_err(EHeader::Imports, imports())),
|
||||
provides: specialize_err(EHeader::Provides, provides_to()),
|
||||
});
|
||||
|
||||
map_with_arena(old, |arena: &'a bumpalo::Bump, old: OldAppHeader<'a>| {
|
||||
let mut before_packages: &'a [CommentOrNewline] = &[];
|
||||
|
||||
let packages = match old.packages {
|
||||
Some(packages) => {
|
||||
before_packages = merge_spaces(
|
||||
arena,
|
||||
packages.value.keyword.before,
|
||||
packages.value.keyword.after,
|
||||
);
|
||||
|
||||
if let To::ExistingPackage(platform_shorthand) = old.provides.to.value {
|
||||
packages.map(|coll| {
|
||||
coll.item.map_items(arena, |loc_spaced_pkg| {
|
||||
if loc_spaced_pkg.value.item().shorthand == platform_shorthand {
|
||||
loc_spaced_pkg.map(|spaced_pkg| {
|
||||
spaced_pkg.map(arena, |pkg| {
|
||||
let mut new_pkg = *pkg;
|
||||
new_pkg.platform_marker = Some(merge_spaces(
|
||||
arena,
|
||||
old.provides.to_keyword.before,
|
||||
old.provides.to_keyword.after,
|
||||
));
|
||||
new_pkg
|
||||
})
|
||||
})
|
||||
} else {
|
||||
*loc_spaced_pkg
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
packages.map(|kw| kw.item)
|
||||
}
|
||||
}
|
||||
None => Loc {
|
||||
region: Region::zero(),
|
||||
value: Collection::empty(),
|
||||
},
|
||||
};
|
||||
|
||||
let provides = match old.provides.types {
|
||||
Some(types) => {
|
||||
let mut combined_items = bumpalo::collections::Vec::with_capacity_in(
|
||||
old.provides.entries.items.len() + types.items.len(),
|
||||
arena,
|
||||
);
|
||||
|
||||
combined_items.extend_from_slice(old.provides.entries.items);
|
||||
|
||||
for loc_spaced_type_ident in types.items {
|
||||
combined_items.push(loc_spaced_type_ident.map(|spaced_type_ident| {
|
||||
spaced_type_ident.map(arena, |type_ident| {
|
||||
ExposedName::new(From::from(*type_ident))
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
let value_comments = old.provides.entries.final_comments();
|
||||
let type_comments = types.final_comments();
|
||||
|
||||
let mut combined_comments = bumpalo::collections::Vec::with_capacity_in(
|
||||
value_comments.len() + type_comments.len(),
|
||||
arena,
|
||||
);
|
||||
combined_comments.extend_from_slice(value_comments);
|
||||
combined_comments.extend_from_slice(type_comments);
|
||||
|
||||
Collection::with_items_and_comments(
|
||||
arena,
|
||||
combined_items.into_bump_slice(),
|
||||
combined_comments.into_bump_slice(),
|
||||
)
|
||||
}
|
||||
None => old.provides.entries,
|
||||
};
|
||||
|
||||
AppHeader {
|
||||
before_provides: merge_spaces(
|
||||
arena,
|
||||
old.before_name,
|
||||
old.provides.provides_keyword.before,
|
||||
),
|
||||
provides,
|
||||
before_packages: merge_spaces(
|
||||
arena,
|
||||
before_packages,
|
||||
old.provides.provides_keyword.after,
|
||||
),
|
||||
packages,
|
||||
old_imports: old.imports.and_then(imports_none_if_empty),
|
||||
old_provides_to_new_package: match old.provides.to.value {
|
||||
To::NewPackage(new_pkg) => Some(new_pkg),
|
||||
To::ExistingPackage(_) => None,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||
record!(PackageHeader {
|
||||
before_exposes: space0_e(EHeader::IndentStart),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_module_collection()),
|
||||
before_packages: space0_e(EHeader::IndentStart),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
||||
})
|
||||
.trace("package_header")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct OldPackageHeader<'a> {
|
||||
before_name: &'a [CommentOrNewline<'a>],
|
||||
exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
||||
packages:
|
||||
Loc<KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn old_package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||
map_with_arena(
|
||||
record!(OldPackageHeader {
|
||||
before_name: skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
specialize_err(EHeader::PackageName, package_name())
|
||||
),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages())),
|
||||
}),
|
||||
|arena: &'a bumpalo::Bump, old: OldPackageHeader<'a>| {
|
||||
let before_exposes = merge_n_spaces!(
|
||||
arena,
|
||||
old.before_name,
|
||||
old.exposes.keyword.before,
|
||||
old.exposes.keyword.after
|
||||
);
|
||||
let before_packages = merge_spaces(
|
||||
arena,
|
||||
old.packages.value.keyword.before,
|
||||
old.packages.value.keyword.after,
|
||||
);
|
||||
|
||||
PackageHeader {
|
||||
before_exposes,
|
||||
exposes: old.exposes.item,
|
||||
before_packages,
|
||||
packages: old.packages.map(|kw| kw.item),
|
||||
}
|
||||
},
|
||||
)
|
||||
.trace("old_package_header")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||
record!(PlatformHeader {
|
||||
before_name: space0_e(EHeader::IndentStart),
|
||||
name: loc(specialize_err(EHeader::PlatformName, package_name())),
|
||||
requires: specialize_err(EHeader::Requires, requires()),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||
packages: specialize_err(EHeader::Packages, packages()),
|
||||
imports: specialize_err(EHeader::Imports, imports()),
|
||||
provides: specialize_err(EHeader::Provides, provides_exposed()),
|
||||
})
|
||||
.trace("platform_header")
|
||||
}
|
||||
|
||||
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
||||
one_of![
|
||||
specialize_err(
|
||||
|_, pos| EProvides::Identifier(pos),
|
||||
map(lowercase_ident(), To::ExistingPackage)
|
||||
),
|
||||
specialize_err(EProvides::Package, map(package_name(), To::NewPackage))
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
|
||||
record!(ProvidesTo {
|
||||
provides_keyword: spaces_around_keyword(
|
||||
ProvidesKeyword,
|
||||
EProvides::Provides,
|
||||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
entries: collection_trailing_sep_e(
|
||||
byte(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b']', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
),
|
||||
types: optional(backtrackable(provides_types())),
|
||||
to_keyword: spaces_around_keyword(
|
||||
ToKeyword,
|
||||
EProvides::To,
|
||||
EProvides::IndentTo,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
to: loc(provides_to_package()),
|
||||
})
|
||||
.trace("provides_to")
|
||||
}
|
||||
|
||||
fn provides_exposed<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ProvidesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
EProvides<'a>,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ProvidesKeyword,
|
||||
EProvides::Provides,
|
||||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
item: collection_trailing_sep_e(
|
||||
byte(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b']', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn provides_types<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, EProvides<'a>> {
|
||||
skip_first(
|
||||
// We only support spaces here, not newlines, because this is not intended
|
||||
// to be the design forever. Someday it will hopefully work like Elm,
|
||||
// where platform authors can provide functions like Browser.sandbox which
|
||||
// present an API based on ordinary-looking type variables.
|
||||
zero_or_more(byte(
|
||||
b' ',
|
||||
// HACK: If this errors, EProvides::Provides is not an accurate reflection
|
||||
// of what went wrong. However, this is both skipped and zero_or_more,
|
||||
// so this error should never be visible to anyone in practice!
|
||||
EProvides::Provides,
|
||||
)),
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EProvides::ListStart),
|
||||
provides_type_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b'}', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn provides_type_entry<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), ident::uppercase()),
|
||||
Spaced::Item,
|
||||
))
|
||||
}
|
||||
|
||||
fn exposes_entry<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, ExposedName<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), unqualified_ident()),
|
||||
|n| Spaced::Item(ExposedName::new(n)),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires<'a>(
|
||||
) -> impl Parser<'a, KeywordItem<'a, RequiresKeyword, PlatformRequires<'a>>, ERequires<'a>> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
RequiresKeyword,
|
||||
ERequires::Requires,
|
||||
ERequires::IndentRequires,
|
||||
ERequires::IndentListStart
|
||||
),
|
||||
item: platform_requires(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> {
|
||||
record!(PlatformRequires {
|
||||
rigids: skip_second(requires_rigids(), space0_e(ERequires::ListStart)),
|
||||
signature: requires_typed_ident()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', ERequires::ListStart),
|
||||
specialize_err(
|
||||
|_, pos| ERequires::Rigid(pos),
|
||||
loc(map(ident::uppercase(), Spaced::Item)),
|
||||
),
|
||||
byte(b',', ERequires::ListEnd),
|
||||
byte(b'}', ERequires::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
||||
skip_first(
|
||||
byte(b'{', ERequires::ListStart),
|
||||
skip_second(
|
||||
reset_min_indent(space0_around_ee(
|
||||
specialize_err(ERequires::TypedIdent, loc(typed_ident())),
|
||||
ERequires::ListStart,
|
||||
ERequires::ListEnd,
|
||||
)),
|
||||
byte(b'}', ERequires::ListStart),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_values_kw<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
EExposes,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: exposes_kw(),
|
||||
item: exposes_list()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_kw<'a>() -> impl Parser<'a, Spaces<'a, ExposesKeyword>, EExposes> {
|
||||
spaces_around_keyword(
|
||||
ExposesKeyword,
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_list<'a>() -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>, EExposes>
|
||||
{
|
||||
collection_trailing_sep_e(
|
||||
byte(b'[', EExposes::ListStart),
|
||||
exposes_entry(EExposes::Identifier),
|
||||
byte(b',', EExposes::ListEnd),
|
||||
byte(b']', EExposes::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn spaces_around_keyword<'a, K: Keyword, E>(
|
||||
keyword_item: K,
|
||||
expectation: fn(Position) -> E,
|
||||
indent_problem1: fn(Position) -> E,
|
||||
indent_problem2: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Spaces<'a, K>, E>
|
||||
where
|
||||
E: 'a + SpaceProblem,
|
||||
{
|
||||
map(
|
||||
and(
|
||||
skip_second(
|
||||
// parse any leading space before the keyword
|
||||
backtrackable(space0_e(indent_problem1)),
|
||||
// parse the keyword
|
||||
crate::parser::keyword(K::KEYWORD, expectation),
|
||||
),
|
||||
// parse the trailing space
|
||||
space0_e(indent_problem2),
|
||||
),
|
||||
move |(before, after)| Spaces {
|
||||
before,
|
||||
item: keyword_item,
|
||||
after,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_modules<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
||||
EExposes,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ExposesKeyword,
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
item: exposes_module_collection(),
|
||||
})
|
||||
}
|
||||
|
||||
fn exposes_module_collection<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>, EExposes> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'[', EExposes::ListStart),
|
||||
exposes_module(EExposes::Identifier),
|
||||
byte(b',', EExposes::ListEnd),
|
||||
byte(b']', EExposes::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
fn exposes_module<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, ModuleName<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), module_name()),
|
||||
Spaced::Item,
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>,
|
||||
EPackages<'a>,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: packages_kw(),
|
||||
item: packages_collection()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages_kw<'a>() -> impl Parser<'a, Spaces<'a, PackagesKeyword>, EPackages<'a>> {
|
||||
spaces_around_keyword(
|
||||
PackagesKeyword,
|
||||
EPackages::Packages,
|
||||
EPackages::IndentPackages,
|
||||
EPackages::IndentListStart,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages_collection<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>, EPackages<'a>> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EPackages::ListStart),
|
||||
specialize_err(EPackages::PackageEntry, loc(package_entry())),
|
||||
byte(b',', EPackages::ListEnd),
|
||||
byte(b'}', EPackages::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
fn imports<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ImportsKeyword, Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>>,
|
||||
EImports,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ImportsKeyword,
|
||||
EImports::Imports,
|
||||
EImports::IndentImports,
|
||||
EImports::IndentListStart
|
||||
),
|
||||
item: collection_trailing_sep_e(
|
||||
byte(b'[', EImports::ListStart),
|
||||
loc(imports_entry()),
|
||||
byte(b',', EImports::ListEnd),
|
||||
byte(b']', EImports::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
)
|
||||
})
|
||||
.trace("imports")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
|
||||
// e.g.
|
||||
//
|
||||
// printLine : Str -> Task {} *
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
loc(specialize_err(
|
||||
|_, pos| ETypedIdent::Identifier(pos),
|
||||
lowercase_ident(),
|
||||
)),
|
||||
space0_e(ETypedIdent::IndentHasType),
|
||||
),
|
||||
skip_first(
|
||||
byte(b':', ETypedIdent::HasType),
|
||||
space0_before_e(
|
||||
specialize_err(
|
||||
ETypedIdent::Type,
|
||||
reset_min_indent(type_annotation::located(true)),
|
||||
),
|
||||
ETypedIdent::IndentType,
|
||||
),
|
||||
),
|
||||
),
|
||||
|((ident, spaces_before_colon), ann)| {
|
||||
Spaced::Item(TypedIdent {
|
||||
ident,
|
||||
spaces_before_colon,
|
||||
ann,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn shortname<'a>() -> impl Parser<'a, &'a str, EImports> {
|
||||
specialize_err(|_, pos| EImports::Shorthand(pos), lowercase_ident())
|
||||
}
|
||||
|
||||
pub fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
F: 'a,
|
||||
{
|
||||
specialize_err(move |_, pos| to_expectation(pos), module_name())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports> {
|
||||
type Temp<'a> = (
|
||||
(Option<&'a str>, ModuleName<'a>),
|
||||
Option<Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
);
|
||||
|
||||
let spaced_import = |((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(Collection::empty);
|
||||
|
||||
let entry = match opt_shortname {
|
||||
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
|
||||
|
||||
None => ImportsEntry::Module(module_name, exposed_values),
|
||||
};
|
||||
|
||||
Spaced::Item(entry)
|
||||
};
|
||||
|
||||
one_of!(
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
// e.g. `pf.`
|
||||
optional(backtrackable(skip_second(
|
||||
shortname(),
|
||||
byte(b'.', EImports::ShorthandDot)
|
||||
))),
|
||||
// e.g. `Task`
|
||||
module_name_help(EImports::ModuleName)
|
||||
),
|
||||
// e.g. `.{ Task, after}`
|
||||
optional(skip_first(
|
||||
byte(b'.', EImports::ExposingDot),
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EImports::SetStart),
|
||||
exposes_entry(EImports::Identifier),
|
||||
byte(b',', EImports::SetEnd),
|
||||
byte(b'}', EImports::SetEnd),
|
||||
Spaced::SpaceBefore
|
||||
)
|
||||
))
|
||||
),
|
||||
spaced_import
|
||||
)
|
||||
.trace("normal_import"),
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
// e.g. "filename"
|
||||
// TODO: str literal allows for multiline strings. We probably don't want that for file names.
|
||||
specialize_err(|_, pos| EImports::StrLiteral(pos), parse_str_literal()),
|
||||
// e.g. as
|
||||
and(
|
||||
and(
|
||||
space0_e(EImports::AsKeyword),
|
||||
two_bytes(b'a', b's', EImports::AsKeyword)
|
||||
),
|
||||
space0_e(EImports::AsKeyword)
|
||||
)
|
||||
),
|
||||
// e.g. file : Str
|
||||
specialize_err(|_, pos| EImports::TypedIdent(pos), typed_ident())
|
||||
),
|
||||
|((file_name, _), typed_ident)| {
|
||||
// TODO: look at blacking block strings during parsing.
|
||||
Spaced::Item(ImportsEntry::IngestedFile(file_name, typed_ident))
|
||||
}
|
||||
)
|
||||
.trace("ingest_file_import")
|
||||
)
|
||||
.trace("imports_entry")
|
||||
}
|
|
@ -8,9 +8,9 @@ use crate::{
|
|||
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, FullAst, Header,
|
||||
Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias,
|
||||
ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation,
|
||||
IngestedFileImport, ModuleImport, ModuleImportParams, OldRecordBuilderField, Pattern,
|
||||
PatternAs, Spaced, Spaces, SpacesBefore, StrLiteral, StrSegment, Tag, TypeAnnotation,
|
||||
TypeDef, TypeHeader, ValueDef, WhenBranch,
|
||||
IngestedFileImport, ModuleImport, ModuleImportParams, Pattern, PatternAs, Spaced, Spaces,
|
||||
SpacesBefore, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
WhenBranch,
|
||||
},
|
||||
header::{
|
||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
||||
|
@ -562,30 +562,6 @@ impl<'a, T: Normalize<'a> + Copy + std::fmt::Debug> Normalize<'a> for AssignedFi
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for OldRecordBuilderField<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
OldRecordBuilderField::Value(a, _, c) => OldRecordBuilderField::Value(
|
||||
a.normalize(arena),
|
||||
&[],
|
||||
arena.alloc(c.normalize(arena)),
|
||||
),
|
||||
OldRecordBuilderField::ApplyValue(a, _, _, c) => OldRecordBuilderField::ApplyValue(
|
||||
a.normalize(arena),
|
||||
&[],
|
||||
&[],
|
||||
arena.alloc(c.normalize(arena)),
|
||||
),
|
||||
OldRecordBuilderField::LabelOnly(a) => {
|
||||
OldRecordBuilderField::LabelOnly(a.normalize(arena))
|
||||
}
|
||||
OldRecordBuilderField::Malformed(a) => OldRecordBuilderField::Malformed(a),
|
||||
OldRecordBuilderField::SpaceBefore(a, _) => a.normalize(arena),
|
||||
OldRecordBuilderField::SpaceAfter(a, _) => a.normalize(arena),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for StrLiteral<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
|
@ -738,7 +714,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
fields: fields.normalize(arena),
|
||||
},
|
||||
Expr::Record(a) => Expr::Record(a.normalize(arena)),
|
||||
Expr::OldRecordBuilder(a) => Expr::OldRecordBuilder(a.normalize(arena)),
|
||||
Expr::RecordBuilder { mapper, fields } => Expr::RecordBuilder {
|
||||
mapper: arena.alloc(mapper.normalize(arena)),
|
||||
fields: fields.normalize(arena),
|
||||
|
@ -796,7 +771,15 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
Expr::UnaryOp(a, b) => {
|
||||
Expr::UnaryOp(arena.alloc(a.normalize(arena)), b.normalize(arena))
|
||||
}
|
||||
Expr::If(a, b) => Expr::If(a.normalize(arena), arena.alloc(b.normalize(arena))),
|
||||
Expr::If {
|
||||
if_thens,
|
||||
final_else,
|
||||
indented_else,
|
||||
} => Expr::If {
|
||||
if_thens: if_thens.normalize(arena),
|
||||
final_else: arena.alloc(final_else.normalize(arena)),
|
||||
indented_else,
|
||||
},
|
||||
Expr::When(a, b) => Expr::When(arena.alloc(a.normalize(arena)), b.normalize(arena)),
|
||||
Expr::ParensAround(a) => {
|
||||
// The formatter can remove redundant parentheses, so also remove these when normalizing for comparison.
|
||||
|
@ -809,12 +792,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
Expr::SpaceBefore(a, _) => a.normalize(arena),
|
||||
Expr::SpaceAfter(a, _) => a.normalize(arena),
|
||||
Expr::SingleQuote(a) => Expr::Num(a),
|
||||
Expr::MultipleOldRecordBuilders(a) => {
|
||||
Expr::MultipleOldRecordBuilders(arena.alloc(a.normalize(arena)))
|
||||
}
|
||||
Expr::UnappliedOldRecordBuilder(a) => {
|
||||
Expr::UnappliedOldRecordBuilder(arena.alloc(a.normalize(arena)))
|
||||
}
|
||||
Expr::EmptyRecordBuilder(a) => {
|
||||
Expr::EmptyRecordBuilder(arena.alloc(a.normalize(arena)))
|
||||
}
|
||||
|
@ -1084,12 +1061,6 @@ impl<'a> Normalize<'a> for EExpr<'a> {
|
|||
EExpr::Record(inner_err, _pos) => {
|
||||
EExpr::Record(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EExpr::OptionalValueInOldRecordBuilder(_pos) => {
|
||||
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
||||
}
|
||||
EExpr::IgnoredValueInOldRecordBuilder(_pos) => {
|
||||
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
||||
}
|
||||
EExpr::Str(inner_err, _pos) => EExpr::Str(inner_err.normalize(arena), Position::zero()),
|
||||
EExpr::Number(inner_err, _pos) => EExpr::Number(inner_err.clone(), Position::zero()),
|
||||
EExpr::List(inner_err, _pos) => {
|
||||
|
@ -1323,7 +1294,6 @@ impl<'a> Normalize<'a> for EImportParams<'a> {
|
|||
EImportParams::Record(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EImportParams::RecordUpdateFound(_) => EImportParams::RecordUpdateFound(Region::zero()),
|
||||
EImportParams::RecordApplyFound(_) => EImportParams::RecordApplyFound(Region::zero()),
|
||||
EImportParams::RecordIgnoredFieldFound(_) => {
|
||||
EImportParams::RecordIgnoredFieldFound(Region::zero())
|
||||
}
|
||||
|
|
|
@ -344,8 +344,6 @@ pub enum EExpr<'a> {
|
|||
|
||||
InParens(EInParens<'a>, Position),
|
||||
Record(ERecord<'a>, Position),
|
||||
OptionalValueInOldRecordBuilder(Region),
|
||||
IgnoredValueInOldRecordBuilder(Region),
|
||||
RecordUpdateOldBuilderField(Region),
|
||||
RecordUpdateIgnoredField(Region),
|
||||
RecordBuilderOldBuilderField(Region),
|
||||
|
@ -551,7 +549,6 @@ pub enum EImportParams<'a> {
|
|||
Record(ERecord<'a>, Position),
|
||||
RecordUpdateFound(Region),
|
||||
RecordBuilderFound(Region),
|
||||
RecordApplyFound(Region),
|
||||
RecordIgnoredFieldFound(Region),
|
||||
Space(BadInputError, Position),
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::ast::{
|
|||
use crate::blankspace::{
|
||||
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||
};
|
||||
use crate::expr::{record_field, FoundApplyValue};
|
||||
use crate::expr::record_field;
|
||||
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
|
@ -565,11 +565,10 @@ fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, ETyp
|
|||
fn ability_impl_field<'a>() -> impl Parser<'a, AssignedField<'a, Expr<'a>>, ERecord<'a>> {
|
||||
then(record_field(), move |arena, state, _, field| {
|
||||
match field.to_assigned_field(arena) {
|
||||
Ok(AssignedField::IgnoredValue(_, _, _)) => {
|
||||
AssignedField::IgnoredValue(_, _, _) => {
|
||||
Err((MadeProgress, ERecord::Field(state.pos())))
|
||||
}
|
||||
Ok(assigned_field) => Ok((MadeProgress, assigned_field, state)),
|
||||
Err(FoundApplyValue) => Err((MadeProgress, ERecord::Field(state.pos()))),
|
||||
assigned_field => Ok((MadeProgress, assigned_field, state)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -427,8 +427,6 @@ impl Problem {
|
|||
| Problem::RuntimeError(RuntimeError::EmptySingleQuote(region))
|
||||
| Problem::RuntimeError(RuntimeError::MultipleCharsInSingleQuote(region))
|
||||
| Problem::RuntimeError(RuntimeError::DegenerateBranch(region))
|
||||
| Problem::RuntimeError(RuntimeError::MultipleOldRecordBuilders(region))
|
||||
| Problem::RuntimeError(RuntimeError::UnappliedOldRecordBuilder(region))
|
||||
| Problem::RuntimeError(RuntimeError::EmptyRecordBuilder(region))
|
||||
| Problem::RuntimeError(RuntimeError::SingleFieldRecordBuilder(region))
|
||||
| Problem::RuntimeError(RuntimeError::OptionalFieldInRecordBuilder {
|
||||
|
@ -686,9 +684,6 @@ pub enum RuntimeError {
|
|||
|
||||
DegenerateBranch(Region),
|
||||
|
||||
MultipleOldRecordBuilders(Region),
|
||||
UnappliedOldRecordBuilder(Region),
|
||||
|
||||
EmptyRecordBuilder(Region),
|
||||
SingleFieldRecordBuilder(Region),
|
||||
OptionalFieldInRecordBuilder {
|
||||
|
@ -739,8 +734,6 @@ impl RuntimeError {
|
|||
| RuntimeError::DegenerateBranch(region)
|
||||
| RuntimeError::InvalidInterpolation(region)
|
||||
| RuntimeError::InvalidHexadecimal(region)
|
||||
| RuntimeError::MultipleOldRecordBuilders(region)
|
||||
| RuntimeError::UnappliedOldRecordBuilder(region)
|
||||
| RuntimeError::EmptyRecordBuilder(region)
|
||||
| RuntimeError::SingleFieldRecordBuilder(region)
|
||||
| RuntimeError::OptionalFieldInRecordBuilder {
|
||||
|
|
|
@ -547,6 +547,11 @@ fn list_drop_at() {
|
|||
RocList::from_slice(&[2, 3]),
|
||||
RocList<i64>
|
||||
);
|
||||
assert_evals_to!(
|
||||
"List.dropAt [1, 2, 3] 1",
|
||||
RocList::from_slice(&[1, 3]),
|
||||
RocList<i64>
|
||||
);
|
||||
assert_evals_to!(
|
||||
"List.dropAt [0, 0, 0] 3",
|
||||
RocList::from_slice(&[0, 0, 0]),
|
||||
|
|
|
@ -1988,3 +1988,75 @@ fn str_contains_self() {
|
|||
bool
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn str_drop_prefix() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropPrefix "" "foo"
|
||||
"#,
|
||||
RocStr::from(""),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropPrefix "bar" "foo"
|
||||
"#,
|
||||
RocStr::from("bar"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropPrefix "foobar" "foo"
|
||||
"#,
|
||||
RocStr::from("bar"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropPrefix "fooBarThisIsDefinitelyAReallyLongAndNotaShortString" "foo"
|
||||
"#,
|
||||
RocStr::from("BarThisIsDefinitelyAReallyLongAndNotaShortString"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn str_drop_suffix() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropSuffix "" "foo"
|
||||
"#,
|
||||
RocStr::from(""),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropSuffix "bar" "foo"
|
||||
"#,
|
||||
RocStr::from("bar"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropSuffix "barfoo" "foo"
|
||||
"#,
|
||||
RocStr::from("bar"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Str.dropSuffix "BarThisIsDefinitelyAReallyLongAndNotaShortStringfoo" "foo"
|
||||
"#,
|
||||
RocStr::from("BarThisIsDefinitelyAReallyLongAndNotaShortString"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.238;
|
||||
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.248;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
ret Test.5;
|
||||
|
|
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
|
@ -43,14 +43,14 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : I64 = 1i64;
|
||||
let Test.1 : I64 = 2i64;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.1;
|
||||
ret Test.3;
|
||||
let Test.5 : I64 = 1i64;
|
||||
let Test.2 : I64 = 2i64;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.4 : I64 = CallByName Num.19 Test.5 Test.2;
|
||||
ret Test.4;
|
||||
|
|
|
@ -44,8 +44,8 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.4 : Str = "";
|
||||
|
|
|
@ -40,19 +40,19 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.238;
|
||||
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.248;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Str = "Hello ";
|
||||
let Test.1 : Str = "world";
|
||||
inc Test.1;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.7 : Str = "!";
|
||||
let Test.5 : Str = CallByName Str.3 Test.1 Test.7;
|
||||
dec Test.7;
|
||||
let Test.3 : Str = CallByName Str.3 Test.4 Test.5;
|
||||
dec Test.5;
|
||||
ret Test.3;
|
||||
let Test.5 : Str = "Hello ";
|
||||
let Test.2 : Str = "world";
|
||||
inc Test.2;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.8 : Str = "!";
|
||||
let Test.6 : Str = CallByName Str.3 Test.2 Test.8;
|
||||
dec Test.8;
|
||||
let Test.4 : Str = CallByName Str.3 Test.5 Test.6;
|
||||
dec Test.6;
|
||||
ret Test.4;
|
||||
|
|
|
@ -39,18 +39,18 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : I64 = 1i64;
|
||||
let Test.4 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.4;
|
||||
dec Test.4;
|
||||
let Test.5 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.5;
|
||||
dec Test.5;
|
||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.6;
|
||||
dec Test.6;
|
||||
ret Test.3;
|
||||
let Test.6 : I64 = 1i64;
|
||||
let Test.7 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.7;
|
||||
dec Test.7;
|
||||
let Test.8 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.8;
|
||||
dec Test.8;
|
||||
let Test.9 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.9;
|
||||
dec Test.9;
|
||||
ret Test.6;
|
||||
|
|
|
@ -40,8 +40,8 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Str = "";
|
||||
|
|
38
crates/compiler/test_mono/generated/dict.txt
generated
38
crates/compiler/test_mono/generated/dict.txt
generated
|
@ -1,29 +1,29 @@
|
|||
procedure Dict.1 (Dict.730):
|
||||
let Dict.739 : List {U32, U32} = Array [];
|
||||
let Dict.740 : List {[], []} = Array [];
|
||||
let Dict.741 : U64 = 0i64;
|
||||
procedure Dict.1 (Dict.731):
|
||||
let Dict.740 : List {U32, U32} = Array [];
|
||||
let Dict.741 : List {[], []} = Array [];
|
||||
let Dict.742 : U64 = 0i64;
|
||||
let Dict.51 : Float32 = CallByName Dict.51;
|
||||
let Dict.52 : U8 = CallByName Dict.52;
|
||||
let Dict.738 : {List {U32, U32}, List {[], []}, U64, Float32, U8} = Struct {Dict.739, Dict.740, Dict.741, Dict.51, Dict.52};
|
||||
let Dict.739 : {List {U32, U32}, List {[], []}, U64, Float32, U8} = Struct {Dict.740, Dict.741, Dict.742, Dict.51, Dict.52};
|
||||
ret Dict.739;
|
||||
|
||||
procedure Dict.4 (Dict.737):
|
||||
let Dict.163 : List {[], []} = StructAtIndex 1 Dict.737;
|
||||
let #Derived_gen.0 : List {U32, U32} = StructAtIndex 0 Dict.737;
|
||||
dec #Derived_gen.0;
|
||||
let Dict.738 : U64 = CallByName List.6 Dict.163;
|
||||
dec Dict.163;
|
||||
ret Dict.738;
|
||||
|
||||
procedure Dict.4 (Dict.736):
|
||||
let Dict.163 : List {[], []} = StructAtIndex 1 Dict.736;
|
||||
let #Derived_gen.0 : List {U32, U32} = StructAtIndex 0 Dict.736;
|
||||
dec #Derived_gen.0;
|
||||
let Dict.737 : U64 = CallByName List.6 Dict.163;
|
||||
dec Dict.163;
|
||||
ret Dict.737;
|
||||
|
||||
procedure Dict.51 ():
|
||||
let Dict.745 : Float32 = 0.8f64;
|
||||
ret Dict.745;
|
||||
let Dict.746 : Float32 = 0.8f64;
|
||||
ret Dict.746;
|
||||
|
||||
procedure Dict.52 ():
|
||||
let Dict.743 : U8 = 64i64;
|
||||
let Dict.744 : U8 = 3i64;
|
||||
let Dict.742 : U8 = CallByName Num.75 Dict.743 Dict.744;
|
||||
ret Dict.742;
|
||||
let Dict.744 : U8 = 64i64;
|
||||
let Dict.745 : U8 = 3i64;
|
||||
let Dict.743 : U8 = CallByName Num.75 Dict.744 Dict.745;
|
||||
ret Dict.743;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.625 : U64 = lowlevel ListLenU64 #Attr.2;
|
||||
|
|
|
@ -164,32 +164,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.285;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.248 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.248;
|
||||
let Str.258 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.258;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.249 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.249;
|
||||
let Str.259 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.259;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.45 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.45 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.45;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.325 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -105,32 +105,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.246;
|
||||
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.256;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.24 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.24 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.24;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.292 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -112,32 +112,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.246;
|
||||
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.256;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.28;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.296 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -38,32 +38,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.246;
|
||||
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.256;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.3 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.3 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.3;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.259 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -110,32 +110,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.246;
|
||||
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.256;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.27 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.27 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.27;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.297 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -113,32 +113,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.246;
|
||||
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.256;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.243;
|
||||
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.253;
|
||||
|
||||
procedure Str.9 (Str.71):
|
||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
||||
if Str.240 then
|
||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
||||
ret Str.241;
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.250 then
|
||||
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||
ret Str.251;
|
||||
else
|
||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.72;
|
||||
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||
dec #Derived_gen.28;
|
||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
||||
ret Str.236;
|
||||
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.301 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
1140
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
1140
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
File diff suppressed because it is too large
Load diff
|
@ -178,8 +178,8 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List I64 = Array [1i64, 2i64, 3i64];
|
||||
|
|
|
@ -292,8 +292,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.237;
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Str = "bar";
|
||||
|
|
|
@ -209,8 +209,8 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Decimal = 3dec;
|
||||
|
|
|
@ -179,8 +179,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Str = "foo";
|
||||
|
|
|
@ -186,8 +186,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Str = "foo";
|
||||
|
|
|
@ -40,8 +40,8 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : Str = "abc";
|
||||
|
|
|
@ -179,8 +179,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Str = "foo";
|
||||
|
|
|
@ -182,8 +182,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : Str = "foo";
|
||||
|
|
|
@ -45,27 +45,27 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
|||
let Num.281 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Str.27 (Str.82):
|
||||
let Str.236 : [C Int1, C I64] = CallByName Str.64 Str.82;
|
||||
ret Str.236;
|
||||
procedure Str.27 (Str.84):
|
||||
let Str.246 : [C Int1, C I64] = CallByName Str.66 Str.84;
|
||||
ret Str.246;
|
||||
|
||||
procedure Str.42 (#Attr.2):
|
||||
let Str.244 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||
ret Str.244;
|
||||
let Str.254 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.64 (Str.189):
|
||||
let Str.190 : {I64, U8} = CallByName Str.42 Str.189;
|
||||
let Str.242 : U8 = StructAtIndex 1 Str.190;
|
||||
let Str.243 : U8 = 0i64;
|
||||
let Str.239 : Int1 = CallByName Bool.11 Str.242 Str.243;
|
||||
if Str.239 then
|
||||
let Str.241 : I64 = StructAtIndex 0 Str.190;
|
||||
let Str.240 : [C Int1, C I64] = TagId(1) Str.241;
|
||||
ret Str.240;
|
||||
procedure Str.66 (Str.191):
|
||||
let Str.192 : {I64, U8} = CallByName Str.42 Str.191;
|
||||
let Str.252 : U8 = StructAtIndex 1 Str.192;
|
||||
let Str.253 : U8 = 0i64;
|
||||
let Str.249 : Int1 = CallByName Bool.11 Str.252 Str.253;
|
||||
if Str.249 then
|
||||
let Str.251 : I64 = StructAtIndex 0 Str.192;
|
||||
let Str.250 : [C Int1, C I64] = TagId(1) Str.251;
|
||||
ret Str.250;
|
||||
else
|
||||
let Str.238 : Int1 = false;
|
||||
let Str.237 : [C Int1, C I64] = TagId(0) Str.238;
|
||||
ret Str.237;
|
||||
let Str.248 : Int1 = false;
|
||||
let Str.247 : [C Int1, C I64] = TagId(0) Str.248;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Int1 = CallByName Bool.2;
|
||||
|
|
|
@ -19,30 +19,30 @@ procedure Decode.26 (Decode.109, Decode.110):
|
|||
ret Decode.126;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.245;
|
||||
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.255;
|
||||
|
||||
procedure Str.27 (Str.82):
|
||||
let Str.236 : [C {}, C I64] = CallByName Str.64 Str.82;
|
||||
ret Str.236;
|
||||
procedure Str.27 (Str.84):
|
||||
let Str.246 : [C {}, C I64] = CallByName Str.66 Str.84;
|
||||
ret Str.246;
|
||||
|
||||
procedure Str.42 (#Attr.2):
|
||||
let Str.244 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||
ret Str.244;
|
||||
let Str.254 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.64 (Str.189):
|
||||
let Str.190 : {I64, U8} = CallByName Str.42 Str.189;
|
||||
let Str.242 : U8 = StructAtIndex 1 Str.190;
|
||||
let Str.243 : U8 = 0i64;
|
||||
let Str.239 : Int1 = CallByName Bool.11 Str.242 Str.243;
|
||||
if Str.239 then
|
||||
let Str.241 : I64 = StructAtIndex 0 Str.190;
|
||||
let Str.240 : [C {}, C I64] = TagId(1) Str.241;
|
||||
ret Str.240;
|
||||
procedure Str.66 (Str.191):
|
||||
let Str.192 : {I64, U8} = CallByName Str.42 Str.191;
|
||||
let Str.252 : U8 = StructAtIndex 1 Str.192;
|
||||
let Str.253 : U8 = 0i64;
|
||||
let Str.249 : Int1 = CallByName Bool.11 Str.252 Str.253;
|
||||
if Str.249 then
|
||||
let Str.251 : I64 = StructAtIndex 0 Str.192;
|
||||
let Str.250 : [C {}, C I64] = TagId(1) Str.251;
|
||||
ret Str.250;
|
||||
else
|
||||
let Str.238 : {} = Struct {};
|
||||
let Str.237 : [C {}, C I64] = TagId(0) Str.238;
|
||||
ret Str.237;
|
||||
let Str.248 : {} = Struct {};
|
||||
let Str.247 : [C {}, C I64] = TagId(0) Str.248;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.103 ():
|
||||
let Test.101 : [C Str, C {List U8, I64}] = CallByName Test.19;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.16 : [C {}, C U64, C Str] = TagId(0) Test.5;
|
||||
|
|
|
@ -71,12 +71,12 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.16 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.237;
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||
|
|
|
@ -70,8 +70,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.237;
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||
|
|
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
|
@ -0,0 +1,59 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.322 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.321 : Str = CallByName Inspect.64 Inspect.322;
|
||||
ret Inspect.321;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.282 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : I64 = 1i64;
|
||||
let Test.5 : Str = CallByName Inspect.33 Test.4;
|
||||
dbg Test.5;
|
||||
dec Test.5;
|
||||
let Test.9 : I64 = 2i64;
|
||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.9;
|
||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.6;
|
||||
dec Test.6;
|
||||
ret Test.3;
|
|
@ -3,8 +3,8 @@ procedure Bool.11 (#Attr.2, #Attr.3):
|
|||
ret Bool.23;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.237;
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
|
||||
procedure Test.2 (Test.7):
|
||||
let Test.24 : Str = ".trace(\"";
|
||||
|
|
|
@ -3,8 +3,8 @@ procedure Num.20 (#Attr.2, #Attr.3):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.238;
|
||||
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.248;
|
||||
|
||||
procedure Test.11 (Test.29, #Attr.12):
|
||||
let Test.32 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
|
|
|
@ -99,12 +99,12 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.281;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.237 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.237;
|
||||
let Str.247 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.247;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.238 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.238;
|
||||
let Str.248 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.248;
|
||||
|
||||
procedure Test.20 (Test.58):
|
||||
let Test.295 : Str = CallByName Encode.23 Test.58;
|
||||
|
|
|
@ -192,12 +192,12 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.285;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.240 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.240;
|
||||
let Str.250 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.250;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.241 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.241;
|
||||
let Str.251 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.251;
|
||||
|
||||
procedure Test.20 (Test.58):
|
||||
inc Test.58;
|
||||
|
|
|
@ -3295,6 +3295,18 @@ fn dbg_inside_string() {
|
|||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn pizza_dbg() {
|
||||
indoc!(
|
||||
r#"
|
||||
1
|
||||
|> dbg
|
||||
|> Num.add 2
|
||||
|> dbg
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn linked_list_reverse() {
|
||||
indoc!(
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Expr(If(IndentElseBranch(@31), @0), @0)
|
|
@ -0,0 +1,4 @@
|
|||
if thing then
|
||||
whatever
|
||||
else
|
||||
something better
|
|
@ -1,6 +1,6 @@
|
|||
SpaceAfter(
|
||||
If(
|
||||
[
|
||||
If {
|
||||
if_thens: [
|
||||
(
|
||||
@3-6 Var {
|
||||
module_name: "",
|
||||
|
@ -60,7 +60,7 @@ SpaceAfter(
|
|||
),
|
||||
),
|
||||
],
|
||||
@49-50 SpaceBefore(
|
||||
final_else: @49-50 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "c",
|
||||
|
@ -71,7 +71,8 @@ SpaceAfter(
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
[
|
||||
LineComment(
|
||||
" 4",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
SpaceAfter(
|
||||
If(
|
||||
[
|
||||
If {
|
||||
if_thens: [
|
||||
(
|
||||
@3-5 Var {
|
||||
module_name: "",
|
||||
|
@ -40,7 +40,7 @@ SpaceAfter(
|
|||
),
|
||||
),
|
||||
],
|
||||
@42-43 SpaceBefore(
|
||||
final_else: @42-43 SpaceBefore(
|
||||
Num(
|
||||
"3",
|
||||
),
|
||||
|
@ -48,7 +48,8 @@ SpaceAfter(
|
|||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1 |> dbg
|
|
@ -0,0 +1,16 @@
|
|||
SpaceAfter(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-1 Num(
|
||||
"1",
|
||||
),
|
||||
@2-4 Pizza,
|
||||
),
|
||||
],
|
||||
@5-8 Dbg,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
1 |> dbg
|
|
@ -8,8 +8,8 @@ SpaceAfter(
|
|||
@2-3 Star,
|
||||
),
|
||||
],
|
||||
@4-30 If(
|
||||
[
|
||||
@4-30 If {
|
||||
if_thens: [
|
||||
(
|
||||
@7-16 Var {
|
||||
module_name: "Bool",
|
||||
|
@ -20,10 +20,11 @@ SpaceAfter(
|
|||
),
|
||||
),
|
||||
],
|
||||
@29-30 Num(
|
||||
final_else: @29-30 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -3,8 +3,8 @@ Record(
|
|||
@1-31 RequiredValue(
|
||||
@1-2 "x",
|
||||
[],
|
||||
@5-31 If(
|
||||
[
|
||||
@5-31 If {
|
||||
if_thens: [
|
||||
(
|
||||
@8-17 Var {
|
||||
module_name: "Bool",
|
||||
|
@ -15,10 +15,11 @@ Record(
|
|||
),
|
||||
),
|
||||
],
|
||||
@30-31 Num(
|
||||
final_else: @30-31 Num(
|
||||
"2",
|
||||
),
|
||||
),
|
||||
indented_else: false,
|
||||
},
|
||||
),
|
||||
@33-37 RequiredValue(
|
||||
@33-34 "y",
|
||||
|
|
|
@ -1986,7 +1986,7 @@ mod test_fmt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn new_record_builder() {
|
||||
fn record_builder() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
{ shoes <- leftShoe: nothing }
|
||||
|
@ -2077,170 +2077,6 @@ mod test_fmt {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn old_record_builder() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
{ a: 1, b: <- get "b" |> batch, c: <- get "c" |> batch, d }
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
{ a: 1, b: <- get "b" |> batch, c:<- get "c" |> batch }
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
{ a: 1, b: <- get "b" |> batch, c: <- get "c" |> batch }
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
{
|
||||
a: 1,
|
||||
b: <- get "b" |> batch,
|
||||
c: <- get "c" |> batch,
|
||||
d,
|
||||
}
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
{ a: 1, b: <- get "b" |> batch,
|
||||
c: <- get "c" |> batch, d }
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
{
|
||||
a: 1,
|
||||
b: <- get "b" |> batch,
|
||||
c: <- get "c" |> batch,
|
||||
d,
|
||||
}
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_record_builder_field() {
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a: <- get "a" |> map (\x -> x * 2)
|
||||
|> batch,
|
||||
b: <- get "b" |> batch,
|
||||
c: items
|
||||
|> List.map \x -> x * 2
|
||||
}
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a: <-
|
||||
get "a"
|
||||
|> map (\x -> x * 2)
|
||||
|> batch,
|
||||
b: <- get "b" |> batch,
|
||||
c:
|
||||
items
|
||||
|> List.map \x -> x * 2,
|
||||
}
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a: # I like to comment in weird places
|
||||
<- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
));
|
||||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a:
|
||||
# I like to comment in weird places
|
||||
<- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outdentable_record_builders() {
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
succeed { a: <- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a: <- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
succeed
|
||||
{
|
||||
a: <- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
succeed {
|
||||
a: <- get "a" |> batch,
|
||||
b: <- get "b" |> batch,
|
||||
}
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_format_multiple_record_builders() {
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
succeed { a: <- get "a" }
|
||||
{ b: <- get "b" }
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
succeed
|
||||
{ a: <- get "a" }
|
||||
{ b: <- get "b" }
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn final_comments_in_records() {
|
||||
expr_formats_same(indoc!(
|
||||
|
@ -3628,6 +3464,60 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn early_return_else() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
if foo then
|
||||
bar
|
||||
else
|
||||
|
||||
baz
|
||||
"
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
if thing then
|
||||
whatever
|
||||
else
|
||||
too close
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
if thing then
|
||||
whatever
|
||||
else
|
||||
|
||||
too close
|
||||
"
|
||||
),
|
||||
);
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
if isGrowing plant then
|
||||
LetBe
|
||||
else
|
||||
|
||||
Water
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
if isGrowing plant then
|
||||
LetBe
|
||||
else
|
||||
|
||||
Water
|
||||
"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line_application() {
|
||||
expr_formats_same(indoc!(
|
||||
|
|
|
@ -202,6 +202,7 @@ mod test_snapshots {
|
|||
fail/expression_indentation_end.expr,
|
||||
fail/if_guard_without_condition.expr,
|
||||
fail/if_missing_else.expr,
|
||||
fail/if_outdented_else_branch.expr,
|
||||
fail/if_outdented_then.expr,
|
||||
fail/import_with_lowercase_alias.moduledefs,
|
||||
fail/imports_missing_comma.header,
|
||||
|
@ -442,6 +443,7 @@ mod test_snapshots {
|
|||
pass/pattern_as_spaces.expr,
|
||||
pass/pattern_with_space_in_parens.expr, // https://github.com/roc-lang/roc/issues/929
|
||||
pass/pizza_bang.moduledefs,
|
||||
pass/pizza_dbg.expr,
|
||||
pass/plus_if.expr,
|
||||
pass/plus_when.expr,
|
||||
pass/pos_inf_float.expr,
|
||||
|
|
|
@ -46,8 +46,8 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : {} = Struct {};
|
||||
|
|
|
@ -49,8 +49,8 @@ procedure Inspect.64 (Inspect.302):
|
|||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.4 : Str = CallByName Inspect.33 Test.3;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue