roc/crates/compiler/can/tests/helpers/mod.rs
Agus Zubiaga 002493e32c
Load and can ingested file imports
Moves handling of ingested file imports from load to can, so that they
can be properly introduced in the scope they appear.

Example:

  import "input.txt" as input : Str

  image =
      import "image.png" as bytes : List U8
      # `bytes` is only available under `image`
      decodePng bytes

  ...
2024-01-20 08:43:40 -03:00

119 lines
3.2 KiB
Rust

extern crate bumpalo;
use self::bumpalo::Bump;
use roc_can::env::Env;
use roc_can::expr::Output;
use roc_can::expr::{canonicalize_expr, Expr};
use roc_can::operator;
use roc_can::scope::Scope;
use roc_collections::all::MutMap;
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
use roc_problem::can::Problem;
use roc_region::all::{Loc, Region};
use roc_types::subs::{VarStore, Variable};
use roc_types::types::{AliasVar, Type};
use std::hash::Hash;
pub fn test_home() -> ModuleId {
ModuleIds::default().get_or_insert(&"Test".into())
}
#[allow(dead_code)]
pub fn can_expr(expr_str: &str) -> CanExprOut {
can_expr_with(&Bump::new(), test_home(), expr_str)
}
pub struct CanExprOut {
pub loc_expr: Loc<Expr>,
pub output: Output,
pub problems: Vec<Problem>,
pub home: ModuleId,
pub interns: Interns,
pub var_store: VarStore,
pub var: Variable,
}
#[allow(dead_code)]
pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut {
let loc_expr = roc_parse::test_helpers::parse_loc_with(arena, expr_str).unwrap_or_else(|e| {
panic!(
"can_expr_with() got a parse error when attempting to canonicalize:\n\n{expr_str:?} {e:?}"
)
});
let mut var_store = VarStore::default();
let var = var_store.fresh();
let module_ids = ModuleIds::default();
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
//
// If we did this *during* canonicalization, then each time we
// visited a BinOp node we'd recursively try to apply this to each of its nested
// operators, and then again on *their* nested operators, ultimately applying the
// rules multiple times unnecessarily.
let loc_expr = operator::desugar_expr(
arena,
&loc_expr,
expr_str,
&mut None,
arena.alloc("TestPath"),
);
let mut scope = Scope::new(home, IdentIds::default(), Default::default());
scope.add_alias(
Symbol::NUM_INT,
Region::zero(),
vec![Loc::at_zero(AliasVar::unbound(
"a".into(),
Variable::EMPTY_RECORD,
))],
vec![],
Type::EmptyRec,
roc_types::types::AliasKind::Structural,
);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(arena, home, &dep_idents, &module_ids);
let (loc_expr, output) = canonicalize_expr(
&mut env,
&mut var_store,
&mut scope,
Region::zero(),
&loc_expr.value,
"Test.roc",
);
let mut all_ident_ids = IdentIds::exposed_builtins(1);
all_ident_ids.insert(home, scope.locals.ident_ids);
let interns = Interns {
module_ids: env.module_ids.clone(),
all_ident_ids,
};
CanExprOut {
loc_expr,
output,
problems: env.problems,
home: env.home,
var_store,
interns,
var,
}
}
#[allow(dead_code)]
pub fn mut_map_from_pairs<K, V, I>(pairs: I) -> MutMap<K, V>
where
I: IntoIterator<Item = (K, V)>,
K: Hash + Eq,
{
let mut answer = MutMap::default();
for (key, value) in pairs {
answer.insert(key, value);
}
answer
}