mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
merge upstream/main
This commit is contained in:
commit
cec67721e6
59 changed files with 2542 additions and 990 deletions
|
@ -13,7 +13,7 @@ use roc_mono::layout::{
|
|||
self, union_sorted_tags_pub, Builtin, Layout, LayoutCache, LayoutInterner, UnionLayout,
|
||||
UnionVariant, WrappedVariant,
|
||||
};
|
||||
use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral};
|
||||
use roc_parse::ast::{AssignedField, Collection, Expr, Pattern, StrLiteral};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_std::RocDec;
|
||||
use roc_target::TargetInfo;
|
||||
|
@ -29,11 +29,6 @@ struct Env<'a, 'env> {
|
|||
layout_cache: LayoutCache<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ToAstProblem {
|
||||
FunctionLayout,
|
||||
}
|
||||
|
||||
/// JIT execute the given main function, and then wrap its results in an Expr
|
||||
/// so we can display them to the user using the formatter.
|
||||
///
|
||||
|
@ -53,7 +48,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
|||
interns: &'a Interns,
|
||||
layout_interner: LayoutInterner<'a>,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
) -> Expr<'a> {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
|
@ -68,10 +63,24 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
|||
result,
|
||||
captures_niche: _,
|
||||
} => {
|
||||
// this is a thunk
|
||||
// This is a thunk, which cannot be defined in userspace, so we know
|
||||
// it's `main` and can be executed.
|
||||
jit_to_ast_help(&mut env, app, main_fn_name, &result, var)
|
||||
}
|
||||
_ => Err(ToAstProblem::FunctionLayout),
|
||||
ProcLayout { arguments, .. } => {
|
||||
// This is a user-supplied function; create a fake Expr for it.
|
||||
let mut arg_patterns =
|
||||
bumpalo::collections::Vec::with_capacity_in(arguments.len(), arena);
|
||||
|
||||
// Put in an underscore for each of the args, just to get the arity right.
|
||||
for _ in 0..arguments.len() {
|
||||
arg_patterns.push(Loc::at_zero(Pattern::Underscore("_")));
|
||||
}
|
||||
|
||||
let body_expr = Loc::at_zero(Expr::Record(Collection::empty()));
|
||||
|
||||
Expr::Closure(arg_patterns.into_bump_slice(), arena.alloc(body_expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,7 +340,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
main_fn_name: &str,
|
||||
layout: &Layout<'a>,
|
||||
var: Variable,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
) -> Expr<'a> {
|
||||
let (newtype_containers, alias_content, raw_var) = unroll_newtypes_and_aliases(env, var);
|
||||
|
||||
macro_rules! num_helper {
|
||||
|
@ -342,18 +351,17 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
};
|
||||
}
|
||||
|
||||
let result = match layout {
|
||||
Layout::Builtin(Builtin::Bool) => Ok(app.call_function(
|
||||
main_fn_name,
|
||||
|_mem: &A::Memory, num: bool| {
|
||||
let expr = match layout {
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
app.call_function(main_fn_name, |_mem: &A::Memory, num: bool| {
|
||||
bool_to_ast(env, num, env.subs.get_content_without_compacting(raw_var))
|
||||
},
|
||||
)),
|
||||
})
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||
use Content::*;
|
||||
use IntWidth::*;
|
||||
|
||||
let result = match (alias_content, int_width) {
|
||||
match (alias_content, int_width) {
|
||||
(Some(Alias(Symbol::NUM_UNSIGNED8, ..)), U8) => num_helper!(u8),
|
||||
(_, U8) => {
|
||||
// This is not a number, it's a tag union or something else
|
||||
|
@ -371,22 +379,18 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
(_, I32) => num_helper!(i32),
|
||||
(_, I64) => num_helper!(i64),
|
||||
(_, I128) => num_helper!(i128),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
let result = match float_width {
|
||||
match float_width {
|
||||
F32 => num_helper!(f32),
|
||||
F64 => num_helper!(f64),
|
||||
F128 => todo!("F128 not implemented"),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Layout::Builtin(Builtin::Decimal) => Ok(num_helper!(RocDec)),
|
||||
Layout::Builtin(Builtin::Decimal) => num_helper!(RocDec),
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
let body = |mem: &A::Memory, addr| {
|
||||
let string = mem.deref_str(addr);
|
||||
|
@ -394,24 +398,21 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
Expr::Str(StrLiteral::PlainLine(arena_str))
|
||||
};
|
||||
|
||||
Ok(app.call_function_returns_roc_str(env.target_info, main_fn_name, body))
|
||||
}
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
//
|
||||
Ok(app.call_function_returns_roc_list(
|
||||
main_fn_name,
|
||||
|mem: &A::Memory, (addr, len, _cap)| {
|
||||
list_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
len,
|
||||
elem_layout,
|
||||
env.subs.get_content_without_compacting(raw_var),
|
||||
)
|
||||
},
|
||||
))
|
||||
app.call_function_returns_roc_str(env.target_info, main_fn_name, body)
|
||||
}
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => app.call_function_returns_roc_list(
|
||||
main_fn_name,
|
||||
|mem: &A::Memory, (addr, len, _cap)| {
|
||||
list_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
len,
|
||||
elem_layout,
|
||||
env.subs.get_content_without_compacting(raw_var),
|
||||
)
|
||||
},
|
||||
),
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
let fields = [Layout::u64(), *layout];
|
||||
let layout = Layout::struct_no_name_order(env.arena.alloc(fields));
|
||||
|
@ -423,38 +424,24 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
.get_content_without_compacting(raw_var)
|
||||
{
|
||||
Content::Structure(FlatType::Record(fields, _)) => {
|
||||
Ok(struct_to_ast(env, mem, addr, *fields))
|
||||
struct_to_ast(env, mem, addr, *fields)
|
||||
}
|
||||
Content::Structure(FlatType::EmptyRecord) => {
|
||||
Ok(struct_to_ast(env, mem, addr, RecordFields::empty()))
|
||||
struct_to_ast(env, mem, addr, RecordFields::empty())
|
||||
}
|
||||
Content::Structure(FlatType::TagUnion(tags, _)) => {
|
||||
let (tag_name, payload_vars) = unpack_single_element_tag_union(env.subs, *tags);
|
||||
|
||||
Ok(single_tag_union_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
field_layouts,
|
||||
tag_name,
|
||||
payload_vars,
|
||||
))
|
||||
single_tag_union_to_ast(env, mem, addr, field_layouts, tag_name, payload_vars)
|
||||
}
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, _, _)) => {
|
||||
let tag_name = &env.subs.get_subs_slice(*tag_names)[0];
|
||||
|
||||
Ok(single_tag_union_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
field_layouts,
|
||||
tag_name,
|
||||
&[],
|
||||
))
|
||||
single_tag_union_to_ast(env, mem, addr, field_layouts, tag_name, &[])
|
||||
}
|
||||
Content::Structure(FlatType::Func(_, _, _)) => {
|
||||
// a function with a struct as the closure environment
|
||||
Ok(OPAQUE_FUNCTION)
|
||||
OPAQUE_FUNCTION
|
||||
}
|
||||
other => {
|
||||
unreachable!(
|
||||
|
@ -472,7 +459,8 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
}
|
||||
Layout::Union(UnionLayout::NonRecursive(_)) => {
|
||||
let size = layout.stack_size(&env.layout_cache.interner, env.target_info);
|
||||
Ok(app.call_function_dynamic_size(
|
||||
|
||||
app.call_function_dynamic_size(
|
||||
main_fn_name,
|
||||
size as usize,
|
||||
|mem: &'a A::Memory, addr: usize| {
|
||||
|
@ -485,14 +473,15 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
env.subs.get_root_key_without_compacting(raw_var),
|
||||
)
|
||||
},
|
||||
))
|
||||
)
|
||||
}
|
||||
Layout::Union(UnionLayout::Recursive(_))
|
||||
| Layout::Union(UnionLayout::NonNullableUnwrapped(_))
|
||||
| Layout::Union(UnionLayout::NullableUnwrapped { .. })
|
||||
| Layout::Union(UnionLayout::NullableWrapped { .. }) => {
|
||||
let size = layout.stack_size(&env.layout_cache.interner, env.target_info);
|
||||
Ok(app.call_function_dynamic_size(
|
||||
|
||||
app.call_function_dynamic_size(
|
||||
main_fn_name,
|
||||
size as usize,
|
||||
|mem: &'a A::Memory, addr: usize| {
|
||||
|
@ -505,31 +494,29 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
env.subs.get_root_key_without_compacting(raw_var),
|
||||
)
|
||||
},
|
||||
))
|
||||
)
|
||||
}
|
||||
Layout::RecursivePointer => {
|
||||
unreachable!("RecursivePointers can only be inside structures")
|
||||
}
|
||||
Layout::LambdaSet(_) => Ok(OPAQUE_FUNCTION),
|
||||
Layout::LambdaSet(_) => OPAQUE_FUNCTION,
|
||||
Layout::Boxed(_) => {
|
||||
let size = layout.stack_size(&env.layout_cache.interner, env.target_info);
|
||||
Ok(app.call_function_dynamic_size(
|
||||
main_fn_name,
|
||||
size as usize,
|
||||
|mem: &A::Memory, addr| {
|
||||
addr_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
layout,
|
||||
WhenRecursive::Unreachable,
|
||||
env.subs.get_root_key_without_compacting(raw_var),
|
||||
)
|
||||
},
|
||||
))
|
||||
|
||||
app.call_function_dynamic_size(main_fn_name, size as usize, |mem: &A::Memory, addr| {
|
||||
addr_to_ast(
|
||||
env,
|
||||
mem,
|
||||
addr,
|
||||
layout,
|
||||
WhenRecursive::Unreachable,
|
||||
env.subs.get_root_key_without_compacting(raw_var),
|
||||
)
|
||||
})
|
||||
}
|
||||
};
|
||||
result.map(|e| apply_newtypes(env, newtype_containers.into_bump_slice(), e))
|
||||
|
||||
apply_newtypes(env, newtype_containers.into_bump_slice(), expr)
|
||||
}
|
||||
|
||||
fn tag_name_to_expr<'a>(env: &Env<'a, '_>, tag_name: &TagName) -> Expr<'a> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_load::{ExecutionMode, LoadConfig, Threading};
|
||||
use roc_reporting::report::Palette;
|
||||
use roc_reporting::report::{Palette, Severity};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use roc_fmt::annotation::Formattable;
|
||||
|
@ -11,48 +11,47 @@ use roc_region::all::LineInfo;
|
|||
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use crate::eval::ToAstProblem;
|
||||
|
||||
pub enum ReplOutput {
|
||||
Problems(Vec<String>),
|
||||
NoProblems { expr: String, expr_type: String },
|
||||
#[derive(Debug)]
|
||||
pub struct ReplOutput {
|
||||
pub expr: String,
|
||||
pub expr_type: String,
|
||||
}
|
||||
|
||||
pub fn format_answer(
|
||||
arena: &Bump,
|
||||
res_answer: Result<Expr, ToAstProblem>,
|
||||
expr_type_str: String,
|
||||
) -> ReplOutput {
|
||||
let mut expr = roc_fmt::Buf::new_in(arena);
|
||||
pub fn format_answer<'a>(arena: &'a Bump, answer: Expr<'_>) -> &'a str {
|
||||
match answer {
|
||||
Expr::Closure(_, _) | Expr::MalformedClosure => "<function>",
|
||||
_ => {
|
||||
let mut expr = roc_fmt::Buf::new_in(arena);
|
||||
|
||||
use ToAstProblem::*;
|
||||
match res_answer {
|
||||
Ok(answer) => {
|
||||
answer.format_with_options(&mut expr, Parens::NotNeeded, Newlines::Yes, 0);
|
||||
}
|
||||
Err(FunctionLayout) => {
|
||||
expr.indent(0);
|
||||
expr.push_str("<function>");
|
||||
}
|
||||
}
|
||||
|
||||
ReplOutput::NoProblems {
|
||||
expr: expr.into_bump_str().to_string(),
|
||||
expr_type: expr_type_str,
|
||||
expr.into_bump_str()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_to_mono<'a>(
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Problems {
|
||||
pub errors: Vec<String>,
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
impl Problems {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.errors.is_empty() && self.warnings.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_to_mono<'a, 'i, I: Iterator<Item = &'i str>>(
|
||||
arena: &'a Bump,
|
||||
src: &str,
|
||||
defs: I,
|
||||
expr: &str,
|
||||
target_info: TargetInfo,
|
||||
palette: Palette,
|
||||
) -> Result<MonomorphizedModule<'a>, Vec<String>> {
|
||||
) -> (Option<MonomorphizedModule<'a>>, Problems) {
|
||||
let filename = PathBuf::from("");
|
||||
let src_dir = PathBuf::from("fake/test/path");
|
||||
|
||||
let module_src = arena.alloc(promote_expr_to_module(src));
|
||||
|
||||
let (bytes_before_expr, module_src) = promote_expr_to_module(arena, defs, expr);
|
||||
let exposed_types = Default::default();
|
||||
let loaded = roc_load::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
|
@ -71,10 +70,16 @@ pub fn compile_to_mono<'a>(
|
|||
let mut loaded = match loaded {
|
||||
Ok(v) => v,
|
||||
Err(LoadingProblem::FormattedReport(report)) => {
|
||||
return Err(vec![report]);
|
||||
return (
|
||||
None,
|
||||
Problems {
|
||||
errors: vec![report],
|
||||
warnings: Vec::new(),
|
||||
},
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("error while loading module: {:?}", e)
|
||||
todo!("error while loading module: {:?}", e)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -86,7 +91,10 @@ pub fn compile_to_mono<'a>(
|
|||
..
|
||||
} = &mut loaded;
|
||||
|
||||
let mut lines = Vec::new();
|
||||
let mut problems = Problems::default();
|
||||
|
||||
let errors = &mut problems.errors;
|
||||
let warnings = &mut problems.warnings;
|
||||
|
||||
for (home, (module_path, src)) in sources.iter() {
|
||||
let can_probs = can_problems.remove(home).unwrap_or_default();
|
||||
|
@ -105,42 +113,77 @@ pub fn compile_to_mono<'a>(
|
|||
let alloc = RocDocAllocator::new(&src_lines, *home, interns);
|
||||
|
||||
for problem in can_probs.into_iter() {
|
||||
let report = can_problem(&alloc, &line_info, module_path.clone(), problem);
|
||||
let mut buf = String::new();
|
||||
|
||||
report.render_color_terminal(&mut buf, &alloc, &palette);
|
||||
|
||||
lines.push(buf);
|
||||
}
|
||||
|
||||
for problem in type_probs {
|
||||
if let Some(report) = type_problem(&alloc, &line_info, module_path.clone(), problem) {
|
||||
// Filter out all warnings and errors whose regions end before this,
|
||||
// because they must be part of the defs (excluding the most renently added def,
|
||||
// if that's the one being evaluated) and therefore not things we should show.
|
||||
// This filters out things like shadowing warnings and unused def warnings.
|
||||
if problem.region().unwrap_or_default().end().offset as usize >= bytes_before_expr {
|
||||
let report = can_problem(&alloc, &line_info, module_path.clone(), problem);
|
||||
let severity = report.severity;
|
||||
let mut buf = String::new();
|
||||
|
||||
report.render_color_terminal(&mut buf, &alloc, &palette);
|
||||
|
||||
lines.push(buf);
|
||||
match severity {
|
||||
Severity::Warning => {
|
||||
warnings.push(buf);
|
||||
}
|
||||
Severity::RuntimeError => {
|
||||
errors.push(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for problem in type_probs {
|
||||
if let Some(report) = type_problem(&alloc, &line_info, module_path.clone(), problem) {
|
||||
let severity = report.severity;
|
||||
let mut buf = String::new();
|
||||
|
||||
report.render_color_terminal(&mut buf, &alloc, &palette);
|
||||
|
||||
match severity {
|
||||
Severity::Warning => {
|
||||
warnings.push(buf);
|
||||
}
|
||||
Severity::RuntimeError => {
|
||||
errors.push(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !lines.is_empty() {
|
||||
Err(lines)
|
||||
} else {
|
||||
Ok(loaded)
|
||||
}
|
||||
(Some(loaded), problems)
|
||||
}
|
||||
|
||||
fn promote_expr_to_module(src: &str) -> String {
|
||||
let mut buffer =
|
||||
String::from("app \"app\" provides [replOutput] to \"./platform\"\n\nreplOutput =\n");
|
||||
fn promote_expr_to_module<'a, 'i, I: Iterator<Item = &'i str>>(
|
||||
arena: &'a Bump,
|
||||
defs: I,
|
||||
expr: &str,
|
||||
) -> (usize, &'a str) {
|
||||
const REPL_MODULE_HEADER: &str = "app \"app\" provides [replOutput] to \"./platform\"\n\n";
|
||||
const REPL_MODULE_MAIN_DEF: &str = "replOutput =\n";
|
||||
const INDENT: &str = " ";
|
||||
|
||||
for line in src.lines() {
|
||||
// indent the body!
|
||||
buffer.push_str(" ");
|
||||
let mut buffer = bumpalo::collections::string::String::from_str_in(REPL_MODULE_HEADER, arena);
|
||||
|
||||
for line in defs {
|
||||
// don't indent the defs
|
||||
buffer.push_str(line);
|
||||
buffer.push_str("\n\n");
|
||||
}
|
||||
|
||||
buffer.push_str(REPL_MODULE_MAIN_DEF);
|
||||
|
||||
let bytes_before_expr = buffer.len();
|
||||
|
||||
for line in expr.lines() {
|
||||
// indent the expr!
|
||||
buffer.push_str(INDENT);
|
||||
buffer.push_str(line);
|
||||
buffer.push('\n');
|
||||
}
|
||||
|
||||
buffer
|
||||
(bytes_before_expr, buffer.into_bump_str())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue