-
-
Notifications
You must be signed in to change notification settings - Fork 401
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
511 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
use boa::{ | ||
builtins::{ | ||
object::{Class, ClassBuilder}, | ||
property::Attribute, | ||
value::Value, | ||
}, | ||
exec::Interpreter, | ||
forward_val, | ||
realm::Realm, | ||
Result, | ||
}; | ||
|
||
use gc::{Finalize, Trace}; | ||
|
||
// We create a new struct that is going to represent a person. | ||
// | ||
// We derive `Debug`, `Trace` and `Finalize`, It automatically implements `NativeObject` | ||
// so we can pass it an object in JavaScript. | ||
// | ||
// The fields of the sturct are not accesable by JavaScript unless accessors are created for them. | ||
/// This Represents a Person. | ||
#[derive(Debug, Trace, Finalize)] | ||
struct Person { | ||
/// The name of the person. | ||
name: String, | ||
/// The age of the preson. | ||
age: u32, | ||
} | ||
|
||
// Here we implement a static method for Person that matches the `NativeFunction` signiture. | ||
// | ||
// NOTE: The function does not have to be implemented of Person it can be a free function, | ||
// or any function that matches that signature. | ||
impl Person { | ||
/// This function says hello | ||
fn say_hello(this: &Value, _: &[Value], ctx: &mut Interpreter) -> Result<Value> { | ||
// We check if this is an object. | ||
if let Some(object) = this.as_object() { | ||
// If it is we downcast the type to type `Person`. | ||
if let Some(person) = object.downcast_ref::<Person>() { | ||
// we print the message to stdout. | ||
println!( | ||
"Hello my name is {}, I'm {} years old", | ||
person.name, | ||
person.age // Here we can access the native rust fields of Person struct. | ||
); | ||
return Ok(Value::undefined()); | ||
} | ||
} | ||
// If `this` was not an object or the type was not an native object `Person`, | ||
// we throw a `TypeError`. | ||
ctx.throw_type_error("'this' is not a Person object") | ||
} | ||
} | ||
|
||
impl Class for Person { | ||
// we set the binging name of this function to be `"Person"`. | ||
// It does not have to be `"Person"` it can be any string. | ||
const NAME: &'static str = "Person"; | ||
// We set the length to `2` since we accept 2 arguments in the constructor. | ||
// | ||
// This is the same as `Object.length`. | ||
// NOTE: If this is not defiend that the default is `0`. | ||
const LENGTH: usize = 2; | ||
|
||
// This is what is called when we do `new Person()` | ||
fn constructor(_this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result<Self> { | ||
// we get the first arguemnt of undefined if the first one is unavalable and call `to_string`. | ||
// | ||
// This is equivalent to `String(arg)`. | ||
let name = args.get(0).cloned().unwrap_or_default().to_string(ctx)?; | ||
// we get the second arguemnt of undefined if the first one is unavalable and call `to_u32`. | ||
// | ||
// This is equivalent to `arg | 0`. | ||
let age = args.get(1).cloned().unwrap_or_default().to_u32(ctx)?; | ||
|
||
// we construct the the native struct `Person` | ||
let person = Person { | ||
name: name.to_string(), | ||
age, | ||
}; | ||
|
||
Ok(person) // and we return it. | ||
} | ||
|
||
/// This is where the object is intitialized. | ||
fn init(class: &mut ClassBuilder) -> Result<()> { | ||
// we add a inheritable method `sayHello` with length `0` the amount of args it takes. | ||
// | ||
// This function is added to `Person.prototype.sayHello()` | ||
class.method("sayHello", 0, Self::say_hello); | ||
// we add a static mathod `is`, and here we use a closure, but it must be converible | ||
// to a NativeFunction. it must not contain state, if it does it will give a compilation error. | ||
// | ||
// This function is added to `Person.is()` | ||
class.static_method("is", 1, |_this, args, _ctx| { | ||
if let Some(arg) = args.get(0) { | ||
if let Some(object) = arg.as_object() { | ||
if object.is::<Person>() { | ||
// we check if the object type is `Person` | ||
return Ok(true.into()); // return `true`. | ||
} | ||
} | ||
} | ||
Ok(false.into()) // otherwise `false`. | ||
}); | ||
|
||
// Add a inherited property with the value `10`, with deafault attribute. | ||
// (`READONLY, NON_ENUMERABLE, PERMANENT). | ||
class.property("inheritedProperty", 10, Attribute::default()); | ||
|
||
// Add a static property with the value `"Im a static property"`, with deafault attribute. | ||
// (`WRITABLE, ENUMERABLE, PERMANENT`). | ||
class.static_property( | ||
"staticProperty", | ||
"Im a static property", | ||
Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::PERMANENT, | ||
); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
fn main() { | ||
let realm = Realm::create(); | ||
let mut context = Interpreter::new(realm); | ||
|
||
// we register the global class `Person`. | ||
context.register_global_class::<Person>().unwrap(); | ||
|
||
forward_val( | ||
&mut context, | ||
r" | ||
let person = new Person('John', 19); | ||
person.sayHello(); | ||
if (Person.is(person)) { | ||
console.log('person is a Person class instance.'); | ||
} | ||
if (!Person.is('Hello')) { | ||
console.log('\'Hello\' string is not a Person class instance.'); | ||
} | ||
console.log(Person.staticProperty); | ||
console.log(person.inheritedProperty); | ||
console.log(Person.prototype.inheritedProperty === person.inheritedProperty); | ||
", | ||
) | ||
.unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.