Browse Source

Make `Function.prototype` a function (#802)

pull/805/head
Halid Odat 4 years ago committed by GitHub
parent
commit
ff25a8ad02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      boa/src/builtins/function/mod.rs
  2. 53
      boa/src/builtins/function/tests.rs
  3. 23
      boa/src/object/mod.rs

16
boa/src/builtins/function/mod.rs

@ -14,7 +14,7 @@
use crate::{ use crate::{
builtins::{Array, BuiltIn}, builtins::{Array, BuiltIn},
environment::lexical_environment::Environment, environment::lexical_environment::Environment,
object::{ConstructorBuilder, Object, ObjectData, PROTOTYPE}, object::{ConstructorBuilder, FunctionBuilder, Object, ObjectData, PROTOTYPE},
property::{Attribute, Property}, property::{Attribute, Property},
syntax::ast::node::{FormalParameter, RcStatementList}, syntax::ast::node::{FormalParameter, RcStatementList},
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
@ -301,13 +301,17 @@ pub struct BuiltInFunctionObject;
impl BuiltInFunctionObject { impl BuiltInFunctionObject {
pub const LENGTH: usize = 1; pub const LENGTH: usize = 1;
fn constructor(this: &Value, _args: &[Value], _context: &mut Context) -> Result<Value> { fn constructor(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
this.set_data(ObjectData::Function(Function::BuiltIn( this.set_data(ObjectData::Function(Function::BuiltIn(
BuiltInFunction(|_, _, _| Ok(Value::undefined())), BuiltInFunction(|_, _, _| Ok(Value::undefined())),
FunctionFlags::CALLABLE | FunctionFlags::CONSTRUCTABLE, FunctionFlags::CALLABLE | FunctionFlags::CONSTRUCTABLE,
))); )));
Ok(this.clone()) Ok(this.clone())
} }
fn prototype(_: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
Ok(Value::undefined())
}
} }
impl BuiltIn for BuiltInFunctionObject { impl BuiltIn for BuiltInFunctionObject {
@ -320,6 +324,14 @@ impl BuiltIn for BuiltInFunctionObject {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event("function", "init"); let _timer = BoaProfiler::global().start_event("function", "init");
let function_prototype = context.standard_objects().function_object().prototype();
FunctionBuilder::new(context, Self::prototype)
.name("")
.length(0)
.callable(true)
.constructable(false)
.build_function_prototype(&function_prototype);
let function_object = ConstructorBuilder::with_standard_object( let function_object = ConstructorBuilder::with_standard_object(
context, context,
Self::constructor, Self::constructor,

53
boa/src/builtins/function/tests.rs

@ -61,3 +61,56 @@ fn self_mutating_function_when_constructing() {
3 3
); );
} }
#[test]
fn call_function_prototype() {
let mut engine = Context::new();
let func = r#"
Function.prototype()
"#;
let value = forward_val(&mut engine, func).unwrap();
assert!(value.is_undefined());
}
#[test]
fn call_function_prototype_with_arguments() {
let mut engine = Context::new();
let func = r#"
Function.prototype(1, "", new String(""))
"#;
let value = forward_val(&mut engine, func).unwrap();
assert!(value.is_undefined());
}
#[test]
fn call_function_prototype_with_new() {
let mut engine = Context::new();
let func = r#"
new Function.prototype()
"#;
let value = forward_val(&mut engine, func);
assert!(value.is_err());
}
#[test]
fn function_prototype_name() {
let mut engine = Context::new();
let func = r#"
Function.prototype.name
"#;
let value = forward_val(&mut engine, func).unwrap();
assert!(value.is_string());
assert!(value.as_string().unwrap().is_empty());
}
#[test]
#[allow(clippy::float_cmp)]
fn function_prototype_length() {
let mut engine = Context::new();
let func = r#"
Function.prototype.length
"#;
let value = forward_val(&mut engine, func).unwrap();
assert!(value.is_number());
assert_eq!(value.as_number().unwrap(), 0.0);
}

23
boa/src/object/mod.rs

@ -670,6 +670,29 @@ impl<'context> FunctionBuilder<'context> {
GcObject::new(function) GcObject::new(function)
} }
/// Initializes the `Function.prototype` function object.
pub(crate) fn build_function_prototype(&mut self, object: &GcObject) {
let mut object = object.borrow_mut();
object.data = ObjectData::Function(Function::BuiltIn(
self.function,
FunctionFlags::from_parameters(self.callable, self.constructable),
));
object.set_prototype_instance(
self.context
.standard_objects()
.object_object()
.prototype()
.into(),
);
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
if let Some(name) = self.name.take() {
object.insert_property("name", name, attribute);
} else {
object.insert_property("name", "", attribute);
}
object.insert_property("length", self.length, attribute);
}
} }
/// Builder for creating objects with properties. /// Builder for creating objects with properties.

Loading…
Cancel
Save