Skip to content

Commit

Permalink
Missing mod op implementation and prelude additions. (#184)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
gmorpheme authored Dec 6, 2022
1 parent e2c987f commit 8dd25d1
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 29 deletions.
32 changes: 18 additions & 14 deletions harness/test/012_arith.eu
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
(l - r): __SUB(l, r)
(l * r): __MUL(l, r)
(l / r): __DIV(l, r)
(l % r): __MOD(l, r)

(l > r): __GT(l, r)
(l < r): __LT(l, r)
Expand All @@ -30,14 +31,15 @@ integer-arithmetic: {
f: 1 >= 2
}

vals: {
four: 2 + 2
also-four: 2 * 2
three: 5 - 2
twelve: 24 / 2
true-calcs: {
four: 2 + 2 //= 4
also-four: 2 * 2 //= 4
three: 5 - 2 //= 3
twelve: 24 / 2 //= 12
two: 5 % 3 //= 2
}

pass: (trues values all-true?) ∧ (falses values map(not) all-true?)
pass: (trues values all-true?) ∧ (falses values map(not) all-true?) ∧ (true-calcs values all-true?)
}

floating-point-arithmetic: {
Expand All @@ -60,10 +62,11 @@ floating-point-arithmetic: {
}

vals: {
fourish: 2.01 + 2.01
also-fourish: 2.01 * 2.01
threeish: 5.01 - 2.01
twelveish: 24.01 / 2.01
fourish: (2.01 + 2.01) - 4 < 0.1
also-fourish: (2.01 * 2.01) - 4 < 0.1
threeish: (5.01 - 2.01) - 3 < 0.1
twelveish: (24.01 / 2.01) - 12 < 0.1
twoish: (5.01 % 3) - 2 < 0.1
}

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

vals: {
fourish: 2.01 + 2
also-fourish: 2.01 * 2
threeish: 5.01 - 2
twelveish: 24.01 / 2
fourish: (2.01 + 2) - 4 < 0.1
also-fourish: (2.01 * 2) - 4 < 0.1
threeish: (5.01 - 2) - 3 < 0.1
twelveish: (24.01 / 2) - 12 < 0.1
twoish: (5.01 % 3) - 2 < 0.1
}

pass: ((trues values) ++ (trues2 values) all-true?) ∧
Expand Down
7 changes: 7 additions & 0 deletions harness/test/036_takes_and_drops.eu
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ tests: {
ι: [0, 1, 2, 3] take-until(>= 0) //= []
κ: [0, 1] cycle take(5) //= [0, 1, 0, 1, 0]
λ: [] cycle take(10) //= []
μ: ints-from(0) split-at(4) first //= [0, 1, 2, 3]
ν: range(0, 10) split-at(5) //= [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
ξ: ints-from(0) take-while(_ < 5) //= [0, 1, 2, 3, 4]
ο: range(0, 8) split-after(_ < 5) //= [[0, 1, 2, 3, 4], [5, 6, 7]]
π: range(0, 8) split-when(_ > 5) //= [[0, 1, 2, 3, 4, 5], [6, 7]]
ρ: ints-from(0) split-after(_ < 5) first //= [0, 1, 2, 3, 4]
σ: ints-from(0) split-after(_ < 5) second take(2) //= [5, 6]
}

RESULT: tests values all-true? then(:PASS, :FAIL)
19 changes: 18 additions & 1 deletion lib/prelude.eu
Original file line number Diff line number Diff line change
Expand Up @@ -526,8 +526,15 @@ take(n, l): __IF((n zero?) ∨ (l nil?), [], cons(l head, take(n dec, l tail)))
` "`drop(n, l)` - return result of dropping integer `n` elements from list `l`."
drop(n, l): __IF((n zero?), l, drop(n dec, l tail))

` "'split-at(n, l) - split list in to at `n`th item and return pair."
split-at(n, l): {
aux(n, xs, prefix): if((xs nil?) ∨ (n zero?), [prefix reverse, xs], aux(n dec, xs tail, cons(xs head, prefix)))
}.aux(n, l, [])

` "`take-while(p?, l)` - initial elements of list `l` while `p?` is true."
take-while(p?, l): if(l nil?, [], if(l head p?, cons(l head, take-while(p?, l tail)), take-while(p?, l tail)))
take-while(p?, l): {
aux(xs, prefix): if(not(xs nil?) ∧ (xs head p?), aux(xs tail, cons(xs head, prefix)), prefix reverse)
}.aux(l, [])

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

` "`split-after(p?, l) - split list where `p?` becomes false and return pair."
split-after(p?, l): {
aux(xs, prefix): if((xs nil?) ∨ (xs head p?),
aux(xs tail, cons(xs head, prefix)),
[prefix reverse, xs])
}.aux(l, [])

` "`split-when(p?, l) - split list where `p?` becomes true and return pair."
split-when(p?, l): split-after(p? complement, l)

` "`nth(n, l)` - return `n`th item of list if it exists, otherwise panic."
nth(n, l): l drop(n) head

Expand Down
2 changes: 1 addition & 1 deletion src/core/desugar/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn declaration_to_binding(
if let Some(target) = &metadata.target {
desugarer.record_target(
target.to_string(),
metadata.doc.unwrap_or_else(|| "".to_string()),
metadata.doc.unwrap_or_default(),
metadata.format,
metadata.validations.unwrap_or_default(),
);
Expand Down
10 changes: 5 additions & 5 deletions src/core/export/embed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ impl Embed for CoreExpr {
Expr::Lookup(_, e, n, fb) => {
elements.push(lit(sym("c-lookup")));
elements.push(e.embed());
elements.push(lit(str(&n)));
elements.push(lit(str(n)));
if let Some(x) = fb {
elements.push(x.embed());
}
}
Expr::Name(_, n) => {
elements.push(lit(sym("c-name")));
elements.push(lit(str(&n)));
elements.push(lit(str(n)));
}
Expr::BlockAnaphor(_, anaphor) => {
elements.push(lit(sym("c-bk-ana")));
Expand Down Expand Up @@ -151,11 +151,11 @@ impl Embed for CoreExpr {
}
Expr::ErrUnresolved(_, x) => {
elements.push(lit(sym("e-unresolved")));
elements.push(lit(str(&x)));
elements.push(lit(str(x)));
}
Expr::ErrRedeclaration(_, x) => {
elements.push(lit(sym("e-redeclaration")));
elements.push(lit(str(&x)));
elements.push(lit(str(x)));
}
Expr::ErrEliminated => {
elements.push(lit(sym("e-eliminated")));
Expand All @@ -178,7 +178,7 @@ impl Embed for CoreExpr {
impl Embed for Primitive {
fn embed(&self) -> Expression {
match self {
Primitive::Str(s) => lit(str(&s)),
Primitive::Str(s) => lit(str(s)),
Primitive::Sym(s) => lit(sym(s)),
Primitive::Num(n) => lit(num(n.clone())),
Primitive::Bool(b) => list(vec![
Expand Down
1 change: 1 addition & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! The core expression representation and various processing phases
#![allow(clippy::result_large_err)]
pub mod analyse;
pub mod anaphora;
pub mod cook;
Expand Down
4 changes: 2 additions & 2 deletions src/eval/machine/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ where
if smid != Smid::default() {
trace.push(smid);
}
match (*frame).next {
match frame.next {
Some(f) => frame = ScopedPtr::from_non_null(guard, f),
None => return trace,
}
Expand All @@ -290,7 +290,7 @@ where
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let len = self.bindings.len();

match (*self).next {
match self.next {
None => {
if len > 0 {
write!(f, "[×{}]→•", len)
Expand Down
42 changes: 42 additions & 0 deletions src/eval/stg/arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,48 @@ impl StgIntrinsic for Div {

impl CallGlobal2 for Div {}

/// MOD(l, r) - mod r from l
pub struct Mod;

impl StgIntrinsic for Mod {
fn name(&self) -> &str {
"MOD"
}

fn execute<'guard>(
&self,
machine: &mut dyn IntrinsicMachine,
view: MutatorHeapView<'guard>,
_emitter: &mut dyn Emitter,
args: &[Ref],
) -> Result<(), crate::eval::error::ExecutionError> {
let x = num_arg(machine, view, &args[0])?;
let y = num_arg(machine, view, &args[1])?;

if let (Some(l), Some(r)) = (x.as_i64(), y.as_i64()) {
let product = l
.checked_rem(r)
.map_or(Err(ExecutionError::NumericRangeError(x, y)), Ok)?;
machine_return_num(machine, view, Number::from(product))
} else if let (Some(l), Some(r)) = (x.as_u64(), y.as_u64()) {
let product = l
.checked_rem(r)
.map_or(Err(ExecutionError::NumericRangeError(x, y)), Ok)?;
machine_return_num(machine, view, Number::from(product))
} else if let (Some(l), Some(r)) = (x.as_f64(), y.as_f64()) {
if let Some(ret) = Number::from_f64(l % r) {
machine_return_num(machine, view, ret)
} else {
Err(ExecutionError::NumericDomainError(x, y))
}
} else {
Err(ExecutionError::NumericDomainError(x, y))
}
}
}

impl CallGlobal2 for Mod {}

/// GT(l, r) l > r
pub struct Gt;

Expand Down
2 changes: 1 addition & 1 deletion src/eval/stg/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ impl<'rt> Compiler<'rt> {
let mut index = KEmptyList.gref(); // binder.add(dsl::nil())?; // TODO: to CAF
for (k, v) in block_map.iter().rev() {
let v_index = self.compile_binding(binder, v.clone(), smid, false)?;
let kv_index = binder.add(dsl::pair(&k, v_index))?;
let kv_index = binder.add(dsl::pair(k, v_index))?;
index = binder.add(dsl::cons(kv_index, index))?;
}
Ok(Holder::new(dsl::block(index)))
Expand Down
1 change: 1 addition & 0 deletions src/eval/stg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub fn make_standard_runtime(source_map: &mut SourceMap) -> Box<runtime::Standar
rt.add(Box::new(arith::Sub));
rt.add(Box::new(arith::Mul));
rt.add(Box::new(arith::Div));
rt.add(Box::new(arith::Mod));
rt.add(Box::new(arith::Gt));
rt.add(Box::new(arith::Lt));
rt.add(Box::new(arith::Gte));
Expand Down
2 changes: 1 addition & 1 deletion src/import/yaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl Tag {
/// If tags aren't explicit, infer from value
#[allow(clippy::trivial_regex)]
fn infer_tag_for_plain_scalar(text: &str) -> Tag {
let set = RegexSet::new(&[
let set = RegexSet::new([
r"^[nN]ull$",
r"^NULL$",
r"^~$",
Expand Down
2 changes: 1 addition & 1 deletion src/syntax/export/embed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl Embed for Literal {
fn embed(&self) -> Expression {
match self {
Literal::Sym(_, s) => lit(sym(s)),
Literal::Str(_, s) => lit(str(&s)),
Literal::Str(_, s) => lit(str(s)),
Literal::Num(_, n) => lit(num(n.clone())),
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/syntax/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ where

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

Expand All @@ -253,7 +253,7 @@ where

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

Expand All @@ -278,7 +278,7 @@ where

if is_normal_start(c) {
if let Some((b, _)) = self.bump() {
let e = self.consume(&is_normal_continuation);
let e = self.consume(is_normal_continuation);
return (i, Token::Symbol(self.slice(b, e)), e);
} else {
panic!("peek and next disagree");
Expand Down

0 comments on commit 8dd25d1

Please sign in to comment.