-
-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added
RangeError
generation and modularized New
and Call
nodes
- Loading branch information
Showing
13 changed files
with
265 additions
and
177 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
//! Expression execution. | ||
use super::{Executable, Interpreter}; | ||
use crate::{ | ||
builtins::{ | ||
object::{INSTANCE_PROTOTYPE, PROTOTYPE}, | ||
value::{ResultValue, Value, ValueData}, | ||
}, | ||
syntax::ast::node::{Call, New, Node}, | ||
}; | ||
|
||
impl Executable for Call { | ||
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { | ||
let (mut this, func) = match self.expr() { | ||
Node::GetConstField(ref obj, ref field) => { | ||
let mut obj = obj.run(interpreter)?; | ||
if obj.get_type() != "object" || obj.get_type() != "symbol" { | ||
obj = interpreter | ||
.to_object(&obj) | ||
.expect("failed to convert to object"); | ||
} | ||
(obj.clone(), obj.get_field(field)) | ||
} | ||
Node::GetField(ref obj, ref field) => { | ||
let obj = obj.run(interpreter)?; | ||
let field = field.run(interpreter)?; | ||
(obj.clone(), obj.get_field(field.to_string())) | ||
} | ||
_ => ( | ||
interpreter.realm().global_obj.clone(), | ||
self.expr().run(interpreter)?, | ||
), // 'this' binding should come from the function's self-contained environment | ||
}; | ||
let mut v_args = Vec::with_capacity(self.args().len()); | ||
for arg in self.args() { | ||
if let Node::Spread(ref x) = arg { | ||
let val = x.run(interpreter)?; | ||
let mut vals = interpreter.extract_array_properties(&val).unwrap(); | ||
v_args.append(&mut vals); | ||
break; // after spread we don't accept any new arguments | ||
} | ||
v_args.push(arg.run(interpreter)?); | ||
} | ||
|
||
// execute the function call itself | ||
let fnct_result = interpreter.call(&func, &mut this, &v_args); | ||
|
||
// unset the early return flag | ||
interpreter.is_return = false; | ||
|
||
fnct_result | ||
} | ||
} | ||
|
||
impl Executable for New { | ||
fn run(&self, interpreter: &mut Interpreter) -> ResultValue { | ||
// let (callee, args) = match call.as_ref() { | ||
// Node::Call(callee, args) => (callee, args), | ||
// _ => unreachable!("Node::New(ref call): 'call' must only be Node::Call type."), | ||
// }; | ||
|
||
let func_object = self.expr().run(interpreter)?; | ||
let mut v_args = Vec::with_capacity(self.args().len()); | ||
for arg in self.args() { | ||
v_args.push(arg.run(interpreter)?); | ||
} | ||
let mut this = Value::new_object(None); | ||
// Create a blank object, then set its __proto__ property to the [Constructor].prototype | ||
this.set_internal_slot(INSTANCE_PROTOTYPE, func_object.get_field(PROTOTYPE)); | ||
|
||
match func_object.data() { | ||
ValueData::Object(ref o) => o.clone().borrow_mut().func.as_ref().unwrap().construct( | ||
&mut func_object.clone(), | ||
&v_args, | ||
interpreter, | ||
&mut this, | ||
), | ||
_ => Ok(Value::undefined()), | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
//! Expression nodes. | ||
use super::{join_nodes, Node}; | ||
use gc::{Finalize, Trace}; | ||
use std::fmt; | ||
|
||
#[cfg(feature = "serde")] | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Calling the function actually performs the specified actions with the indicated parameters. | ||
/// | ||
/// Defining a function does not execute it. Defining it simply names the function and | ||
/// specifies what to do when the function is called. Functions must be in scope when they are | ||
/// called, but the function declaration can be hoisted. The scope of a function is the | ||
/// function in which it is declared (or the entire program, if it is declared at the top | ||
/// level). | ||
/// | ||
/// More information: | ||
/// - [ECMAScript reference][spec] | ||
/// - [MDN documentation][mdn] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#prod-CallExpression | ||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] | ||
pub struct Call { | ||
expr: Box<Node>, | ||
args: Box<[Node]>, | ||
} | ||
|
||
impl Call { | ||
/// Creates a new `Call` AST node. | ||
pub fn new<E, A>(expr: E, args: A) -> Self | ||
where | ||
E: Into<Node>, | ||
A: Into<Box<[Node]>>, | ||
{ | ||
Self { | ||
expr: Box::new(expr.into()), | ||
args: args.into(), | ||
} | ||
} | ||
|
||
/// Gets the name of the function call. | ||
pub fn expr(&self) -> &Node { | ||
&self.expr | ||
} | ||
|
||
/// Retrieves the arguments passed to the function. | ||
pub fn args(&self) -> &[Node] { | ||
&self.args | ||
} | ||
} | ||
|
||
impl fmt::Display for Call { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}(", self.expr)?; | ||
join_nodes(f, &self.args)?; | ||
f.write_str(")") | ||
} | ||
} | ||
|
||
impl From<Call> for Node { | ||
fn from(call: Call) -> Self { | ||
Self::Call(call) | ||
} | ||
} | ||
|
||
/// The `new` operator lets developers create an instance of a user-defined object type or of | ||
/// one of the built-in object types that has a constructor function. | ||
/// | ||
/// The new keyword does the following things: | ||
/// - Creates a blank, plain JavaScript object; | ||
/// - Links (sets the constructor of) this object to another object; | ||
/// - Passes the newly created object from Step 1 as the this context; | ||
/// - Returns this if the function doesn't return its own object. | ||
/// | ||
/// More information: | ||
/// - [ECMAScript reference][spec] | ||
/// - [MDN documentation][mdn] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#prod-NewExpression | ||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] | ||
pub struct New { | ||
call: Call, | ||
} | ||
|
||
impl New { | ||
/// Gets the name of the function call. | ||
pub fn expr(&self) -> &Node { | ||
&self.call.expr() | ||
} | ||
|
||
/// Retrieves the arguments passed to the function. | ||
pub fn args(&self) -> &[Node] { | ||
&self.call.args() | ||
} | ||
} | ||
|
||
impl From<Call> for New { | ||
fn from(call: Call) -> Self { | ||
Self { call } | ||
} | ||
} | ||
|
||
impl fmt::Display for New { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "new {}", self.call) | ||
} | ||
} | ||
|
||
impl From<New> for Node { | ||
fn from(new: New) -> Self { | ||
Self::New(new) | ||
} | ||
} |
Oops, something went wrong.