Skip to content

Commit

Permalink
Added native Class
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Aug 15, 2020
1 parent ca1ee12 commit 0e93042
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 6 deletions.
6 changes: 3 additions & 3 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ unsafe impl Trace for FunctionBody {

bitflags! {
#[derive(Finalize, Default)]
struct FunctionFlags: u8 {
pub(crate) struct FunctionFlags: u8 {
const CALLABLE = 0b0000_0001;
const CONSTRUCTABLE = 0b0000_0010;
}
}

impl FunctionFlags {
fn from_parameters(callable: bool, constructable: bool) -> Self {
pub(crate) fn from_parameters(callable: bool, constructable: bool) -> Self {
let mut flags = Self::default();

if callable {
Expand Down Expand Up @@ -142,7 +142,7 @@ pub struct Function {
// Environment, built-in functions don't need Environments
pub environment: Option<Environment>,
/// Is it constructable or
flags: FunctionFlags,
pub(crate) flags: FunctionFlags,
}

impl Function {
Expand Down
121 changes: 119 additions & 2 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
builtins::{
function::Function,
map::ordered_map::OrderedMap,
property::Property,
property::{Attribute, Property},
value::{RcBigInt, RcString, RcSymbol, ResultValue, Value},
BigInt, Date, RegExp,
},
Expand All @@ -29,7 +29,7 @@ use rustc_hash::FxHashMap;
use std::any::Any;
use std::fmt::{Debug, Display, Error, Formatter};

use super::function::{make_builtin_fn, make_constructor_fn};
use super::function::{make_builtin_fn, make_constructor_fn, FunctionFlags, NativeFunctionData};
use crate::builtins::value::same_value;

pub mod gcobject;
Expand Down Expand Up @@ -61,6 +61,123 @@ impl<T: Any + Debug + Trace> NativeObject for T {
}
}

pub trait Class: NativeObject {
const NAME: &'static str;
const LENGTH: usize = 0;

fn constructor(_: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue;
fn methods(class: &mut ClassBuilder<'_>) -> ResultValue;
}

#[derive(Debug)]
pub struct ClassBuilder<'context> {
context: &'context mut Interpreter,
object: GcObject,
prototype: GcObject,
}

impl<'context> ClassBuilder<'context> {
pub(crate) fn new<T>(context: &'context mut Interpreter) -> Self
where
T: Class,
{
let global = context.global();

let prototype = {
let object_prototype = global.get_field("Object").get_field(PROTOTYPE);

let object = Object::create(object_prototype);
GcObject::new(object)
};
// Create the native function
let mut function = Function::builtin(Vec::new(), T::constructor);
function.flags = FunctionFlags::from_parameters(false, true);

// Get reference to Function.prototype
// Create the function object and point its instance prototype to Function.prototype
let mut constructor =
Object::function(function, global.get_field("Function").get_field(PROTOTYPE));

let length = Property::data_descriptor(
T::LENGTH.into(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
);
constructor.insert_property("length", length);

let name = Property::data_descriptor(
T::NAME.into(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
);
constructor.insert_property("name", name);

let constructor = GcObject::new(constructor);

prototype
.borrow_mut()
.insert_field("constructor", constructor.clone().into());

constructor
.borrow_mut()
.insert_field(PROTOTYPE, prototype.clone().into());

Self {
context,
object: constructor,
prototype,
}
}

pub(crate) fn build(self) -> GcObject {
self.object
}

pub fn method<N>(&mut self, name: N, length: usize, function: NativeFunctionData)
where
N: Into<String>,
{
let name = name.into();
let mut function = Object::function(
Function::builtin(Vec::new(), function),
self.context
.global()
.get_field("Function")
.get_field("prototype"),
);

function.insert_field("length", Value::from(length));
function.insert_field("name", Value::from(name.as_str()));

self.prototype
.borrow_mut()
.insert_field(name, Value::from(function));
}

pub fn static_method<N>(&mut self, name: N, length: usize, function: NativeFunctionData)
where
N: Into<String>,
{
let name = name.into();
let mut function = Object::function(
Function::builtin(Vec::new(), function),
self.context
.global()
.get_field("Function")
.get_field("prototype"),
);

function.insert_field("length", Value::from(length));
function.insert_field("name", Value::from(name.as_str()));

self.object
.borrow_mut()
.insert_field(name, Value::from(function));
}

pub fn context(&mut self) -> &'_ mut Interpreter {
self.context
}
}

/// The internal representation of an JavaScript object.
#[derive(Debug, Trace, Finalize)]
pub struct Object {
Expand Down
14 changes: 13 additions & 1 deletion boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
builtins::{
function::{Function as FunctionObject, FunctionBody, ThisMode},
number::{f64_to_int32, f64_to_uint32},
object::{Object, ObjectData, PROTOTYPE},
object::{Class, ClassBuilder, Object, ObjectData, PROTOTYPE},
property::PropertyKey,
value::{RcBigInt, RcString, ResultValue, Type, Value},
BigInt, Console, Number,
Expand Down Expand Up @@ -675,6 +675,18 @@ impl Interpreter {
pub(crate) fn console_mut(&mut self) -> &mut Console {
&mut self.console
}

pub fn register_global_class<T>(&mut self) -> ResultValue
where
T: Class,
{
let mut class_builder = ClassBuilder::new::<T>(self);
T::methods(&mut class_builder)?;

let class = class_builder.build();
self.global().set_field(T::NAME, class);
Ok(Value::undefined())
}
}

impl Executable for Node {
Expand Down

0 comments on commit 0e93042

Please sign in to comment.