Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
sebffischer committed Oct 27, 2024
1 parent 5a6bd88 commit 0ba583d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 26 deletions.
11 changes: 11 additions & 0 deletions src/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@

## Noteable Bugs Addressed:

<<<<<<< Updated upstream
* `substitute()` now works on datatypes such as literals or calls.
=======
* `substitute()` now works on datatypes such as literals or calls (#199).
* accessing variable collected via 'rest-args' does now force evaluation of calls (#216).
>>>>>>> Stashed changes
## Internals

Expand All @@ -26,9 +31,15 @@
and unused ones removed.
* The `RepType` struct that was introduced in 0.4.0 was removed again (#189).
* `eval_list_eager()` was removed from the `Context` trait and added as a member method for `CallStack`.
<<<<<<< Updated upstream
* `eval_list_lazy()` now boxes all expressions in promises (including literals)
This is necessary to box `..a`-style ellipsis arguments in a list-call promise, which requires
access to the underlying expression.
=======
* `eval_list_lazy()` now boxes all expressions in promises (including literals).
This is necessary to box `..a`-style ellipsis arguments in a list-call promise, which requires
access to the underlying expression (needed to solve #216).
>>>>>>> Stashed changes
## Notable Bugs Addressed

Expand Down
53 changes: 27 additions & 26 deletions src/callable/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ pub trait CallableFormals {
pub trait Callable: CallableFormals {
fn match_args(&self, args: List, stack: &mut CallStack) -> Result<(List, List), Signal> {
let mut formals = self.formals();

// this collects the expressions
let mut expr_ellipsis: ExprList = ExprList::new();
let mut ellipsis: List = List::new();
let mut matched_args: List = List::new();

Expand Down Expand Up @@ -70,52 +67,56 @@ pub trait Callable: CallableFormals {

// backfill unnamed args, populating ellipsis with overflow
for (key, value) in args.iter_pairs() {
match (key, value.clone()) {
match key {
// named args go directly to ellipsis, they did not match a formal
(Character::Some(arg), Obj::Promise(_, e, _)) => {
expr_ellipsis.push_named(Character::Some(arg.clone()).as_option(), e);
ellipsis.push_named(Character::Some(arg), value);
}
Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value),

// unnamed args populate next formal, or ellipsis if formals exhausted
(Character::NA, value) => {
Character::NA => {
let next_unassigned_formal = formals.remove(0);
if let Some((Some(param), _)) = next_unassigned_formal {
matched_args.push_named(Character::Some(param), value);
} else {
let Obj::Promise(_, e, _) = value.clone() else {
unreachable!()
};
expr_ellipsis.push_named(Character::NA.as_option(), e);
ellipsis.push_named(Character::NA, value);
}
}
_ => unreachable!(),
}
}

// add back in parameter defaults that weren't filled with args
for (param, default) in formals.into_iter() {
matched_args.push_named(
param.into(),
Obj::Promise(None, default, stack.last_frame().env().clone()),
)
}
let mut ellipsis_expr = ExprList::new();

use crate::callable::builtins::BUILTIN;
for (k, v) in ellipsis.iter_pairs() {
if let Obj::Promise(_, e, _) = v {
ellipsis_expr.push_named(k.as_option(), e)
} else {
// all arguments must be boxed in promises to allow for NSE
unreachable!()
}
}

let list = BUILTIN.get("list").cloned().unwrap();
let list = crate::callable::builtins::BUILTIN
.get("list")
.cloned()
.unwrap();

// convert the expr_ellipsis to an Obj::Promise where the expression is a call into List

let a = Obj::Promise(
let ellipsis_promise = Obj::Promise(
None,
Expr::Call(Box::new(Expr::Primitive(list)), expr_ellipsis),
Expr::Call(Box::new(Expr::Primitive(list)), ellipsis_expr),
stack.last_frame().env().clone(),
);

// add back in parameter defaults that weren't filled with args
for (param, default) in formals.into_iter() {
matched_args.push_named(
param.into(),
Obj::Promise(None, default, stack.last_frame().env().clone()),
)
}

if let Some(Expr::Ellipsis(Some(name))) = remainder.get(0) {
matched_args.push_named(Character::Some(name), a);
matched_args.push_named(Character::Some(name), ellipsis_promise);
} else if !remainder.is_empty() {
matched_args.push_named(
Character::Some("...".to_string()),
Expand Down

0 comments on commit 0ba583d

Please sign in to comment.