Skip to content

Commit 8dd25d1

Browse files
authored
Missing mod op implementation and prelude additions. (#184)
- feature: new `split-at`, `split-after`, `split-once` prelude fns - fix: `take-while` now tail recursive and lazier - fix: __MOD intrinsic and % op were broken; now fixed
1 parent e2c987f commit 8dd25d1

File tree

13 files changed

+101
-29
lines changed

13 files changed

+101
-29
lines changed

harness/test/012_arith.eu

+18-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
(l - r): __SUB(l, r)
66
(l * r): __MUL(l, r)
77
(l / r): __DIV(l, r)
8+
(l % r): __MOD(l, r)
89

910
(l > r): __GT(l, r)
1011
(l < r): __LT(l, r)
@@ -30,14 +31,15 @@ integer-arithmetic: {
3031
f: 1 >= 2
3132
}
3233

33-
vals: {
34-
four: 2 + 2
35-
also-four: 2 * 2
36-
three: 5 - 2
37-
twelve: 24 / 2
34+
true-calcs: {
35+
four: 2 + 2 //= 4
36+
also-four: 2 * 2 //= 4
37+
three: 5 - 2 //= 3
38+
twelve: 24 / 2 //= 12
39+
two: 5 % 3 //= 2
3840
}
3941

40-
pass: (trues values all-true?) ∧ (falses values map(not) all-true?)
42+
pass: (trues values all-true?) ∧ (falses values map(not) all-true?) ∧ (true-calcs values all-true?)
4143
}
4244

4345
floating-point-arithmetic: {
@@ -60,10 +62,11 @@ floating-point-arithmetic: {
6062
}
6163

6264
vals: {
63-
fourish: 2.01 + 2.01
64-
also-fourish: 2.01 * 2.01
65-
threeish: 5.01 - 2.01
66-
twelveish: 24.01 / 2.01
65+
fourish: (2.01 + 2.01) - 4 < 0.1
66+
also-fourish: (2.01 * 2.01) - 4 < 0.1
67+
threeish: (5.01 - 2.01) - 3 < 0.1
68+
twelveish: (24.01 / 2.01) - 12 < 0.1
69+
twoish: (5.01 % 3) - 2 < 0.1
6770
}
6871

6972
pass: (trues values all-true?) ∧ (falses values map(not) all-true?)
@@ -107,10 +110,11 @@ mixed-arithmetic: {
107110
}
108111

109112
vals: {
110-
fourish: 2.01 + 2
111-
also-fourish: 2.01 * 2
112-
threeish: 5.01 - 2
113-
twelveish: 24.01 / 2
113+
fourish: (2.01 + 2) - 4 < 0.1
114+
also-fourish: (2.01 * 2) - 4 < 0.1
115+
threeish: (5.01 - 2) - 3 < 0.1
116+
twelveish: (24.01 / 2) - 12 < 0.1
117+
twoish: (5.01 % 3) - 2 < 0.1
114118
}
115119

116120
pass: ((trues values) ++ (trues2 values) all-true?) ∧

harness/test/036_takes_and_drops.eu

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ tests: {
1010
ι: [0, 1, 2, 3] take-until(>= 0) //= []
1111
κ: [0, 1] cycle take(5) //= [0, 1, 0, 1, 0]
1212
λ: [] cycle take(10) //= []
13+
μ: ints-from(0) split-at(4) first //= [0, 1, 2, 3]
14+
ν: range(0, 10) split-at(5) //= [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
15+
ξ: ints-from(0) take-while(_ < 5) //= [0, 1, 2, 3, 4]
16+
ο: range(0, 8) split-after(_ < 5) //= [[0, 1, 2, 3, 4], [5, 6, 7]]
17+
π: range(0, 8) split-when(_ > 5) //= [[0, 1, 2, 3, 4, 5], [6, 7]]
18+
ρ: ints-from(0) split-after(_ < 5) first //= [0, 1, 2, 3, 4]
19+
σ: ints-from(0) split-after(_ < 5) second take(2) //= [5, 6]
1320
}
1421

1522
RESULT: tests values all-true? then(:PASS, :FAIL)

lib/prelude.eu

+18-1
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,15 @@ take(n, l): __IF((n zero?) ∨ (l nil?), [], cons(l head, take(n dec, l tail)))
526526
` "`drop(n, l)` - return result of dropping integer `n` elements from list `l`."
527527
drop(n, l): __IF((n zero?), l, drop(n dec, l tail))
528528

529+
` "'split-at(n, l) - split list in to at `n`th item and return pair."
530+
split-at(n, l): {
531+
aux(n, xs, prefix): if((xs nil?) ∨ (n zero?), [prefix reverse, xs], aux(n dec, xs tail, cons(xs head, prefix)))
532+
}.aux(n, l, [])
533+
529534
` "`take-while(p?, l)` - initial elements of list `l` while `p?` is true."
530-
take-while(p?, l): if(l nil?, [], if(l head p?, cons(l head, take-while(p?, l tail)), take-while(p?, l tail)))
535+
take-while(p?, l): {
536+
aux(xs, prefix): if(not(xs nil?) ∧ (xs head p?), aux(xs tail, cons(xs head, prefix)), prefix reverse)
537+
}.aux(l, [])
531538

532539
` "`take-until(p?, l)` - initial elements of list `l` while `p?` is false."
533540
take-until(p?): take-while(p? complement)
@@ -538,6 +545,16 @@ drop-while(p?, l): if(l nil?, [], if(l head p?, drop-while(p?, l tail), l))
538545
` "`drop-until(p?, l)` - skip initial elements of list `l` while `p?` is false."
539546
drop-until(p?): drop-while(p? complement)
540547

548+
` "`split-after(p?, l) - split list where `p?` becomes false and return pair."
549+
split-after(p?, l): {
550+
aux(xs, prefix): if((xs nil?) ∨ (xs head p?),
551+
aux(xs tail, cons(xs head, prefix)),
552+
[prefix reverse, xs])
553+
}.aux(l, [])
554+
555+
` "`split-when(p?, l) - split list where `p?` becomes true and return pair."
556+
split-when(p?, l): split-after(p? complement, l)
557+
541558
` "`nth(n, l)` - return `n`th item of list if it exists, otherwise panic."
542559
nth(n, l): l drop(n) head
543560

src/core/desugar/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn declaration_to_binding(
7777
if let Some(target) = &metadata.target {
7878
desugarer.record_target(
7979
target.to_string(),
80-
metadata.doc.unwrap_or_else(|| "".to_string()),
80+
metadata.doc.unwrap_or_default(),
8181
metadata.format,
8282
metadata.validations.unwrap_or_default(),
8383
);

src/core/export/embed.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ impl Embed for CoreExpr {
6060
Expr::Lookup(_, e, n, fb) => {
6161
elements.push(lit(sym("c-lookup")));
6262
elements.push(e.embed());
63-
elements.push(lit(str(&n)));
63+
elements.push(lit(str(n)));
6464
if let Some(x) = fb {
6565
elements.push(x.embed());
6666
}
6767
}
6868
Expr::Name(_, n) => {
6969
elements.push(lit(sym("c-name")));
70-
elements.push(lit(str(&n)));
70+
elements.push(lit(str(n)));
7171
}
7272
Expr::BlockAnaphor(_, anaphor) => {
7373
elements.push(lit(sym("c-bk-ana")));
@@ -151,11 +151,11 @@ impl Embed for CoreExpr {
151151
}
152152
Expr::ErrUnresolved(_, x) => {
153153
elements.push(lit(sym("e-unresolved")));
154-
elements.push(lit(str(&x)));
154+
elements.push(lit(str(x)));
155155
}
156156
Expr::ErrRedeclaration(_, x) => {
157157
elements.push(lit(sym("e-redeclaration")));
158-
elements.push(lit(str(&x)));
158+
elements.push(lit(str(x)));
159159
}
160160
Expr::ErrEliminated => {
161161
elements.push(lit(sym("e-eliminated")));
@@ -178,7 +178,7 @@ impl Embed for CoreExpr {
178178
impl Embed for Primitive {
179179
fn embed(&self) -> Expression {
180180
match self {
181-
Primitive::Str(s) => lit(str(&s)),
181+
Primitive::Str(s) => lit(str(s)),
182182
Primitive::Sym(s) => lit(sym(s)),
183183
Primitive::Num(n) => lit(num(n.clone())),
184184
Primitive::Bool(b) => list(vec![

src/core/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! The core expression representation and various processing phases
2+
#![allow(clippy::result_large_err)]
23
pub mod analyse;
34
pub mod anaphora;
45
pub mod cook;

src/eval/machine/env.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ where
275275
if smid != Smid::default() {
276276
trace.push(smid);
277277
}
278-
match (*frame).next {
278+
match frame.next {
279279
Some(f) => frame = ScopedPtr::from_non_null(guard, f),
280280
None => return trace,
281281
}
@@ -290,7 +290,7 @@ where
290290
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291291
let len = self.bindings.len();
292292

293-
match (*self).next {
293+
match self.next {
294294
None => {
295295
if len > 0 {
296296
write!(f, "[×{}]→•", len)

src/eval/stg/arith.rs

+42
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,48 @@ impl StgIntrinsic for Div {
179179

180180
impl CallGlobal2 for Div {}
181181

182+
/// MOD(l, r) - mod r from l
183+
pub struct Mod;
184+
185+
impl StgIntrinsic for Mod {
186+
fn name(&self) -> &str {
187+
"MOD"
188+
}
189+
190+
fn execute<'guard>(
191+
&self,
192+
machine: &mut dyn IntrinsicMachine,
193+
view: MutatorHeapView<'guard>,
194+
_emitter: &mut dyn Emitter,
195+
args: &[Ref],
196+
) -> Result<(), crate::eval::error::ExecutionError> {
197+
let x = num_arg(machine, view, &args[0])?;
198+
let y = num_arg(machine, view, &args[1])?;
199+
200+
if let (Some(l), Some(r)) = (x.as_i64(), y.as_i64()) {
201+
let product = l
202+
.checked_rem(r)
203+
.map_or(Err(ExecutionError::NumericRangeError(x, y)), Ok)?;
204+
machine_return_num(machine, view, Number::from(product))
205+
} else if let (Some(l), Some(r)) = (x.as_u64(), y.as_u64()) {
206+
let product = l
207+
.checked_rem(r)
208+
.map_or(Err(ExecutionError::NumericRangeError(x, y)), Ok)?;
209+
machine_return_num(machine, view, Number::from(product))
210+
} else if let (Some(l), Some(r)) = (x.as_f64(), y.as_f64()) {
211+
if let Some(ret) = Number::from_f64(l % r) {
212+
machine_return_num(machine, view, ret)
213+
} else {
214+
Err(ExecutionError::NumericDomainError(x, y))
215+
}
216+
} else {
217+
Err(ExecutionError::NumericDomainError(x, y))
218+
}
219+
}
220+
}
221+
222+
impl CallGlobal2 for Mod {}
223+
182224
/// GT(l, r) l > r
183225
pub struct Gt;
184226

src/eval/stg/compiler.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ impl<'rt> Compiler<'rt> {
10431043
let mut index = KEmptyList.gref(); // binder.add(dsl::nil())?; // TODO: to CAF
10441044
for (k, v) in block_map.iter().rev() {
10451045
let v_index = self.compile_binding(binder, v.clone(), smid, false)?;
1046-
let kv_index = binder.add(dsl::pair(&k, v_index))?;
1046+
let kv_index = binder.add(dsl::pair(k, v_index))?;
10471047
index = binder.add(dsl::cons(kv_index, index))?;
10481048
}
10491049
Ok(Holder::new(dsl::block(index)))

src/eval/stg/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn make_standard_runtime(source_map: &mut SourceMap) -> Box<runtime::Standar
4343
rt.add(Box::new(arith::Sub));
4444
rt.add(Box::new(arith::Mul));
4545
rt.add(Box::new(arith::Div));
46+
rt.add(Box::new(arith::Mod));
4647
rt.add(Box::new(arith::Gt));
4748
rt.add(Box::new(arith::Lt));
4849
rt.add(Box::new(arith::Gte));

src/import/yaml.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ impl Tag {
342342
/// If tags aren't explicit, infer from value
343343
#[allow(clippy::trivial_regex)]
344344
fn infer_tag_for_plain_scalar(text: &str) -> Tag {
345-
let set = RegexSet::new(&[
345+
let set = RegexSet::new([
346346
r"^[nN]ull$",
347347
r"^NULL$",
348348
r"^~$",

src/syntax/export/embed.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl Embed for Literal {
1111
fn embed(&self) -> Expression {
1212
match self {
1313
Literal::Sym(_, s) => lit(sym(s)),
14-
Literal::Str(_, s) => lit(str(&s)),
14+
Literal::Str(_, s) => lit(str(s)),
1515
Literal::Num(_, n) => lit(num(n.clone())),
1616
}
1717
}

src/syntax/lexer.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ where
233233

234234
/// consume a normal identifer
235235
fn normal(&mut self, i: ByteIndex) -> (ByteIndex, Token<'text>, ByteIndex) {
236-
let e = self.consume(&is_normal_continuation);
236+
let e = self.consume(is_normal_continuation);
237237
(i, Token::NormalIdentifier(self.slice(i, e)), e)
238238
}
239239

@@ -253,7 +253,7 @@ where
253253

254254
/// consume an operator identifer
255255
fn oper(&mut self, i: ByteIndex) -> (ByteIndex, Token<'text>, ByteIndex) {
256-
let e = self.consume(&is_oper_continuation);
256+
let e = self.consume(is_oper_continuation);
257257
(i, Token::OperatorIdentifier(self.slice(i, e)), e)
258258
}
259259

@@ -278,7 +278,7 @@ where
278278

279279
if is_normal_start(c) {
280280
if let Some((b, _)) = self.bump() {
281-
let e = self.consume(&is_normal_continuation);
281+
let e = self.consume(is_normal_continuation);
282282
return (i, Token::Symbol(self.slice(b, e)), e);
283283
} else {
284284
panic!("peek and next disagree");

0 commit comments

Comments
 (0)