mirror of https://github.com/boa-dev/boa.git
Jason Williams
6 years ago
8 changed files with 386 additions and 149 deletions
@ -1,17 +1,43 @@
|
||||
use js::object::{INSTANCE_PROTOTYPE, PROTOTYPE, ObjectData}; |
||||
use gc::GcCell; |
||||
use js::object::ObjectData; |
||||
use js::value::{ResultValue, Value, ValueData}; |
||||
use js::{function, json, object}; |
||||
use std::cell::RefCell; |
||||
use syntax::ast::expr::Expr; |
||||
|
||||
/// An execution engine
|
||||
pub trait Executor { |
||||
/// Make a new execution engine
|
||||
fn new() -> Self; |
||||
/// Set a global variable called `name` with the value `val`
|
||||
// fn set_global(&mut self, name: String, val: Value) -> Value;
|
||||
fn set_global(&mut self, name: String, val: Value) -> Value; |
||||
/// Resolve the global variable `name`
|
||||
// fn get_global(&self, name: String) -> Value;
|
||||
fn get_global(&self, name: String) -> Value; |
||||
/// Create a new scope and return it
|
||||
// fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
|
||||
fn make_scope(&mut self) -> GcCell<RefCell<ObjectData>>; |
||||
/// Destroy the current scope
|
||||
fn destroy_scope(&mut self) -> (); |
||||
/// Run an expression
|
||||
// fn run(&mut self, expr: &Expr) -> ResultValue;
|
||||
fn run(&mut self, expr: &Expr) -> ResultValue; |
||||
} |
||||
|
||||
/// A Javascript intepreter
|
||||
pub struct Interpreter { |
||||
/// An object representing the global object
|
||||
global: Value, |
||||
/// The variable scopes
|
||||
scopes: Vec<GcCell<RefCell<ObjectData>>>, |
||||
} |
||||
|
||||
impl Executor for Interpreter { |
||||
fn new() -> Interpreter { |
||||
let global = ValueData::new_obj(None); |
||||
object::init(global); |
||||
function::init(global); |
||||
json::init(global); |
||||
Interpreter { |
||||
global: global, |
||||
scopes: Vec::new(), |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,110 @@
|
||||
use exec::Interpreter; |
||||
use gc::GcCell; |
||||
use js::object::{ObjectData, Property}; |
||||
use js::value::{to_value, ResultValue, Value, ValueData}; |
||||
use std::collections::HashMap; |
||||
use syntax::ast::expr::Expr; |
||||
/// A Javascript function
|
||||
/// A member of the Object type that may be invoked as a subroutine
|
||||
/// https://tc39.github.io/ecma262/#sec-terms-and-definitions-function
|
||||
pub enum Function { |
||||
/// A native javascript function
|
||||
NativeFunc(NativeFunction), |
||||
/// A regular javascript function
|
||||
RegularFunc(RegularFunction), |
||||
} |
||||
|
||||
impl Function { |
||||
/// Call a function with some arguments
|
||||
pub fn call( |
||||
&self, |
||||
exe: &mut Interpreter, |
||||
this: Value, |
||||
callee: Value, |
||||
args: Vec<Value>, |
||||
) -> ResultValue { |
||||
match *self { |
||||
Function::NativeFunc(ref ntv) => { |
||||
let func = ntv.data; |
||||
func(this, callee, args) |
||||
} |
||||
Function::RegularFunc(ref data) => { |
||||
let scope = exe.make_scope(); |
||||
scope |
||||
.borrow() |
||||
.borrow_mut() |
||||
.insert("this".to_string(), Property::new(this)); |
||||
for i in 0..data.args.len() { |
||||
let name = data.args.get(i); |
||||
let expr = args.get(i); |
||||
scope |
||||
.borrow() |
||||
.borrow_mut() |
||||
.insert(name.to_string(), Property::new(*expr)); |
||||
} |
||||
let result = exe.run(&data.expr); |
||||
exe.destroy_scope(); |
||||
result |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Represents a regular javascript function in memory
|
||||
/// A member of the Object type that may be invoked as a subroutine
|
||||
pub struct RegularFunction { |
||||
/// The fields associated with the function
|
||||
pub object: ObjectData, |
||||
/// This function's expression
|
||||
pub expr: Expr, |
||||
/// The argument names of the function
|
||||
pub args: Vec<String>, |
||||
} |
||||
|
||||
impl RegularFunction { |
||||
/// Make a new regular function
|
||||
pub fn new(expr: Expr, args: Vec<String>) -> RegularFunction { |
||||
let mut obj = HashMap::new(); |
||||
obj.insert( |
||||
"arguments".to_string(), |
||||
Property::new(GcCell::new(ValueData::Integer(args.len() as i32))), |
||||
); |
||||
RegularFunction { |
||||
object: obj, |
||||
expr: expr, |
||||
args: args, |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub type NativeFunctionData = fn(Value, Value, Vec<Value>) -> ResultValue; |
||||
|
||||
/// Represents a native javascript function in memory
|
||||
pub struct NativeFunction { |
||||
/// The fields associated with the function
|
||||
pub object: ObjectData, |
||||
/// The callable function data
|
||||
pub data: NativeFunctionData, |
||||
} |
||||
impl NativeFunction { |
||||
/// Make a new native function with the given function data
|
||||
pub fn new(data: NativeFunctionData) -> NativeFunction { |
||||
let obj = HashMap::new(); |
||||
NativeFunction { |
||||
object: obj, |
||||
data: data, |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Create a new `Function` object
|
||||
pub fn _create() -> Value { |
||||
let function: ObjectData = HashMap::new(); |
||||
to_value(function) |
||||
} |
||||
|
||||
/// Initialise the global object with the `Function` object
|
||||
pub fn init(global: Value) { |
||||
let global_ptr = global.borrow(); |
||||
global_ptr.set_field_slice("Function", _create(global)); |
||||
} |
@ -0,0 +1,34 @@
|
||||
/// The JSON Object
|
||||
/// https://tc39.github.io/ecma262/#sec-json-object
|
||||
use gc::GcCell; |
||||
use js::value::{to_value, ResultValue, Value, ValueData}; |
||||
|
||||
/// Parse a JSON string into a Javascript object
|
||||
/// https://tc39.github.io/ecma262/#sec-json.parse
|
||||
pub fn parse(args: Vec<Value>) -> ResultValue { |
||||
match serde_json::from_str(args.get(0).borrow().to_str().as_slice()) { |
||||
Ok(json) => Ok(GcCell::new(ValueData::from_json(json))), |
||||
Err(err) => Err(GcCell::new(Value::String(err.to_str()))), |
||||
} |
||||
} |
||||
/// Process a Javascript object into a JSON string
|
||||
pub fn stringify(args: Vec<Value>) -> ResultValue { |
||||
let obj = args.get(0); |
||||
let json = serde_json::to_string_pretty(obj.borrow()).unwrap(); |
||||
Ok(GcCell::new(Value::String(json.to_pretty_str()))) |
||||
} |
||||
|
||||
/// Create a new `JSON` object
|
||||
pub fn _create(global: Value) -> Value { |
||||
let object = ValueData::new_obj(Some(global)); |
||||
let object_ptr = object.borrow(); |
||||
object_ptr.set_field_slice("stringify", to_value(stringify)); |
||||
object_ptr.set_field_slice("parse", to_value(parse)); |
||||
object |
||||
} |
||||
|
||||
/// Initialise the global object with the `JSON` object
|
||||
pub fn init(global: Value) { |
||||
let global_ptr = global.borrow(); |
||||
global_ptr.set_field_slice("JSON", _create(global)); |
||||
} |
Loading…
Reference in new issue