mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Use helpers in can builtins
This commit is contained in:
parent
d0da4bf926
commit
a399614824
1 changed files with 104 additions and 121 deletions
|
@ -1,11 +1,12 @@
|
|||
use crate::def::Def;
|
||||
use crate::expr::Expr;
|
||||
use crate::expr::Recursive;
|
||||
use roc_collections::all::SendMap;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_parse::operator::CalledVia;
|
||||
use roc_region::all::{Located, Region};
|
||||
use roc_types::subs::VarStore;
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
|
||||
/// Some builtins cannot be constructed in code gen alone, and need to be defined
|
||||
/// as separate Roc defs. For example, List.get has this type:
|
||||
|
@ -44,77 +45,63 @@ fn list_get(var_store: &VarStore) -> Def {
|
|||
),
|
||||
];
|
||||
|
||||
// Perform a bounds check. If it passes, delegate to List.getUnsafe
|
||||
// Perform a bounds check. If it passes, delegate to List.#getUnsafe
|
||||
let body = If {
|
||||
cond_var: var_store.fresh(),
|
||||
branch_var: var_store.fresh(),
|
||||
branches: vec![(
|
||||
// if-condition
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Call(
|
||||
Box::new((
|
||||
var_store.fresh(),
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Var(Symbol::LIST_IS_EMPTY), // TODO actually check if (index < List.len list)
|
||||
},
|
||||
var_store.fresh(),
|
||||
)),
|
||||
vec![(
|
||||
var_store.fresh(),
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Var(Symbol::LIST_GET_ARG_LIST),
|
||||
},
|
||||
)],
|
||||
CalledVia::Space,
|
||||
),
|
||||
},
|
||||
// then-branch
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value:
|
||||
// Ok
|
||||
Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(), // TODO Variable::EMPTY_TAG_UNION should work here
|
||||
name: TagName::Global("Ok".into()),
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
no_region(
|
||||
// index < List.len list
|
||||
call(
|
||||
Symbol::NUM_LT,
|
||||
vec![
|
||||
Var(Symbol::LIST_GET_ARG_INDEX),
|
||||
call(
|
||||
Symbol::LIST_LEN,
|
||||
vec![Var(Symbol::LIST_GET_ARG_LIST)],
|
||||
var_store,
|
||||
),
|
||||
],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
// then-branch
|
||||
no_region(
|
||||
// Ok
|
||||
tag(
|
||||
"Ok",
|
||||
vec![
|
||||
// List.getUnsafe list index
|
||||
Call(
|
||||
Box::new((var_store.fresh(), no_region(Var(Symbol::LIST_GET_UNSAFE)), var_store.fresh())),
|
||||
Box::new((
|
||||
var_store.fresh(),
|
||||
no_region(Var(Symbol::LIST_GET_UNSAFE)),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
vec![
|
||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_LIST))),
|
||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_INDEX))),
|
||||
(
|
||||
var_store.fresh(),
|
||||
no_region(Var(Symbol::LIST_GET_ARG_INDEX)),
|
||||
),
|
||||
],
|
||||
CalledVia::Space,
|
||||
)
|
||||
)
|
||||
)]
|
||||
},
|
||||
},
|
||||
),
|
||||
],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// else-branch
|
||||
no_region(
|
||||
// Err
|
||||
Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
name: TagName::Global("Err".into()),
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
no_region(Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
name: TagName::Global("OutOfBounds".into()),
|
||||
arguments: std::vec::Vec::new(),
|
||||
}),
|
||||
)],
|
||||
},
|
||||
tag(
|
||||
"Err",
|
||||
vec![tag("OutOfBounds", Vec::new(), var_store)],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
@ -147,79 +134,47 @@ fn list_first(var_store: &VarStore) -> Def {
|
|||
)];
|
||||
|
||||
// Perform a bounds check. If it passes, delegate to List.getUnsafe.
|
||||
let body =
|
||||
// Use "when" instead of "if" so that we can have False be the first branch.
|
||||
let body = If {
|
||||
// TODO Use "when" instead of "if" so that we can have False be the first branch.
|
||||
// We want that for branch prediction; usually we expect the list to be nonempty.
|
||||
If {
|
||||
cond_var: var_store.fresh(),
|
||||
branch_var: var_store.fresh(),
|
||||
branches: vec![(
|
||||
// if-condition
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Call(
|
||||
Box::new((
|
||||
var_store.fresh(),
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Var(Symbol::LIST_IS_EMPTY),
|
||||
},
|
||||
var_store.fresh(),
|
||||
)),
|
||||
vec![(
|
||||
var_store.fresh(),
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value: Var(Symbol::LIST_GET_ARG_LIST),
|
||||
},
|
||||
)],
|
||||
CalledVia::Space,
|
||||
),
|
||||
},
|
||||
// then-branch
|
||||
Located {
|
||||
region: Region::zero(),
|
||||
value:
|
||||
// Ok
|
||||
Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
name: TagName::Global("Ok".into()),
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
no_region(
|
||||
// List.getUnsafe list index
|
||||
Call(
|
||||
Box::new((var_store.fresh(), no_region(Var(Symbol::LIST_GET_UNSAFE)), var_store.fresh())),
|
||||
vec![
|
||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_LIST))),
|
||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_INDEX))),
|
||||
],
|
||||
CalledVia::Space,
|
||||
)
|
||||
)
|
||||
)]
|
||||
},
|
||||
},
|
||||
// List.isEmpty list
|
||||
call(
|
||||
Symbol::LIST_IS_EMPTY,
|
||||
vec![Var(Symbol::LIST_FIRST_ARG)],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
// then-branch
|
||||
no_region(
|
||||
// Err OutOfBounds
|
||||
tag(
|
||||
"Err",
|
||||
vec![tag("OutOfBounds", Vec::new(), var_store)],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// default branch
|
||||
no_region(
|
||||
// Err
|
||||
Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
name: TagName::Global("Err".into()),
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
no_region(Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
name: TagName::Global("OutOfBounds".into()),
|
||||
arguments: std::vec::Vec::new(),
|
||||
}),
|
||||
)],
|
||||
},
|
||||
// Ok (List.#getUnsafe list 0)
|
||||
tag(
|
||||
"Ok",
|
||||
vec![
|
||||
// List.#getUnsafe list 0
|
||||
call(
|
||||
Symbol::LIST_GET_UNSAFE,
|
||||
vec![(Var(Symbol::LIST_FIRST_ARG)), (Int(var_store.fresh(), 0))],
|
||||
var_store,
|
||||
),
|
||||
],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
@ -248,3 +203,31 @@ fn no_region<T>(value: T) -> Located<T> {
|
|||
value,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag(name: &'static str, args: Vec<Expr>, var_store: &VarStore) -> Expr {
|
||||
Expr::Tag {
|
||||
variant_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(), // TODO Variable::EMPTY_TAG_UNION should work here
|
||||
name: TagName::Global(name.into()),
|
||||
arguments: args
|
||||
.into_iter()
|
||||
.map(|expr| (var_store.fresh(), no_region(expr)))
|
||||
.collect::<Vec<(Variable, Located<Expr>)>>(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn call(symbol: Symbol, args: Vec<Expr>, var_store: &VarStore) -> Expr {
|
||||
Expr::Call(
|
||||
Box::new((
|
||||
var_store.fresh(),
|
||||
no_region(Expr::Var(symbol)),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
args.into_iter()
|
||||
.map(|expr| (var_store.fresh(), no_region(expr)))
|
||||
.collect::<Vec<(Variable, Located<Expr>)>>(),
|
||||
CalledVia::Space,
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue