mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Merge branch 'trunk' into bytes
This commit is contained in:
commit
869d3d18d0
19 changed files with 1036 additions and 477 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2950,6 +2950,7 @@ dependencies = [
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"ven_pretty",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -135,6 +135,9 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io
|
||||||
Err(LoadingProblem::ParsingFailedReport(report)) => {
|
Err(LoadingProblem::ParsingFailedReport(report)) => {
|
||||||
print!("{}", report);
|
print!("{}", report);
|
||||||
}
|
}
|
||||||
|
Err(LoadingProblem::NoPlatform(report)) => {
|
||||||
|
print!("{}", report);
|
||||||
|
}
|
||||||
Err(other) => {
|
Err(other) => {
|
||||||
panic!("build_file failed with error:\n{:?}", other);
|
panic!("build_file failed with error:\n{:?}", other);
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,9 +230,8 @@ mod cli_run {
|
||||||
#[test]
|
#[test]
|
||||||
#[serial(astar)]
|
#[serial(astar)]
|
||||||
fn run_astar_optimized_1() {
|
fn run_astar_optimized_1() {
|
||||||
check_output_with_stdin(
|
check_output(
|
||||||
&example_file("benchmarks", "TestAStar.roc"),
|
&example_file("benchmarks", "TestAStar.roc"),
|
||||||
"1",
|
|
||||||
"test-astar",
|
"test-astar",
|
||||||
&[],
|
&[],
|
||||||
"True\n",
|
"True\n",
|
||||||
|
|
|
@ -674,32 +674,43 @@ pub fn canonicalize_expr<'a>(
|
||||||
Output::default(),
|
Output::default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::Expr::If(cond, then_branch, else_branch) => {
|
ast::Expr::If(if_thens, final_else_branch) => {
|
||||||
let (loc_cond, mut output) =
|
let mut branches = Vec::with_capacity(1);
|
||||||
canonicalize_expr(env, var_store, scope, cond.region, &cond.value);
|
let mut output = Output::default();
|
||||||
let (loc_then, then_output) = canonicalize_expr(
|
|
||||||
env,
|
for (condition, then_branch) in if_thens.iter() {
|
||||||
var_store,
|
let (loc_cond, cond_output) =
|
||||||
scope,
|
canonicalize_expr(env, var_store, scope, condition.region, &condition.value);
|
||||||
then_branch.region,
|
|
||||||
&then_branch.value,
|
let (loc_then, then_output) = canonicalize_expr(
|
||||||
);
|
env,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
then_branch.region,
|
||||||
|
&then_branch.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
branches.push((loc_cond, loc_then));
|
||||||
|
|
||||||
|
output.references = output.references.union(cond_output.references);
|
||||||
|
output.references = output.references.union(then_output.references);
|
||||||
|
}
|
||||||
|
|
||||||
let (loc_else, else_output) = canonicalize_expr(
|
let (loc_else, else_output) = canonicalize_expr(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
else_branch.region,
|
final_else_branch.region,
|
||||||
&else_branch.value,
|
&final_else_branch.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.references = output.references.union(then_output.references);
|
|
||||||
output.references = output.references.union(else_output.references);
|
output.references = output.references.union(else_output.references);
|
||||||
|
|
||||||
(
|
(
|
||||||
If {
|
If {
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
branch_var: var_store.fresh(),
|
branch_var: var_store.fresh(),
|
||||||
branches: vec![(loc_cond, loc_then)],
|
branches,
|
||||||
final_else: Box::new(loc_else),
|
final_else: Box::new(loc_else),
|
||||||
},
|
},
|
||||||
output,
|
output,
|
||||||
|
|
|
@ -290,16 +290,21 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
If(condition, then_branch, else_branch)
|
If(if_thens, final_else_branch) | Nested(If(if_thens, final_else_branch)) => {
|
||||||
| Nested(If(condition, then_branch, else_branch)) => {
|
// If does not get desugared into `when` so we can give more targetted error messages during type checking.
|
||||||
// If does not get desugared yet so we can give more targetted error messages during
|
let desugared_final_else = &*arena.alloc(desugar_expr(arena, &final_else_branch));
|
||||||
// type checking.
|
|
||||||
let desugared_cond = &*arena.alloc(desugar_expr(arena, &condition));
|
let mut desugared_if_thens = Vec::with_capacity_in(if_thens.len(), arena);
|
||||||
let desugared_then = &*arena.alloc(desugar_expr(arena, &then_branch));
|
|
||||||
let desugared_else = &*arena.alloc(desugar_expr(arena, &else_branch));
|
for (condition, then_branch) in if_thens.iter() {
|
||||||
|
desugared_if_thens.push((
|
||||||
|
desugar_expr(arena, condition).clone(),
|
||||||
|
desugar_expr(arena, then_branch).clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
value: If(desugared_cond, desugared_then, desugared_else),
|
value: If(desugared_if_thens.into_bump_slice(), desugared_final_else),
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,11 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
||||||
loc_expr.is_multiline() || args.iter().any(|loc_arg| loc_arg.is_multiline())
|
loc_expr.is_multiline() || args.iter().any(|loc_arg| loc_arg.is_multiline())
|
||||||
}
|
}
|
||||||
|
|
||||||
If(loc_cond, loc_if_true, loc_if_false) => {
|
If(branches, final_else) => {
|
||||||
loc_cond.is_multiline() || loc_if_true.is_multiline() || loc_if_false.is_multiline()
|
final_else.is_multiline()
|
||||||
|
|| branches
|
||||||
|
.iter()
|
||||||
|
.any(|(c, t)| c.is_multiline() || t.is_multiline())
|
||||||
}
|
}
|
||||||
|
|
||||||
BinOp((loc_left, _, loc_right)) => {
|
BinOp((loc_left, _, loc_right)) => {
|
||||||
|
@ -257,8 +260,8 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
||||||
// still print the return value.
|
// still print the return value.
|
||||||
ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||||
}
|
}
|
||||||
If(loc_condition, loc_then, loc_else) => {
|
If(branches, final_else) => {
|
||||||
fmt_if(buf, loc_condition, loc_then, loc_else, indent);
|
fmt_if(buf, branches, final_else, self.is_multiline(), indent);
|
||||||
}
|
}
|
||||||
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
||||||
List {
|
List {
|
||||||
|
@ -629,15 +632,15 @@ fn fmt_when<'a>(
|
||||||
|
|
||||||
fn fmt_if<'a>(
|
fn fmt_if<'a>(
|
||||||
buf: &mut String<'a>,
|
buf: &mut String<'a>,
|
||||||
loc_condition: &'a Located<Expr<'a>>,
|
branches: &'a [(Located<Expr<'a>>, Located<Expr<'a>>)],
|
||||||
loc_then: &'a Located<Expr<'a>>,
|
final_else: &'a Located<Expr<'a>>,
|
||||||
loc_else: &'a Located<Expr<'a>>,
|
is_multiline: bool,
|
||||||
indent: u16,
|
indent: u16,
|
||||||
) {
|
) {
|
||||||
let is_multiline_then = loc_then.is_multiline();
|
// let is_multiline_then = loc_then.is_multiline();
|
||||||
let is_multiline_else = loc_else.is_multiline();
|
// let is_multiline_else = final_else.is_multiline();
|
||||||
let is_multiline_condition = loc_condition.is_multiline();
|
// let is_multiline_condition = loc_condition.is_multiline();
|
||||||
let is_multiline = is_multiline_then || is_multiline_else || is_multiline_condition;
|
// let is_multiline = is_multiline_then || is_multiline_else || is_multiline_condition;
|
||||||
|
|
||||||
let return_indent = if is_multiline {
|
let return_indent = if is_multiline {
|
||||||
indent + INDENT
|
indent + INDENT
|
||||||
|
@ -645,80 +648,89 @@ fn fmt_if<'a>(
|
||||||
indent
|
indent
|
||||||
};
|
};
|
||||||
|
|
||||||
buf.push_str("if");
|
for (loc_condition, loc_then) in branches.iter() {
|
||||||
|
let is_multiline_condition = loc_condition.is_multiline();
|
||||||
|
|
||||||
if is_multiline_condition {
|
buf.push_str("if");
|
||||||
match &loc_condition.value {
|
|
||||||
Expr::SpaceBefore(expr_below, spaces_above_expr) => {
|
|
||||||
fmt_comments_only(buf, spaces_above_expr.iter(), NewlineAt::Top, return_indent);
|
|
||||||
newline(buf, return_indent);
|
|
||||||
|
|
||||||
match &expr_below {
|
if is_multiline_condition {
|
||||||
Expr::SpaceAfter(expr_above, spaces_below_expr) => {
|
match &loc_condition.value {
|
||||||
expr_above.format(buf, return_indent);
|
Expr::SpaceBefore(expr_below, spaces_above_expr) => {
|
||||||
fmt_comments_only(
|
fmt_comments_only(buf, spaces_above_expr.iter(), NewlineAt::Top, return_indent);
|
||||||
buf,
|
newline(buf, return_indent);
|
||||||
spaces_below_expr.iter(),
|
|
||||||
NewlineAt::Top,
|
|
||||||
return_indent,
|
|
||||||
);
|
|
||||||
newline(buf, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
match &expr_below {
|
||||||
expr_below.format(buf, return_indent);
|
Expr::SpaceAfter(expr_above, spaces_below_expr) => {
|
||||||
|
expr_above.format(buf, return_indent);
|
||||||
|
fmt_comments_only(
|
||||||
|
buf,
|
||||||
|
spaces_below_expr.iter(),
|
||||||
|
NewlineAt::Top,
|
||||||
|
return_indent,
|
||||||
|
);
|
||||||
|
newline(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
expr_below.format(buf, return_indent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Expr::SpaceAfter(expr_above, spaces_below_expr) => {
|
Expr::SpaceAfter(expr_above, spaces_below_expr) => {
|
||||||
newline(buf, return_indent);
|
newline(buf, return_indent);
|
||||||
expr_above.format(buf, return_indent);
|
expr_above.format(buf, return_indent);
|
||||||
fmt_comments_only(buf, spaces_below_expr.iter(), NewlineAt::Top, return_indent);
|
fmt_comments_only(buf, spaces_below_expr.iter(), NewlineAt::Top, return_indent);
|
||||||
newline(buf, indent);
|
newline(buf, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
newline(buf, return_indent);
|
newline(buf, return_indent);
|
||||||
loc_condition.format(buf, return_indent);
|
loc_condition.format(buf, return_indent);
|
||||||
newline(buf, indent);
|
newline(buf, indent);
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf.push(' ');
|
|
||||||
loc_condition.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
|
||||||
buf.push(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str("then");
|
|
||||||
|
|
||||||
if is_multiline {
|
|
||||||
match &loc_then.value {
|
|
||||||
Expr::SpaceBefore(expr_below, spaces_below) => {
|
|
||||||
// we want exactly one newline, user-inserted extra newlines are ignored.
|
|
||||||
newline(buf, return_indent);
|
|
||||||
fmt_comments_only(buf, spaces_below.iter(), NewlineAt::Bottom, return_indent);
|
|
||||||
|
|
||||||
match &expr_below {
|
|
||||||
Expr::SpaceAfter(expr_above, spaces_above) => {
|
|
||||||
expr_above.format(buf, return_indent);
|
|
||||||
|
|
||||||
fmt_comments_only(buf, spaces_above.iter(), NewlineAt::Top, return_indent);
|
|
||||||
newline(buf, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
expr_below.format(buf, return_indent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
} else {
|
||||||
loc_condition.format(buf, return_indent);
|
buf.push(' ');
|
||||||
}
|
loc_condition.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||||
|
buf.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str("then");
|
||||||
|
|
||||||
|
if is_multiline {
|
||||||
|
match &loc_then.value {
|
||||||
|
Expr::SpaceBefore(expr_below, spaces_below) => {
|
||||||
|
// we want exactly one newline, user-inserted extra newlines are ignored.
|
||||||
|
newline(buf, return_indent);
|
||||||
|
fmt_comments_only(buf, spaces_below.iter(), NewlineAt::Bottom, return_indent);
|
||||||
|
|
||||||
|
match &expr_below {
|
||||||
|
Expr::SpaceAfter(expr_above, spaces_above) => {
|
||||||
|
expr_above.format(buf, return_indent);
|
||||||
|
|
||||||
|
fmt_comments_only(
|
||||||
|
buf,
|
||||||
|
spaces_above.iter(),
|
||||||
|
NewlineAt::Top,
|
||||||
|
return_indent,
|
||||||
|
);
|
||||||
|
newline(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
expr_below.format(buf, return_indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
loc_condition.format(buf, return_indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.push_str(" ");
|
||||||
|
loc_then.format(buf, return_indent);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
buf.push_str(" ");
|
|
||||||
loc_then.format(buf, return_indent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
|
@ -728,7 +740,7 @@ fn fmt_if<'a>(
|
||||||
buf.push_str(" else ");
|
buf.push_str(" else ");
|
||||||
}
|
}
|
||||||
|
|
||||||
loc_else.format(buf, return_indent);
|
final_else.format(buf, return_indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fmt_closure<'a>(
|
pub fn fmt_closure<'a>(
|
||||||
|
|
|
@ -19,6 +19,7 @@ roc_parse = { path = "../parse" }
|
||||||
roc_solve = { path = "../solve" }
|
roc_solve = { path = "../solve" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_reporting = { path = "../reporting" }
|
roc_reporting = { path = "../reporting" }
|
||||||
|
ven_pretty = { path = "../../vendor/pretty" }
|
||||||
bumpalo = { version = "3.2", features = ["collections"] }
|
bumpalo = { version = "3.2", features = ["collections"] }
|
||||||
inlinable_string = "0.1"
|
inlinable_string = "0.1"
|
||||||
parking_lot = { version = "0.11", features = ["deadlock_detection"] }
|
parking_lot = { version = "0.11", features = ["deadlock_detection"] }
|
||||||
|
|
|
@ -631,6 +631,7 @@ struct ModuleHeader<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleNameEnum<'a>,
|
module_name: ModuleNameEnum<'a>,
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
|
is_root_module: bool,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
||||||
packages: MutMap<&'a str, PackageOrPath<'a>>,
|
packages: MutMap<&'a str, PackageOrPath<'a>>,
|
||||||
|
@ -781,6 +782,14 @@ enum Msg<'a> {
|
||||||
FailedToParse(ParseProblem<'a, SyntaxError<'a>>),
|
FailedToParse(ParseProblem<'a, SyntaxError<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum PlatformPath<'a> {
|
||||||
|
NotSpecified,
|
||||||
|
Valid(To<'a>),
|
||||||
|
RootIsInterface,
|
||||||
|
RootIsPkgConfig,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct State<'a> {
|
struct State<'a> {
|
||||||
pub root_id: ModuleId,
|
pub root_id: ModuleId,
|
||||||
|
@ -789,7 +798,7 @@ struct State<'a> {
|
||||||
pub stdlib: &'a StdLib,
|
pub stdlib: &'a StdLib,
|
||||||
pub exposed_types: SubsByModule,
|
pub exposed_types: SubsByModule,
|
||||||
pub output_path: Option<&'a str>,
|
pub output_path: Option<&'a str>,
|
||||||
pub platform_path: Option<To<'a>>,
|
pub platform_path: PlatformPath<'a>,
|
||||||
|
|
||||||
pub headers_parsed: MutSet<ModuleId>,
|
pub headers_parsed: MutSet<ModuleId>,
|
||||||
|
|
||||||
|
@ -994,6 +1003,8 @@ pub enum LoadingProblem<'a> {
|
||||||
},
|
},
|
||||||
ParsingFailed(ParseProblem<'a, SyntaxError<'a>>),
|
ParsingFailed(ParseProblem<'a, SyntaxError<'a>>),
|
||||||
UnexpectedHeader(String),
|
UnexpectedHeader(String),
|
||||||
|
/// there is no platform (likely running an Interface module)
|
||||||
|
NoPlatform(String),
|
||||||
|
|
||||||
MsgChannelDied,
|
MsgChannelDied,
|
||||||
ErrJoiningWorkerThreads,
|
ErrJoiningWorkerThreads,
|
||||||
|
@ -1147,6 +1158,7 @@ impl<'a> LoadStart<'a> {
|
||||||
load_filename(
|
load_filename(
|
||||||
arena,
|
arena,
|
||||||
filename,
|
filename,
|
||||||
|
true,
|
||||||
None,
|
None,
|
||||||
Arc::clone(&arc_modules),
|
Arc::clone(&arc_modules),
|
||||||
Arc::clone(&ident_ids_by_module),
|
Arc::clone(&ident_ids_by_module),
|
||||||
|
@ -1415,7 +1427,7 @@ where
|
||||||
goal_phase,
|
goal_phase,
|
||||||
stdlib,
|
stdlib,
|
||||||
output_path: None,
|
output_path: None,
|
||||||
platform_path: None,
|
platform_path: PlatformPath::NotSpecified,
|
||||||
module_cache: ModuleCache::default(),
|
module_cache: ModuleCache::default(),
|
||||||
dependencies: Dependencies::default(),
|
dependencies: Dependencies::default(),
|
||||||
procedures: MutMap::default(),
|
procedures: MutMap::default(),
|
||||||
|
@ -1492,7 +1504,7 @@ where
|
||||||
state,
|
state,
|
||||||
subs,
|
subs,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
)));
|
)?));
|
||||||
}
|
}
|
||||||
Msg::FailedToParse(problem) => {
|
Msg::FailedToParse(problem) => {
|
||||||
// Shut down all the worker threads.
|
// Shut down all the worker threads.
|
||||||
|
@ -1623,16 +1635,25 @@ fn update<'a>(
|
||||||
|
|
||||||
match header_extra {
|
match header_extra {
|
||||||
App { to_platform } => {
|
App { to_platform } => {
|
||||||
debug_assert_eq!(state.platform_path, None);
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
|
state.platform_path = PlatformPath::Valid(to_platform.clone());
|
||||||
state.platform_path = Some(to_platform.clone());
|
|
||||||
}
|
}
|
||||||
PkgConfig { .. } => {
|
PkgConfig { .. } => {
|
||||||
debug_assert_eq!(state.platform_id, None);
|
debug_assert_eq!(state.platform_id, None);
|
||||||
|
|
||||||
state.platform_id = Some(header.module_id);
|
state.platform_id = Some(header.module_id);
|
||||||
|
|
||||||
|
if header.is_root_module {
|
||||||
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
|
state.platform_path = PlatformPath::RootIsPkgConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Interface => {
|
||||||
|
if header.is_root_module {
|
||||||
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
|
state.platform_path = PlatformPath::RootIsInterface;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Interface => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// store an ID to name mapping, so we know the file to read when fetching dependencies' headers
|
// store an ID to name mapping, so we know the file to read when fetching dependencies' headers
|
||||||
|
@ -2070,7 +2091,7 @@ fn finish_specialization(
|
||||||
state: State,
|
state: State,
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
exposed_to_host: MutMap<Symbol, Variable>,
|
exposed_to_host: MutMap<Symbol, Variable>,
|
||||||
) -> MonomorphizedModule {
|
) -> Result<MonomorphizedModule, LoadingProblem> {
|
||||||
let module_ids = Arc::try_unwrap(state.arc_modules)
|
let module_ids = Arc::try_unwrap(state.arc_modules)
|
||||||
.unwrap_or_else(|_| panic!("There were still outstanding Arc references to module_ids"))
|
.unwrap_or_else(|_| panic!("There were still outstanding Arc references to module_ids"))
|
||||||
.into_inner()
|
.into_inner()
|
||||||
|
@ -2097,21 +2118,89 @@ fn finish_specialization(
|
||||||
..
|
..
|
||||||
} = module_cache;
|
} = module_cache;
|
||||||
|
|
||||||
let sources = sources
|
let sources: MutMap<ModuleId, (PathBuf, Box<str>)> = sources
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, (path, src))| (id, (path, src.into())))
|
.map(|(id, (path, src))| (id, (path, src.into())))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let path_to_platform = {
|
let path_to_platform = {
|
||||||
|
use PlatformPath::*;
|
||||||
let package_or_path = match platform_path {
|
let package_or_path = match platform_path {
|
||||||
Some(To::ExistingPackage(shorthand)) => {
|
Valid(To::ExistingPackage(shorthand)) => {
|
||||||
match (*state.arc_shorthands).lock().get(shorthand) {
|
match (*state.arc_shorthands).lock().get(shorthand) {
|
||||||
Some(p_or_p) => p_or_p.clone(),
|
Some(p_or_p) => p_or_p.clone(),
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(To::NewPackage(p_or_p)) => p_or_p,
|
Valid(To::NewPackage(p_or_p)) => p_or_p,
|
||||||
None => panic!("no platform!"),
|
other => {
|
||||||
|
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
|
||||||
|
use ven_pretty::DocAllocator;
|
||||||
|
|
||||||
|
let module_id = state.root_id;
|
||||||
|
|
||||||
|
let palette = DEFAULT_PALETTE;
|
||||||
|
|
||||||
|
// Report parsing and canonicalization problems
|
||||||
|
let alloc = RocDocAllocator::new(&[], module_id, &interns);
|
||||||
|
|
||||||
|
let report = {
|
||||||
|
match other {
|
||||||
|
Valid(_) => unreachable!(),
|
||||||
|
NotSpecified => {
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow("I could not find a platform based on your input file."),
|
||||||
|
alloc.reflow(r"Does the module header contain an entry that looks like this:"),
|
||||||
|
alloc
|
||||||
|
.parser_suggestion(" packages { base: \"platform\" }")
|
||||||
|
.indent(4),
|
||||||
|
alloc.reflow("See also TODO."),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "NO PLATFORM".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RootIsInterface => {
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"The input file is a interface file, but only app modules can be ran."),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I will still parse and typecheck the input file and its dependencies,"),
|
||||||
|
alloc.reflow(r"but won't output any executable."),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "NO PLATFORM".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RootIsPkgConfig => {
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"The input file is a package config file, but only app modules can be ran."),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I will still parse and typecheck the input file and its dependencies,"),
|
||||||
|
alloc.reflow(r"but won't output any executable."),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "NO PLATFORM".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut buf = String::new();
|
||||||
|
|
||||||
|
report.render_color_terminal(&mut buf, &alloc, &palette);
|
||||||
|
|
||||||
|
return Err(LoadingProblem::NoPlatform(buf));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match package_or_path {
|
match package_or_path {
|
||||||
|
@ -2123,7 +2212,7 @@ fn finish_specialization(
|
||||||
|
|
||||||
let platform_path = path_to_platform.into();
|
let platform_path = path_to_platform.into();
|
||||||
|
|
||||||
MonomorphizedModule {
|
Ok(MonomorphizedModule {
|
||||||
can_problems,
|
can_problems,
|
||||||
mono_problems,
|
mono_problems,
|
||||||
type_problems,
|
type_problems,
|
||||||
|
@ -2136,7 +2225,7 @@ fn finish_specialization(
|
||||||
procedures,
|
procedures,
|
||||||
sources,
|
sources,
|
||||||
timings: state.timings,
|
timings: state.timings,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(
|
fn finish(
|
||||||
|
@ -2319,6 +2408,7 @@ fn load_module<'a>(
|
||||||
load_filename(
|
load_filename(
|
||||||
arena,
|
arena,
|
||||||
filename,
|
filename,
|
||||||
|
false,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
module_ids,
|
module_ids,
|
||||||
ident_ids_by_module,
|
ident_ids_by_module,
|
||||||
|
@ -2358,6 +2448,7 @@ fn parse_header<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
read_file_duration: Duration,
|
read_file_duration: Duration,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
is_root_module: bool,
|
||||||
opt_shorthand: Option<&'a str>,
|
opt_shorthand: Option<&'a str>,
|
||||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
|
@ -2383,6 +2474,7 @@ fn parse_header<'a>(
|
||||||
value: ModuleNameEnum::Interface(header.name.value),
|
value: ModuleNameEnum::Interface(header.name.value),
|
||||||
},
|
},
|
||||||
filename,
|
filename,
|
||||||
|
is_root_module,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
&[],
|
&[],
|
||||||
header.exposes.into_bump_slice(),
|
header.exposes.into_bump_slice(),
|
||||||
|
@ -2405,6 +2497,7 @@ fn parse_header<'a>(
|
||||||
value: ModuleNameEnum::App(header.name.value),
|
value: ModuleNameEnum::App(header.name.value),
|
||||||
},
|
},
|
||||||
filename,
|
filename,
|
||||||
|
is_root_module,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
packages,
|
packages,
|
||||||
header.provides.into_bump_slice(),
|
header.provides.into_bump_slice(),
|
||||||
|
@ -2507,9 +2600,11 @@ fn parse_header<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load a module by its filename
|
/// Load a module by its filename
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn load_filename<'a>(
|
fn load_filename<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
is_root_module: bool,
|
||||||
opt_shorthand: Option<&'a str>,
|
opt_shorthand: Option<&'a str>,
|
||||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
|
@ -2525,6 +2620,7 @@ fn load_filename<'a>(
|
||||||
arena,
|
arena,
|
||||||
file_io_duration,
|
file_io_duration,
|
||||||
filename,
|
filename,
|
||||||
|
is_root_module,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
module_ids,
|
module_ids,
|
||||||
ident_ids_by_module,
|
ident_ids_by_module,
|
||||||
|
@ -2559,6 +2655,7 @@ fn load_from_str<'a>(
|
||||||
arena,
|
arena,
|
||||||
file_io_duration,
|
file_io_duration,
|
||||||
filename,
|
filename,
|
||||||
|
false,
|
||||||
None,
|
None,
|
||||||
module_ids,
|
module_ids,
|
||||||
ident_ids_by_module,
|
ident_ids_by_module,
|
||||||
|
@ -2580,6 +2677,7 @@ enum ModuleNameEnum<'a> {
|
||||||
fn send_header<'a>(
|
fn send_header<'a>(
|
||||||
loc_name: Located<ModuleNameEnum<'a>>,
|
loc_name: Located<ModuleNameEnum<'a>>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
is_root_module: bool,
|
||||||
opt_shorthand: Option<&'a str>,
|
opt_shorthand: Option<&'a str>,
|
||||||
packages: &'a [Located<PackageEntry<'a>>],
|
packages: &'a [Located<PackageEntry<'a>>],
|
||||||
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
|
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
|
||||||
|
@ -2766,6 +2864,7 @@ fn send_header<'a>(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
|
is_root_module,
|
||||||
exposed_ident_ids: ident_ids,
|
exposed_ident_ids: ident_ids,
|
||||||
module_name: loc_name.value,
|
module_name: loc_name.value,
|
||||||
packages: package_entries,
|
packages: package_entries,
|
||||||
|
@ -2787,6 +2886,7 @@ fn send_header<'a>(
|
||||||
fn send_header_two<'a>(
|
fn send_header_two<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
is_root_module: bool,
|
||||||
shorthand: &'a str,
|
shorthand: &'a str,
|
||||||
app_module_id: ModuleId,
|
app_module_id: ModuleId,
|
||||||
packages: &'a [Located<PackageEntry<'a>>],
|
packages: &'a [Located<PackageEntry<'a>>],
|
||||||
|
@ -2983,6 +3083,7 @@ fn send_header_two<'a>(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
|
is_root_module,
|
||||||
exposed_ident_ids: ident_ids,
|
exposed_ident_ids: ident_ids,
|
||||||
module_name,
|
module_name,
|
||||||
packages: package_entries,
|
packages: package_entries,
|
||||||
|
@ -3126,6 +3227,7 @@ fn fabricate_pkg_config_module<'a>(
|
||||||
send_header_two(
|
send_header_two(
|
||||||
arena,
|
arena,
|
||||||
filename,
|
filename,
|
||||||
|
false,
|
||||||
shorthand,
|
shorthand,
|
||||||
app_module_id,
|
app_module_id,
|
||||||
&[],
|
&[],
|
||||||
|
|
|
@ -127,7 +127,7 @@ pub enum Expr<'a> {
|
||||||
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
||||||
|
|
||||||
// Conditionals
|
// Conditionals
|
||||||
If(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
If(&'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)], &'a Loc<Expr<'a>>),
|
||||||
When(
|
When(
|
||||||
/// The condition
|
/// The condition
|
||||||
&'a Loc<Expr<'a>>,
|
&'a Loc<Expr<'a>>,
|
||||||
|
|
|
@ -60,11 +60,12 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn space0_around_e<'a, P, S, E>(
|
pub fn space0_around_ee<'a, P, S, E>(
|
||||||
parser: P,
|
parser: P,
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
space_problem: fn(BadInputError, Row, Col) -> E,
|
space_problem: fn(BadInputError, Row, Col) -> E,
|
||||||
indent_problem: fn(Row, Col) -> E,
|
indent_before_problem: fn(Row, Col) -> E,
|
||||||
|
indent_after_problem: fn(Row, Col) -> E,
|
||||||
) -> impl Parser<'a, Located<S>, E>
|
) -> impl Parser<'a, Located<S>, E>
|
||||||
where
|
where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
|
@ -75,8 +76,11 @@ where
|
||||||
{
|
{
|
||||||
parser::map_with_arena(
|
parser::map_with_arena(
|
||||||
and(
|
and(
|
||||||
space0_e(min_indent, space_problem, indent_problem),
|
space0_e(min_indent, space_problem, indent_before_problem),
|
||||||
and(parser, space0_e(min_indent, space_problem, indent_problem)),
|
and(
|
||||||
|
parser,
|
||||||
|
space0_e(min_indent, space_problem, indent_after_problem),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
move |arena: &'a Bump,
|
move |arena: &'a Bump,
|
||||||
tuples: (
|
tuples: (
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::ast::{
|
||||||
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
line_comment, space0, space0_after, space0_after_e, space0_around, space0_around_e,
|
line_comment, space0, space0_after, space0_after_e, space0_around, space0_around_ee,
|
||||||
space0_before, space0_before_e, space0_e, space1, space1_around, space1_before, spaces_exactly,
|
space0_before, space0_before_e, space0_e, space1, space1_before, spaces_exactly,
|
||||||
};
|
};
|
||||||
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
|
@ -11,8 +11,8 @@ use crate::number_literal::number_literal;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, allocated, and_then_with_indent_level, ascii_char, ascii_string, attempt, backtrackable,
|
self, allocated, and_then_with_indent_level, ascii_char, ascii_string, attempt, backtrackable,
|
||||||
fail, map, newline_char, not, not_followed_by, optional, sep_by1, specialize, specialize_ref,
|
fail, map, newline_char, not, not_followed_by, optional, sep_by1, specialize, specialize_ref,
|
||||||
then, unexpected, unexpected_eof, word1, word2, EExpr, Either, ParseResult, Parser, State,
|
then, unexpected, unexpected_eof, word1, word2, BadInputError, EExpr, Either, If, List,
|
||||||
SyntaxError, When,
|
ParseResult, Parser, State, SyntaxError, When,
|
||||||
};
|
};
|
||||||
use crate::pattern::loc_closure_param;
|
use crate::pattern::loc_closure_param;
|
||||||
use crate::type_annotation;
|
use crate::type_annotation;
|
||||||
|
@ -324,7 +324,7 @@ pub fn expr_to_pattern<'a>(
|
||||||
| Expr::Closure(_, _)
|
| Expr::Closure(_, _)
|
||||||
| Expr::BinOp(_)
|
| Expr::BinOp(_)
|
||||||
| Expr::Defs(_, _)
|
| Expr::Defs(_, _)
|
||||||
| Expr::If(_, _, _)
|
| Expr::If(_, _)
|
||||||
| Expr::When(_, _)
|
| Expr::When(_, _)
|
||||||
| Expr::MalformedClosure
|
| Expr::MalformedClosure
|
||||||
| Expr::PrecedenceConflict(_, _, _, _)
|
| Expr::PrecedenceConflict(_, _, _, _)
|
||||||
|
@ -1029,14 +1029,15 @@ mod when {
|
||||||
and!(
|
and!(
|
||||||
when_with_indent(),
|
when_with_indent(),
|
||||||
skip_second!(
|
skip_second!(
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
loc!(specialize_ref(
|
loc!(specialize_ref(
|
||||||
When::Syntax,
|
When::Syntax,
|
||||||
move |arena, state| parse_expr(min_indent, arena, state)
|
move |arena, state| parse_expr(min_indent, arena, state)
|
||||||
)),
|
)),
|
||||||
min_indent,
|
min_indent,
|
||||||
When::Space,
|
When::Space,
|
||||||
When::IndentCondition
|
When::IndentCondition,
|
||||||
|
When::IndentIs,
|
||||||
),
|
),
|
||||||
parser::keyword_e(keyword::IS, When::Is)
|
parser::keyword_e(keyword::IS, When::Is)
|
||||||
)
|
)
|
||||||
|
@ -1182,13 +1183,14 @@ mod when {
|
||||||
skip_first!(
|
skip_first!(
|
||||||
parser::keyword_e(keyword::IF, When::IfToken),
|
parser::keyword_e(keyword::IF, When::IfToken),
|
||||||
// TODO we should require space before the expression but not after
|
// TODO we should require space before the expression but not after
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
loc!(specialize_ref(When::IfGuard, move |arena, state| {
|
loc!(specialize_ref(When::IfGuard, move |arena, state| {
|
||||||
parse_expr(min_indent, arena, state)
|
parse_expr(min_indent, arena, state)
|
||||||
})),
|
})),
|
||||||
min_indent,
|
min_indent,
|
||||||
When::Space,
|
When::Space,
|
||||||
When::IndentIfGuard,
|
When::IndentIfGuard,
|
||||||
|
When::IndentArrow,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Some
|
Some
|
||||||
|
@ -1234,41 +1236,100 @@ mod when {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
fn if_branch<'a>(
|
||||||
map_with_arena!(
|
min_indent: u16,
|
||||||
and!(
|
) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), If<'a>> {
|
||||||
skip_first!(
|
move |arena, state| {
|
||||||
parser::keyword(keyword::IF, min_indent),
|
// NOTE: only parse spaces before the expression
|
||||||
space1_around(
|
let (_, cond, state) = space0_around_ee(
|
||||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
specialize_ref(
|
||||||
min_indent,
|
If::Syntax,
|
||||||
)
|
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
),
|
),
|
||||||
and!(
|
min_indent,
|
||||||
skip_first!(
|
If::Space,
|
||||||
parser::keyword(keyword::THEN, min_indent),
|
If::IndentCondition,
|
||||||
space1_around(
|
If::IndentThenToken,
|
||||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
)
|
||||||
min_indent,
|
.parse(arena, state)
|
||||||
)
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
),
|
|
||||||
skip_first!(
|
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then)
|
||||||
parser::keyword(keyword::ELSE, min_indent),
|
.parse(arena, state)
|
||||||
// NOTE changed this from space1_around to space1_before
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
space1_before(
|
|
||||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
let (_, then_branch, state) = space0_around_ee(
|
||||||
min_indent,
|
specialize_ref(
|
||||||
)
|
If::Syntax,
|
||||||
)
|
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
)
|
),
|
||||||
),
|
min_indent,
|
||||||
|arena: &'a Bump, (condition, (then_branch, else_branch))| {
|
If::Space,
|
||||||
Expr::If(
|
If::IndentThenBranch,
|
||||||
&*arena.alloc(condition),
|
If::IndentElseToken,
|
||||||
&*arena.alloc(then_branch),
|
)
|
||||||
&*arena.alloc(else_branch),
|
.parse(arena, state)
|
||||||
)
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
}
|
|
||||||
|
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else)
|
||||||
|
.parse(arena, state)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
Ok((MadeProgress, (cond, then_branch), state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||||
|
move |arena: &'a Bump, state| {
|
||||||
|
let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?;
|
||||||
|
|
||||||
|
let mut branches = Vec::with_capacity_in(1, arena);
|
||||||
|
|
||||||
|
let mut loop_state = state;
|
||||||
|
|
||||||
|
let state_final_else = loop {
|
||||||
|
let (_, (cond, then_branch), state) = if_branch(min_indent).parse(arena, loop_state)?;
|
||||||
|
|
||||||
|
branches.push((cond, then_branch));
|
||||||
|
|
||||||
|
// try to parse another `if`
|
||||||
|
// NOTE this drops spaces between the `else` and the `if`
|
||||||
|
let optional_if = and!(
|
||||||
|
backtrackable(space0_e(min_indent, If::Space, If::IndentIf)),
|
||||||
|
parser::keyword_e(keyword::IF, If::If)
|
||||||
|
);
|
||||||
|
|
||||||
|
match optional_if.parse(arena, state) {
|
||||||
|
Err((_, _, state)) => break state,
|
||||||
|
Ok((_, _, state)) => {
|
||||||
|
loop_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_, else_branch, state) = space0_before_e(
|
||||||
|
specialize_ref(
|
||||||
|
If::Syntax,
|
||||||
|
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
|
),
|
||||||
|
min_indent,
|
||||||
|
If::Space,
|
||||||
|
If::IndentElseBranch,
|
||||||
|
)
|
||||||
|
.parse(arena, state_final_else)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch));
|
||||||
|
|
||||||
|
Ok((MadeProgress, expr, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
|
specialize(
|
||||||
|
|e, r, c| SyntaxError::Expr(EExpr::If(e, r, c)),
|
||||||
|
if_expr_help(min_indent),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1632,37 +1693,42 @@ fn binop<'a>() -> impl Parser<'a, BinOp, SyntaxError<'a>> {
|
||||||
map!(ascii_char(b'%'), |_| BinOp::Percent)
|
map!(ascii_char(b'%'), |_| BinOp::Percent)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn list_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
pub fn list_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
specialize(
|
||||||
let elems = collection_trailing_sep!(
|
|e, r, c| SyntaxError::Expr(EExpr::List(e, r, c)),
|
||||||
ascii_char(b'['),
|
list_literal_help(min_indent),
|
||||||
loc!(expr(min_indent)),
|
|
||||||
ascii_char(b','),
|
|
||||||
ascii_char(b']'),
|
|
||||||
min_indent
|
|
||||||
);
|
|
||||||
|
|
||||||
parser::attempt(
|
|
||||||
Attempting::List,
|
|
||||||
map_with_arena!(elems, |arena,
|
|
||||||
(parsed_elems, final_comments): (
|
|
||||||
Vec<'a, Located<Expr<'a>>>,
|
|
||||||
&'a [CommentOrNewline<'a>]
|
|
||||||
)| {
|
|
||||||
let mut allocated = Vec::with_capacity_in(parsed_elems.len(), arena);
|
|
||||||
|
|
||||||
for parsed_elem in parsed_elems {
|
|
||||||
allocated.push(&*arena.alloc(parsed_elem));
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr::List {
|
|
||||||
items: allocated.into_bump_slice(),
|
|
||||||
final_comments,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> {
|
||||||
|
move |arena, state| {
|
||||||
|
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!(
|
||||||
|
word1(b'[', List::Open),
|
||||||
|
specialize_ref(List::Syntax, loc!(expr(min_indent))),
|
||||||
|
word1(b',', List::End),
|
||||||
|
word1(b']', List::End),
|
||||||
|
min_indent,
|
||||||
|
List::Open,
|
||||||
|
List::Space,
|
||||||
|
List::IndentEnd
|
||||||
|
)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let mut allocated = Vec::with_capacity_in(parsed_elems.len(), arena);
|
||||||
|
|
||||||
|
for parsed_elem in parsed_elems {
|
||||||
|
allocated.push(&*arena.alloc(parsed_elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = Expr::List {
|
||||||
|
items: allocated.into_bump_slice(),
|
||||||
|
final_comments,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((MadeProgress, expr, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parser<'a, Vec<'a, Located<AssignedField<'a, S>>>>
|
// Parser<'a, Vec<'a, Located<AssignedField<'a, S>>>>
|
||||||
fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
then(
|
then(
|
||||||
|
|
|
@ -378,12 +378,28 @@ pub enum EExpr<'a> {
|
||||||
Space(BadInputError, Row, Col),
|
Space(BadInputError, Row, Col),
|
||||||
|
|
||||||
When(When<'a>, Row, Col),
|
When(When<'a>, Row, Col),
|
||||||
|
If(If<'a>, Row, Col),
|
||||||
|
|
||||||
|
List(List<'a>, Row, Col),
|
||||||
|
|
||||||
// EInParens(PInParens<'a>, Row, Col),
|
// EInParens(PInParens<'a>, Row, Col),
|
||||||
IndentStart(Row, Col),
|
IndentStart(Row, Col),
|
||||||
IndentEnd(Row, Col),
|
IndentEnd(Row, Col),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum List<'a> {
|
||||||
|
Open(Row, Col),
|
||||||
|
End(Row, Col),
|
||||||
|
Space(BadInputError, Row, Col),
|
||||||
|
|
||||||
|
Syntax(&'a SyntaxError<'a>, Row, Col),
|
||||||
|
Expr(&'a EExpr<'a>, Row, Col),
|
||||||
|
|
||||||
|
IndentOpen(Row, Col),
|
||||||
|
IndentEnd(Row, Col),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum When<'a> {
|
pub enum When<'a> {
|
||||||
Space(BadInputError, Row, Col),
|
Space(BadInputError, Row, Col),
|
||||||
|
@ -408,6 +424,26 @@ pub enum When<'a> {
|
||||||
PatternAlignment(u16, Row, Col),
|
PatternAlignment(u16, Row, Col),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum If<'a> {
|
||||||
|
Space(BadInputError, Row, Col),
|
||||||
|
If(Row, Col),
|
||||||
|
Then(Row, Col),
|
||||||
|
Else(Row, Col),
|
||||||
|
// TODO make EEXpr
|
||||||
|
Condition(&'a EExpr<'a>, Row, Col),
|
||||||
|
ThenBranch(&'a EExpr<'a>, Row, Col),
|
||||||
|
ElseBranch(&'a EExpr<'a>, Row, Col),
|
||||||
|
Syntax(&'a SyntaxError<'a>, Row, Col),
|
||||||
|
|
||||||
|
IndentCondition(Row, Col),
|
||||||
|
IndentIf(Row, Col),
|
||||||
|
IndentThenToken(Row, Col),
|
||||||
|
IndentElseToken(Row, Col),
|
||||||
|
IndentThenBranch(Row, Col),
|
||||||
|
IndentElseBranch(Row, Col),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum EPattern<'a> {
|
pub enum EPattern<'a> {
|
||||||
Record(PRecord<'a>, Row, Col),
|
Record(PRecord<'a>, Row, Col),
|
||||||
|
@ -1431,10 +1467,11 @@ macro_rules! collection_trailing_sep_e {
|
||||||
and!(
|
and!(
|
||||||
$crate::parser::trailing_sep_by0(
|
$crate::parser::trailing_sep_by0(
|
||||||
$delimiter,
|
$delimiter,
|
||||||
$crate::blankspace::space0_around_e(
|
$crate::blankspace::space0_around_ee(
|
||||||
$elem,
|
$elem,
|
||||||
$min_indent,
|
$min_indent,
|
||||||
$space_problem,
|
$space_problem,
|
||||||
|
$indent_problem,
|
||||||
$indent_problem
|
$indent_problem
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ast::Pattern;
|
use crate::ast::Pattern;
|
||||||
use crate::blankspace::{space0_around_e, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::{ident, lowercase_ident, Ident};
|
use crate::ident::{ident, lowercase_ident, Ident};
|
||||||
use crate::number_literal::number_literal;
|
use crate::number_literal::number_literal;
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
|
@ -133,11 +133,12 @@ fn loc_pattern_in_parens_help<'a>(
|
||||||
) -> impl Parser<'a, Located<Pattern<'a>>, PInParens<'a>> {
|
) -> impl Parser<'a, Located<Pattern<'a>>, PInParens<'a>> {
|
||||||
between!(
|
between!(
|
||||||
word1(b'(', PInParens::Open),
|
word1(b'(', PInParens::Open),
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
move |arena, state| specialize_ref(PInParens::Syntax, loc_pattern(min_indent))
|
move |arena, state| specialize_ref(PInParens::Syntax, loc_pattern(min_indent))
|
||||||
.parse(arena, state),
|
.parse(arena, state),
|
||||||
min_indent,
|
min_indent,
|
||||||
PInParens::Space,
|
PInParens::Space,
|
||||||
|
PInParens::IndentOpen,
|
||||||
PInParens::IndentEnd,
|
PInParens::IndentEnd,
|
||||||
),
|
),
|
||||||
word1(b')', PInParens::End)
|
word1(b')', PInParens::End)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ast::{AssignedField, Tag, TypeAnnotation};
|
use crate::ast::{AssignedField, Tag, TypeAnnotation};
|
||||||
use crate::blankspace::{space0_around_e, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::join_module_parts;
|
use crate::ident::join_module_parts;
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
|
@ -146,11 +146,12 @@ fn loc_type_in_parens<'a>(
|
||||||
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> {
|
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> {
|
||||||
between!(
|
between!(
|
||||||
word1(b'(', TInParens::Open),
|
word1(b'(', TInParens::Open),
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent))
|
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent))
|
||||||
.parse(arena, state),
|
.parse(arena, state),
|
||||||
min_indent,
|
min_indent,
|
||||||
TInParens::Space,
|
TInParens::Space,
|
||||||
|
TInParens::IndentOpen,
|
||||||
TInParens::IndentEnd,
|
TInParens::IndentEnd,
|
||||||
),
|
),
|
||||||
word1(b')', TInParens::End)
|
word1(b')', TInParens::End)
|
||||||
|
@ -436,11 +437,12 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
|
||||||
let (p2, rest, state) = zero_or_more!(skip_first!(
|
let (p2, rest, state) = zero_or_more!(skip_first!(
|
||||||
word1(b',', Type::TFunctionArgument),
|
word1(b',', Type::TFunctionArgument),
|
||||||
one_of![
|
one_of![
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
term(min_indent),
|
term(min_indent),
|
||||||
min_indent,
|
min_indent,
|
||||||
Type::TSpace,
|
Type::TSpace,
|
||||||
Type::TIndentStart
|
Type::TIndentStart,
|
||||||
|
Type::TIndentEnd
|
||||||
),
|
),
|
||||||
|_, state: State<'a>| Err((
|
|_, state: State<'a>| Err((
|
||||||
NoProgress,
|
NoProgress,
|
||||||
|
|
|
@ -158,7 +158,10 @@ enum Context {
|
||||||
enum Node {
|
enum Node {
|
||||||
WhenCondition,
|
WhenCondition,
|
||||||
WhenBranch,
|
WhenBranch,
|
||||||
// WhenIfGuard,
|
IfCondition,
|
||||||
|
IfThenBranch,
|
||||||
|
IfElseBranch,
|
||||||
|
ListElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_expr_report<'a>(
|
fn to_expr_report<'a>(
|
||||||
|
@ -173,10 +176,240 @@ fn to_expr_report<'a>(
|
||||||
|
|
||||||
match parse_problem {
|
match parse_problem {
|
||||||
EExpr::When(when, row, col) => to_when_report(alloc, filename, context, &when, *row, *col),
|
EExpr::When(when, row, col) => to_when_report(alloc, filename, context, &when, *row, *col),
|
||||||
|
EExpr::If(if_, row, col) => to_if_report(alloc, filename, context, &if_, *row, *col),
|
||||||
|
EExpr::List(list, row, col) => to_list_report(alloc, filename, context, &list, *row, *col),
|
||||||
_ => todo!("unhandled parse error: {:?}", parse_problem),
|
_ => todo!("unhandled parse error: {:?}", parse_problem),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_list_report<'a>(
|
||||||
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
|
filename: PathBuf,
|
||||||
|
context: Context,
|
||||||
|
parse_problem: &roc_parse::parser::List<'a>,
|
||||||
|
start_row: Row,
|
||||||
|
start_col: Col,
|
||||||
|
) -> Report<'a> {
|
||||||
|
use roc_parse::parser::List;
|
||||||
|
|
||||||
|
match *parse_problem {
|
||||||
|
List::Syntax(syntax, row, col) => to_syntax_report(alloc, filename, syntax, row, col),
|
||||||
|
List::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
|
||||||
|
|
||||||
|
List::Expr(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::ListElement, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
List::Open(row, col) | List::End(row, col) => {
|
||||||
|
match dbg!(what_is_next(alloc.src_lines, row, col)) {
|
||||||
|
Next::Other(Some(',')) => {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||||
|
let region = Region::from_row_col(row, col);
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(
|
||||||
|
r"I am partway through started parsing a list, but I got stuck here:",
|
||||||
|
),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc
|
||||||
|
.reflow(r"I was expecting to see a list entry before this comma, "),
|
||||||
|
alloc.reflow(r"so try adding a list entry"),
|
||||||
|
alloc.reflow(r" and see if that helps?"),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED LIST".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||||
|
let region = Region::from_row_col(row, col);
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(
|
||||||
|
r"I am partway through started parsing a list, but I got stuck here:",
|
||||||
|
),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(
|
||||||
|
r"I was expecting to see a closing square bracket before this, ",
|
||||||
|
),
|
||||||
|
alloc.reflow(r"so try adding a "),
|
||||||
|
alloc.parser_suggestion("]"),
|
||||||
|
alloc.reflow(r" and see if that helps?"),
|
||||||
|
]),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.note("When "),
|
||||||
|
alloc.reflow(r"I get stuck like this, "),
|
||||||
|
alloc.reflow(r"it usually means that there is a missing parenthesis "),
|
||||||
|
alloc.reflow(r"or bracket somewhere earlier. "),
|
||||||
|
alloc.reflow(r"It could also be a stray keyword or operator."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED LIST".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List::IndentOpen(row, col) | List::IndentEnd(row, col) => {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||||
|
let region = Region::from_row_col(row, col);
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"I cannot find the end of this list:"),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"You could change it to something like "),
|
||||||
|
alloc.parser_suggestion("[ 1, 2, 3 ]"),
|
||||||
|
alloc.reflow(" or even just "),
|
||||||
|
alloc.parser_suggestion("[]"),
|
||||||
|
alloc.reflow(". Anything where there is an open and a close square bracket, "),
|
||||||
|
alloc.reflow("and where the elements of the list are separated by commas."),
|
||||||
|
]),
|
||||||
|
note_for_tag_union_type_indent(alloc),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED LIST".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_if_report<'a>(
|
||||||
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
|
filename: PathBuf,
|
||||||
|
context: Context,
|
||||||
|
parse_problem: &roc_parse::parser::If<'a>,
|
||||||
|
start_row: Row,
|
||||||
|
start_col: Col,
|
||||||
|
) -> Report<'a> {
|
||||||
|
use roc_parse::parser::If;
|
||||||
|
|
||||||
|
match *parse_problem {
|
||||||
|
If::Syntax(syntax, row, col) => to_syntax_report(alloc, filename, syntax, row, col),
|
||||||
|
If::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
|
||||||
|
|
||||||
|
If::Condition(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfCondition, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::ThenBranch(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfThenBranch, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::ElseBranch(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfElseBranch, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::If(_row, _col) => unreachable!("another branch would be taken"),
|
||||||
|
If::IndentIf(_row, _col) => unreachable!("another branch would be taken"),
|
||||||
|
|
||||||
|
If::Then(row, col) | If::IndentThenBranch(row, col) | If::IndentThenToken(row, col) => {
|
||||||
|
to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see the "),
|
||||||
|
alloc.keyword("then"),
|
||||||
|
alloc.reflow(r" keyword next."),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
If::Else(row, col) | If::IndentElseBranch(row, col) | If::IndentElseToken(row, col) => {
|
||||||
|
to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see the "),
|
||||||
|
alloc.keyword("else"),
|
||||||
|
alloc.reflow(r" keyword next."),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
If::IndentCondition(row, col) => to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see a expression next")
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_unfinished_if_report<'a>(
|
||||||
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
|
filename: PathBuf,
|
||||||
|
row: Row,
|
||||||
|
col: Col,
|
||||||
|
start_row: Row,
|
||||||
|
start_col: Col,
|
||||||
|
message: RocDocBuilder<'a>,
|
||||||
|
) -> Report<'a> {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||||
|
let region = Region::from_row_col(row, col);
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was partway through parsing an "),
|
||||||
|
alloc.keyword("if"),
|
||||||
|
alloc.reflow(r" expression, but I got stuck here:"),
|
||||||
|
]),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
message,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED IF".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_when_report<'a>(
|
fn to_when_report<'a>(
|
||||||
alloc: &'a RocDocAllocator<'a>,
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
@ -792,6 +1025,23 @@ fn to_type_report<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type::TIndentEnd(row, col) => {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||||
|
let region = Region::from_row_col(*row, *col);
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"I am partway through parsing a type, but I got stuck here:"),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.note("I may be confused by indentation"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED TYPE".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type::TAsIndentStart(row, col) => {
|
Type::TAsIndentStart(row, col) => {
|
||||||
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||||
let region = Region::from_row_col(*row, *col);
|
let region = Region::from_row_col(*row, *col);
|
||||||
|
@ -1606,6 +1856,7 @@ fn to_space_report<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum Next<'a> {
|
enum Next<'a> {
|
||||||
Keyword(&'a str),
|
Keyword(&'a str),
|
||||||
// Operator(&'a str),
|
// Operator(&'a str),
|
||||||
|
|
|
@ -801,35 +801,36 @@ mod test_reporting {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn if_3_branch_mismatch() {
|
fn if_3_branch_mismatch() {
|
||||||
// report_problem_as(
|
report_problem_as(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// if True then 2 else if False then 2 else "foo"
|
if True then 2 else if False then 2 else "foo"
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// ── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// The 2nd branch of this `if` does not match all the previous branches:
|
The 3rd branch of this `if` does not match all the previous branches:
|
||||||
|
|
||||||
// 1│ if True then 2 else "foo"
|
1│ if True then 2 else if False then 2 else "foo"
|
||||||
// ^^^^^
|
^^^^^
|
||||||
|
|
||||||
// The 2nd branch is a string of type
|
The 3rd branch is a string of type:
|
||||||
|
|
||||||
// Str
|
Str
|
||||||
|
|
||||||
// But all the previous branches have the type
|
But all the previous branches have type:
|
||||||
|
|
||||||
// Num a
|
Num a
|
||||||
|
|
||||||
// "#
|
I need all branches in an `if` to have the same type!
|
||||||
// ),
|
"#
|
||||||
// )
|
),
|
||||||
// }
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn when_branch_mismatch() {
|
fn when_branch_mismatch() {
|
||||||
|
@ -4635,12 +4636,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I just started parsing a type, but I got stuck here:
|
I am partway through parsing a type, but I got stuck here:
|
||||||
|
|
||||||
1│ f : I64, I64
|
1│ f : I64, I64
|
||||||
^
|
^
|
||||||
|
|
||||||
Note: I may be confused by indentation
|
Note: I may be confused by indentation
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -4949,4 +4950,138 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_outdented_then() {
|
||||||
|
// TODO I think we can do better here
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x =
|
||||||
|
if 5 == 5
|
||||||
|
then 2 else 3
|
||||||
|
|
||||||
|
x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
|
2│ if 5 == 5
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see the `then` keyword next.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_missing_else() {
|
||||||
|
// this should get better with time
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
if 5 == 5 then 2
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
|
1│ if 5 == 5 then 2
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see the `else` keyword next.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_double_comma() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[ 1, 2, , 3 ]
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through started parsing a list, but I got stuck here:
|
||||||
|
|
||||||
|
1│ [ 1, 2, , 3 ]
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see a list entry before this comma, so try adding a
|
||||||
|
list entry and see if that helps?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_without_end() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[ 1, 2,
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through started parsing a list, but I got stuck here:
|
||||||
|
|
||||||
|
1│ [ 1, 2,
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see a closing square bracket before this, so try
|
||||||
|
adding a ] and see if that helps?
|
||||||
|
|
||||||
|
Note: When I get stuck like this, it usually means that there is a
|
||||||
|
missing parenthesis or bracket somewhere earlier. It could also be a
|
||||||
|
stray keyword or operator.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_bad_indent() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x = [ 1, 2,
|
||||||
|
]
|
||||||
|
|
||||||
|
x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I cannot find the end of this list:
|
||||||
|
|
||||||
|
1│ x = [ 1, 2,
|
||||||
|
^
|
||||||
|
|
||||||
|
You could change it to something like [ 1, 2, 3 ] or even just [].
|
||||||
|
Anything where there is an open and a close square bracket, and where
|
||||||
|
the elements of the list are separated by commas.
|
||||||
|
|
||||||
|
Note: I may be confused by indentation
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
|
||||||
let mut rects_arena = Bump::new();
|
let mut rects_arena = Bump::new();
|
||||||
|
let mut ast_arena = Bump::new();
|
||||||
|
|
||||||
// Render loop
|
// Render loop
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
|
@ -255,8 +256,8 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// queue_no_file_text(&size, NOTHING_OPENED, CODE_TXT_XY.into(), &mut glyph_brush);
|
// queue_no_file_text(&size, NOTHING_OPENED, CODE_TXT_XY.into(), &mut glyph_brush);
|
||||||
|
ast_arena.reset();
|
||||||
let mut pool = Pool::with_capacity(12);
|
let mut pool = Pool::with_capacity(1024);
|
||||||
let mut var_store = VarStore::default();
|
let mut var_store = VarStore::default();
|
||||||
let dep_idents = IdentIds::exposed_builtins(8);
|
let dep_idents = IdentIds::exposed_builtins(8);
|
||||||
let mut module_ids = ModuleIds::default();
|
let mut module_ids = ModuleIds::default();
|
||||||
|
@ -280,7 +281,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
let (expr2, _) = crate::lang::expr::str_to_expr2(
|
let (expr2, _) = crate::lang::expr::str_to_expr2(
|
||||||
&arena,
|
&arena,
|
||||||
"{ x: 2, y: 5 }",
|
"{ a: 1, b: 2, c: {x: 3, y: 4} }",
|
||||||
&mut env,
|
&mut env,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
region,
|
region,
|
||||||
|
@ -288,6 +289,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
super::render_ast::render_expr2(
|
super::render_ast::render_expr2(
|
||||||
|
&ast_arena,
|
||||||
&mut env,
|
&mut env,
|
||||||
&expr2,
|
&expr2,
|
||||||
&size,
|
&size,
|
||||||
|
|
|
@ -1,16 +1,156 @@
|
||||||
use crate::editor::colors::CODE_COL;
|
use crate::lang::pool::PoolStr;
|
||||||
|
use bumpalo::collections::String as BumpString;
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use cgmath::Vector2;
|
||||||
|
use wgpu_glyph::GlyphBrush;
|
||||||
|
use winit::dpi::PhysicalSize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
editor::colors::CODE_COL,
|
||||||
graphics::{
|
graphics::{
|
||||||
primitives::text::{queue_code_text_draw, Text},
|
primitives::text::{queue_code_text_draw, Text},
|
||||||
style::CODE_FONT_SIZE,
|
style::CODE_FONT_SIZE,
|
||||||
},
|
},
|
||||||
lang::{ast::Expr2, expr::Env},
|
lang::{ast::Expr2, expr::Env},
|
||||||
};
|
};
|
||||||
use cgmath::Vector2;
|
|
||||||
use wgpu_glyph::GlyphBrush;
|
fn pool_str_len<'a>(env: &Env<'a>, pool_str: &PoolStr) -> usize {
|
||||||
use winit::dpi::PhysicalSize;
|
env.pool.get_str(pool_str).len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the str len, necessary for BumpString
|
||||||
|
fn expr2_to_len<'a>(env: &Env<'a>, expr2: &Expr2) -> usize {
|
||||||
|
match expr2 {
|
||||||
|
Expr2::SmallInt { text, .. } => pool_str_len(env, text),
|
||||||
|
Expr2::I128 { text, .. } => pool_str_len(env, text),
|
||||||
|
Expr2::U128 { text, .. } => pool_str_len(env, text),
|
||||||
|
Expr2::Float { text, .. } => pool_str_len(env, text),
|
||||||
|
Expr2::Str(text) => pool_str_len(env, text),
|
||||||
|
Expr2::GlobalTag { name, .. } => pool_str_len(env, name),
|
||||||
|
Expr2::Call { expr: expr_id, .. } => {
|
||||||
|
let expr = env.pool.get(*expr_id);
|
||||||
|
|
||||||
|
expr2_to_len(env, expr)
|
||||||
|
}
|
||||||
|
Expr2::Var(symbol) => {
|
||||||
|
//TODO make bump_format to use arena
|
||||||
|
let text = format!("{:?}", symbol);
|
||||||
|
|
||||||
|
text.len()
|
||||||
|
}
|
||||||
|
Expr2::List { elems, .. } => {
|
||||||
|
let mut len_ctr = 2; // for '[' and ']'
|
||||||
|
|
||||||
|
for (idx, node_id) in elems.iter_node_ids().enumerate() {
|
||||||
|
let sub_expr2 = env.pool.get(node_id);
|
||||||
|
|
||||||
|
len_ctr += expr2_to_len(env, sub_expr2);
|
||||||
|
|
||||||
|
if idx + 1 < elems.len() {
|
||||||
|
len_ctr += 2; // for ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len_ctr
|
||||||
|
}
|
||||||
|
Expr2::Record { fields, .. } => {
|
||||||
|
let mut len_ctr = 2; // for '{' and '}'
|
||||||
|
|
||||||
|
for (idx, node_id) in fields.iter_node_ids().enumerate() {
|
||||||
|
let (pool_field_name, _, sub_expr2_node_id) = env.pool.get(node_id);
|
||||||
|
|
||||||
|
len_ctr += pool_str_len(env, &pool_field_name);
|
||||||
|
|
||||||
|
let sub_expr2 = env.pool.get(*sub_expr2_node_id);
|
||||||
|
let sub_expr2_len = expr2_to_len(env, sub_expr2);
|
||||||
|
len_ctr += sub_expr2_len;
|
||||||
|
|
||||||
|
if idx + 1 < fields.len() {
|
||||||
|
len_ctr += 2; // for ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len_ctr
|
||||||
|
}
|
||||||
|
rest => todo!("implement expr2_to_str for {:?}", rest),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bump_str<'a, 'b>(arena: &'a Bump, env: &Env<'b>, pool_str: &PoolStr) -> BumpString<'a> {
|
||||||
|
let env_str = env.pool.get_str(pool_str);
|
||||||
|
|
||||||
|
BumpString::from_str_in(env_str, arena)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expr2_to_str<'a, 'b>(arena: &'a Bump, env: &Env<'b>, expr2: &Expr2) -> BumpString<'a> {
|
||||||
|
match expr2 {
|
||||||
|
Expr2::SmallInt { text, .. } => get_bump_str(arena, env, text),
|
||||||
|
Expr2::I128 { text, .. } => get_bump_str(arena, env, text),
|
||||||
|
Expr2::U128 { text, .. } => get_bump_str(arena, env, text),
|
||||||
|
Expr2::Float { text, .. } => get_bump_str(arena, env, text),
|
||||||
|
Expr2::Str(text) => get_bump_str(arena, env, text),
|
||||||
|
Expr2::GlobalTag { name, .. } => get_bump_str(arena, env, name),
|
||||||
|
Expr2::Call { expr: expr_id, .. } => {
|
||||||
|
let expr = env.pool.get(*expr_id);
|
||||||
|
|
||||||
|
expr2_to_str(arena, env, expr)
|
||||||
|
}
|
||||||
|
Expr2::Var(symbol) => {
|
||||||
|
//TODO make bump_format with arena
|
||||||
|
let text = format!("{:?}", symbol);
|
||||||
|
|
||||||
|
BumpString::from_str_in(&text, arena)
|
||||||
|
}
|
||||||
|
Expr2::List { elems, .. } => {
|
||||||
|
let mut bump_str = BumpString::with_capacity_in(expr2_to_len(env, expr2), arena);
|
||||||
|
|
||||||
|
bump_str.push('[');
|
||||||
|
|
||||||
|
for (idx, node_id) in elems.iter_node_ids().enumerate() {
|
||||||
|
let sub_expr2 = env.pool.get(node_id);
|
||||||
|
|
||||||
|
bump_str.push_str(&expr2_to_str(arena, env, sub_expr2));
|
||||||
|
|
||||||
|
if idx + 1 < elems.len() {
|
||||||
|
bump_str.push_str(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bump_str.push(']');
|
||||||
|
|
||||||
|
bump_str
|
||||||
|
}
|
||||||
|
Expr2::Record { fields, .. } => {
|
||||||
|
let mut bump_str = BumpString::with_capacity_in(expr2_to_len(env, expr2), arena);
|
||||||
|
|
||||||
|
bump_str.push('{');
|
||||||
|
|
||||||
|
for (idx, node_id) in fields.iter_node_ids().enumerate() {
|
||||||
|
let (pool_field_name, _, sub_expr2_node_id) = env.pool.get(node_id);
|
||||||
|
|
||||||
|
let field_name = env.pool.get_str(pool_field_name);
|
||||||
|
|
||||||
|
let sub_expr2 = env.pool.get(*sub_expr2_node_id);
|
||||||
|
|
||||||
|
bump_str.push_str(field_name);
|
||||||
|
bump_str.push(':');
|
||||||
|
bump_str.push_str(&expr2_to_str(arena, env, sub_expr2));
|
||||||
|
|
||||||
|
if idx + 1 < fields.len() {
|
||||||
|
bump_str.push_str(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bump_str.push('}');
|
||||||
|
|
||||||
|
bump_str
|
||||||
|
}
|
||||||
|
rest => todo!("implement expr2_to_str for {:?}", rest),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_expr2<'a>(
|
pub fn render_expr2<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
expr2: &Expr2,
|
expr2: &Expr2,
|
||||||
size: &PhysicalSize<u32>,
|
size: &PhysicalSize<u32>,
|
||||||
|
@ -19,240 +159,18 @@ pub fn render_expr2<'a>(
|
||||||
) {
|
) {
|
||||||
let area_bounds = (size.width as f32, size.height as f32).into();
|
let area_bounds = (size.width as f32, size.height as f32).into();
|
||||||
|
|
||||||
match expr2 {
|
let expr_str = expr2_to_str(arena, env, expr2);
|
||||||
Expr2::SmallInt { text, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: env.pool.get_str(text),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
// TODO format expr_str
|
||||||
}
|
|
||||||
Expr2::I128 { text, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: env.pool.get_str(text),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
let code_text = Text {
|
||||||
}
|
position,
|
||||||
Expr2::U128 { text, .. } => {
|
area_bounds,
|
||||||
let code_text = Text {
|
color: CODE_COL.into(),
|
||||||
position,
|
text: &expr_str,
|
||||||
area_bounds,
|
size: CODE_FONT_SIZE,
|
||||||
color: CODE_COL.into(),
|
..Default::default()
|
||||||
text: env.pool.get_str(text),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::Float { text, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: env.pool.get_str(text),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::Str(text) => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: env.pool.get_str(text),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::GlobalTag { name, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: env.pool.get_str(name),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::Call { expr: expr_id, .. } => {
|
|
||||||
let expr = env.pool.get(*expr_id);
|
|
||||||
|
|
||||||
render_expr2(env, expr, size, position, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::Var(symbol) => {
|
|
||||||
let text = format!("{:?}", symbol);
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: text.as_str(),
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::List { elems, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: "[",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
|
|
||||||
let mut x_pos = position.x;
|
|
||||||
|
|
||||||
for (idx, node_id) in elems.iter_node_ids().enumerate() {
|
|
||||||
let sub_expr2 = env.pool.get(node_id);
|
|
||||||
|
|
||||||
x_pos += 20.0;
|
|
||||||
|
|
||||||
render_expr2(
|
|
||||||
env,
|
|
||||||
sub_expr2,
|
|
||||||
size,
|
|
||||||
Vector2::new(x_pos, position.y),
|
|
||||||
glyph_brush,
|
|
||||||
);
|
|
||||||
|
|
||||||
if idx + 1 < elems.len() {
|
|
||||||
x_pos += 10.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: ",",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x_pos += 20.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: "]",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
Expr2::Record { fields, .. } => {
|
|
||||||
let code_text = Text {
|
|
||||||
position,
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: "{",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
|
|
||||||
let mut x_pos = position.x;
|
|
||||||
|
|
||||||
for (idx, node_id) in fields.iter_node_ids().enumerate() {
|
|
||||||
let (pool_field_name, _, sub_expr2_node_id) = env.pool.get(node_id);
|
|
||||||
|
|
||||||
let field_name = env.pool.get_str(pool_field_name);
|
|
||||||
|
|
||||||
x_pos += 20.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: field_name,
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
|
|
||||||
x_pos += 10.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: ":",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
|
|
||||||
let sub_expr2 = env.pool.get(*sub_expr2_node_id);
|
|
||||||
|
|
||||||
x_pos += 20.0;
|
|
||||||
|
|
||||||
render_expr2(
|
|
||||||
env,
|
|
||||||
sub_expr2,
|
|
||||||
size,
|
|
||||||
Vector2::new(x_pos, position.y),
|
|
||||||
glyph_brush,
|
|
||||||
);
|
|
||||||
|
|
||||||
if idx + 1 < fields.len() {
|
|
||||||
x_pos += 10.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: ",",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x_pos += 20.0;
|
|
||||||
|
|
||||||
let code_text = Text {
|
|
||||||
position: Vector2::new(x_pos, position.y),
|
|
||||||
area_bounds,
|
|
||||||
color: CODE_COL.into(),
|
|
||||||
text: "}",
|
|
||||||
size: CODE_FONT_SIZE,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
queue_code_text_draw(&code_text, glyph_brush);
|
|
||||||
}
|
|
||||||
rest => todo!("implement {:?} render", rest),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
queue_code_text_draw(&code_text, glyph_brush);
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,22 +508,31 @@ pub fn to_expr2<'a>(
|
||||||
Output::default(),
|
Output::default(),
|
||||||
),
|
),
|
||||||
|
|
||||||
If(cond, then_branch, else_branch) => {
|
If(branches, final_else) => {
|
||||||
let (cond, mut output) = to_expr2(env, scope, &cond.value, cond.region);
|
let mut new_branches = Vec::with_capacity(branches.len());
|
||||||
|
let mut output = Output::default();
|
||||||
|
|
||||||
let (then_expr, then_output) =
|
for (condition, then_branch) in branches.iter() {
|
||||||
to_expr2(env, scope, &then_branch.value, then_branch.region);
|
let (cond, cond_output) = to_expr2(env, scope, &condition.value, condition.region);
|
||||||
|
|
||||||
|
let (then_expr, then_output) =
|
||||||
|
to_expr2(env, scope, &then_branch.value, then_branch.region);
|
||||||
|
|
||||||
|
output.references.union_mut(cond_output.references);
|
||||||
|
output.references.union_mut(then_output.references);
|
||||||
|
|
||||||
|
new_branches.push((cond, then_expr));
|
||||||
|
}
|
||||||
|
|
||||||
let (else_expr, else_output) =
|
let (else_expr, else_output) =
|
||||||
to_expr2(env, scope, &else_branch.value, else_branch.region);
|
to_expr2(env, scope, &final_else.value, final_else.region);
|
||||||
|
|
||||||
output.references.union_mut(then_output.references);
|
|
||||||
output.references.union_mut(else_output.references);
|
output.references.union_mut(else_output.references);
|
||||||
|
|
||||||
let expr = Expr2::If {
|
let expr = Expr2::If {
|
||||||
cond_var: env.var_store.fresh(),
|
cond_var: env.var_store.fresh(),
|
||||||
expr_var: env.var_store.fresh(),
|
expr_var: env.var_store.fresh(),
|
||||||
branches: PoolVec::new(vec![(cond, then_expr)].into_iter(), env.pool),
|
branches: PoolVec::new(new_branches.into_iter(), env.pool),
|
||||||
final_else: env.pool.add(else_expr),
|
final_else: env.pool.add(else_expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue