Skip to content

Commit

Permalink
Merge pull request #82 from Jacherr/function_apply
Browse files Browse the repository at this point in the history
add method `Function#apply`
  • Loading branch information
y21 authored Mar 20, 2024
2 parents 865659a + aad8b9e commit 38a0503
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 3 deletions.
3 changes: 2 additions & 1 deletion crates/dash_middle/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ pub mod sym {
getPrototypeOf,
isPrototypeOf,
arguments,
propertyIsEnumerable
propertyIsEnumerable,
apply
}
]
}
Expand Down
34 changes: 32 additions & 2 deletions crates/dash_vm/src/js_std/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,42 @@ use crate::value::function::bound::BoundFunction;
use crate::value::function::native::CallContext;
use crate::value::function::Function;
use crate::value::object::Object;
use crate::value::{Root, Typeof, Value};
use crate::value::ops::conversions::ValueConversion;
use crate::value::{Root, Typeof, Value, ValueContext};

pub fn constructor(cx: CallContext) -> Result<Value, Value> {
throw!(cx.scope, Error, "Dynamic code compilation is currently not supported")
}

pub fn apply(cx: CallContext) -> Result<Value, Value> {
let target_this = cx.args.first().cloned();
let target_args = if let Some(array) = cx.args.get(1).cloned() {
if array.is_nullish() {
vec![]
} else {
let mut target_args = vec![];
for i in 0..array.length_of_array_like(cx.scope)? {
let sym = cx.scope.intern_usize(i).into();

let arg_i = array.get_property(cx.scope, sym).root(cx.scope)?;
target_args.push(arg_i);
}
target_args
}
} else {
vec![]
};

let target_callee = match cx.this {
Value::Object(o) if matches!(o.type_of(), Typeof::Function) => o,
_ => throw!(cx.scope, TypeError, "Bound value must be a function"),
};

target_callee
.apply(cx.scope, target_this.unwrap_or_undefined(), target_args)
.root(cx.scope)
}

pub fn bind(cx: CallContext) -> Result<Value, Value> {
let target_this = cx.args.first().cloned();
let target_args = cx.args.get(1..).map(|s| s.to_vec());
Expand All @@ -32,7 +62,7 @@ pub fn call(cx: CallContext) -> Result<Value, Value> {
target_callee
.apply(
cx.scope,
target_this.unwrap_or_else(Value::undefined),
target_this.unwrap_or_undefined(),
target_args.unwrap_or_default(),
)
.root(cx.scope)
Expand Down
1 change: 1 addition & 0 deletions crates/dash_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ impl Vm {
scope.statics.object_prototype.clone(),
function_ctor.clone(),
[
(sym::apply, scope.statics.function_apply.clone()),
(sym::bind, scope.statics.function_bind.clone()),
(sym::call, scope.statics.function_call.clone()),
(sym::toString, scope.statics.function_to_string.clone()),
Expand Down
2 changes: 2 additions & 0 deletions crates/dash_vm/src/statics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use super::value::primitive::Symbol;
pub struct Statics {
pub function_proto: Handle,
pub function_ctor: Handle,
pub function_apply: Handle,
pub function_bind: Handle,
pub function_call: Handle,
pub function_to_string: Handle,
Expand Down Expand Up @@ -266,6 +267,7 @@ impl Statics {
Self {
function_proto: empty_object(gc),
function_ctor: function(gc, sym::Function, js_std::function::constructor),
function_apply: function(gc, sym::apply, js_std::function::apply),
function_bind: function(gc, sym::bind, js_std::function::bind),
function_call: function(gc, sym::call, js_std::function::call),
function_to_string: function(gc, sym::toString, js_std::function::to_string),
Expand Down
12 changes: 12 additions & 0 deletions crates/dash_vm/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,15 @@ assert([,,].length === 2);
"#,
Value::undefined()
);

simple_test!(
function_apply,
r#"
function sum(...args) { return args.reduce((p,c)=>p+c,0); }
assert(sum.apply(null, [1,2,3]) === 6);
assert(sum.apply(null) === 0);
assert(sum.apply(null, null) === 0);
assert(sum.apply(null, 0) === 0);
"#,
Value::undefined()
);

0 comments on commit 38a0503

Please sign in to comment.