1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use arret_syntax::span::Span;
use arret_runtime::boxed;
use crate::mir::builder::Builder;
use crate::mir::error::Result;
use crate::mir::eval_hir::EvalHirCtx;
use crate::mir::value::list::{list_value_len, ListValueLen};
use crate::mir::Value;
pub fn length(
ehx: &mut EvalHirCtx,
b: &mut Option<Builder>,
span: Span,
arg_list_value: &Value,
) -> Result<Option<Value>> {
let mut iter = arg_list_value.unsized_list_iter();
let single_arg = iter.next_unchecked(b, span);
let list_len = list_value_len(&single_arg);
if let ListValueLen::Exact(known_len) = list_len {
return Ok(Some(boxed::Int::new(ehx, known_len as i64).into()));
}
if let Some(b) = b {
use crate::mir::ops::*;
use crate::mir::value;
use crate::mir::value::build_reg::value_to_reg;
use arret_runtime::abitype;
let list_reg = value_to_reg(
ehx,
b,
span,
&single_arg,
&abitype::TOP_LIST_BOXED_ABI_TYPE.into(),
);
let list_len_reg = b.push_reg(
span,
OpKind::LoadBoxedListLen,
LoadBoxedListLenOp {
list_reg: list_reg.into(),
min_list_len: list_len.lower_bound(),
},
);
return Ok(Some(
value::RegValue::new(list_len_reg, abitype::AbiType::Int).into(),
));
}
Ok(None)
}
pub fn cons(
_ehx: &mut EvalHirCtx,
b: &mut Option<Builder>,
span: Span,
arg_list_value: &Value,
) -> Result<Option<Value>> {
let mut iter = arg_list_value.unsized_list_iter();
let head = iter.next_unchecked(b, span);
let rest = iter.next_unchecked(b, span);
Ok(Some(Value::List(Box::new([head]), Some(Box::new(rest)))))
}
pub fn repeat(
_ehx: &mut EvalHirCtx,
b: &mut Option<Builder>,
span: Span,
arg_list_value: &Value,
) -> Result<Option<Value>> {
const MAX_REPEAT_EVAL_LEN: i64 = 64;
use crate::mir::intrinsic::num_utils::try_value_to_i64;
let mut iter = arg_list_value.unsized_list_iter();
let count_value = iter.next_unchecked(b, span);
let count = if let Some(count) = try_value_to_i64(count_value) {
count
} else {
return Ok(None);
};
let value = iter.next_unchecked(b, span);
if count <= 0 {
return Ok(Some(Value::List(Box::new([]), None)));
} else if count > MAX_REPEAT_EVAL_LEN {
return Ok(None);
}
Ok(Some(Value::List(
std::iter::repeat(value).take(count as usize).collect(),
None,
)))
}