Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Added Try/Catch parsing #263

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 85 additions & 147 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions boa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ default = ["wasm-bindgen"]
[dependencies]
gc = "0.3.3"
gc_derive = "0.3.2"
serde_json = "1.0.46"
serde_json = "1.0.48"
rand = "0.7.3"
regex = "1.3.4"

# Optional Dependencies
wasm-bindgen = { version = "0.2.58", optional = true }
wasm-bindgen = { version = "0.2.59", optional = true }

[dev-dependencies]
criterion = "0.3.1"
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,15 +855,15 @@ impl Display for ValueData {
ValueData::Function(ref v) => match *v.borrow() {
Function::NativeFunc(_) => write!(f, "function() {{ [native code] }}"),
Function::RegularFunc(ref rf) => {
write!(f, "function(")?;
write!(f, "function{}(", if rf.args.is_empty() { "" } else { " " })?;
let last_index = rf.args.len() - 1;
for (index, arg) in rf.args.iter().enumerate() {
write!(f, "{}", arg)?;
if index != last_index {
write!(f, ", ")?;
}
}
write!(f, "){}", rf.expr)
write!(f, ") {}", rf.expr)
}
},
}
Expand Down
37 changes: 35 additions & 2 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,39 @@ impl Executor for Interpreter {
ValueData::Function(_) => "function",
}))
}
// <tc39.es/ecma262/#sec-try-statement>
ExprDef::TryCatch(ref try_block, ref catch_expr, ref finally_block) => {
if let Err(val) = self.run(try_block) {
if let Some((catch_bind, catch_block)) = catch_expr {
{
let env = &mut self.realm.environment;
env.push(new_declarative_environment(Some(
env.get_current_environment_ref().clone(),
)));
}

if let Some(catch_bind) = catch_bind {
self.realm.environment.create_mutable_binding(
catch_bind.clone(),
false,
VariableScope::Block,
);

self.realm.environment.initialize_binding(catch_bind, val);
}

todo!("run the catch block");
} else {
return Err(val);
}
}

if let Some(expr) = finally_block {
self.run(expr)?;
}

Ok(Gc::new(ValueData::Undefined))
}
}
}
}
Expand All @@ -520,7 +553,7 @@ impl Interpreter {
&self.realm
}

/// https://tc39.es/ecma262/#sec-call
/// <https://tc39.es/ecma262/#sec-call>
pub(crate) fn call(&mut self, f: &Value, v: &Value, arguments_list: Vec<Value>) -> ResultValue {
// All functions should be objects, and eventually will be.
// During this transition call will support both native functions and function objects
Expand Down Expand Up @@ -764,7 +797,7 @@ impl Interpreter {
}
}

/// `extract_array_properties` converts an array object into a rust vector of Values.
/// `extract_array_properties` converts an array object into a rust vector of Values.
/// This is useful for the spread operator, for any other object an `Err` is returned
fn extract_array_properties(&mut self, value: &Value) -> Result<Vec<Gc<ValueData>>, ()> {
if let ValueData::Object(ref x) = *value.deref().borrow() {
Expand Down
162 changes: 108 additions & 54 deletions boa/src/syntax/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,18 @@ pub enum ExprDef {
Throw(Box<Expr>),
/// Assign an expression to a value
Assign(Box<Expr>, Box<Expr>),
/// {
/// A variable declaratio
/// }
/// A variable declaration
VarDecl(Vec<(String, Option<Expr>)>),
/// Let declaraton
LetDecl(Vec<(String, Option<Expr>)>),
/// Return a string representing the type of the given expression
TypeOf(Box<Expr>),
/// Try...catch...finally block.
TryCatch(
Box<Expr>,
Option<(Option<String>, Box<Expr>)>,
Option<Box<Expr>>,
),
}

impl Operator for ExprDef {
Expand Down Expand Up @@ -114,115 +118,165 @@ impl Operator for ExprDef {

impl Display for ExprDef {
fn fmt(&self, f: &mut Formatter) -> Result {
self.display(f, 0)
}
}

impl ExprDef {
fn display(&self, f: &mut Formatter, indentation: usize) -> Result {
let indent = " ".repeat(indentation);
match *self {
ExprDef::Const(ref c) => write!(f, "{}", c),
ExprDef::Block(ref block) => {
write!(f, "{{")?;
Self::Block(_) => {}
_ => write!(f, "{}", indent)?,
}

match *self {
Self::Const(ref c) => write!(f, "{}", c),
Self::Block(ref block) => {
writeln!(f, "{{")?;
for expr in block.iter() {
write!(f, "{};", expr)?;
expr.def.display(f, indentation + 1)?;

match expr.def {
Self::Block(_)
| Self::If(_, _, _)
| Self::Switch(_, _, _)
| Self::FunctionDecl(_, _, _)
| Self::WhileLoop(_, _)
| Self::TryCatch(_, _, _) => {}
_ => write!(f, ";")?,
}
writeln!(f)?;
}
write!(f, "}}")
write!(f, "{}}}", indent)
}
ExprDef::Local(ref s) => write!(f, "{}", s),
ExprDef::GetConstField(ref ex, ref field) => write!(f, "{}.{}", ex, field),
ExprDef::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field),
ExprDef::Call(ref ex, ref args) => {
Self::Local(ref s) => write!(f, "{}", s),
Self::GetConstField(ref ex, ref field) => write!(f, "{}.{}", ex, field),
Self::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field),
Self::Call(ref ex, ref args) => {
write!(f, "{}(", ex)?;
let arg_strs: Vec<String> = args.iter().map(ToString::to_string).collect();
write!(f, "{})", arg_strs.join(","))
write!(f, "{})", arg_strs.join(", "))
}
ExprDef::Construct(ref func, ref args) => {
f.write_fmt(format_args!("new {}", func))?;
Self::Construct(ref func, ref args) => {
write!(f, "new {}", func)?;
f.write_str("(")?;
let mut first = true;
for e in args.iter() {
if !first {
f.write_str(", ")?;
first = false;
}
first = false;

Display::fmt(e, f)?;
}
f.write_str(")")
}
ExprDef::WhileLoop(ref cond, ref expr) => write!(f, "while({}) {}", cond, expr),
ExprDef::If(ref cond, ref expr, None) => write!(f, "if({}) {}", cond, expr),
ExprDef::If(ref cond, ref expr, Some(ref else_e)) => {
write!(f, "if({}) {} else {}", cond, expr, else_e)
Self::WhileLoop(ref cond, ref expr) => {
write!(f, "while ({}) ", cond)?;
expr.def.display(f, indentation)
}
ExprDef::Switch(ref val, ref vals, None) => {
f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?;
Self::If(ref cond, ref expr, None) => {
write!(f, "if ({}) ", cond)?;
expr.def.display(f, indentation)
}
Self::If(ref cond, ref expr, Some(ref else_e)) => {
write!(f, "if ({}) ", cond)?;
expr.def.display(f, indentation)?;
f.write_str(" else ")?;
else_e.def.display(f, indentation)
}
Self::Switch(ref val, ref vals, None) => {
writeln!(f, "switch ({}) {{", val)?;
for e in vals.iter() {
f.write_fmt(format_args!("case {}: \n", e.0))?;
writeln!(f, "{}case {}:", indent, e.0)?;
join_expr(f, &e.1)?;
}
f.write_str("}")
writeln!(f, "{}}}", indent)
}
ExprDef::Switch(ref val, ref vals, Some(ref def)) => {
f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?;
Self::Switch(ref val, ref vals, Some(ref def)) => {
writeln!(f, "switch ({}) {{", val)?;
for e in vals.iter() {
f.write_fmt(format_args!("case {}: \n", e.0))?;
writeln!(f, "{}case {}:", indent, e.0)?;
join_expr(f, &e.1)?;
}
f.write_str("default: \n")?;
Display::fmt(def, f)?;
f.write_str("}")
writeln!(f, "{}default:", indent)?;
def.def.display(f, indentation + 1)?;
write!(f, "{}}}", indent)
}
ExprDef::ObjectDecl(ref map) => {
f.write_str("{")?;
Self::ObjectDecl(ref map) => {
f.write_str("{\n")?;
for (key, value) in map.iter() {
f.write_fmt(format_args!("{}: {},", key, value))?;
write!(f, "{} {}: {},", indent, key, value)?;
}
f.write_str("}")
}
ExprDef::ArrayDecl(ref arr) => {
Self::ArrayDecl(ref arr) => {
f.write_str("[")?;
join_expr(f, arr)?;
f.write_str("]")
}
ExprDef::FunctionDecl(ref name, ref args, ref expr) => {
Self::FunctionDecl(ref name, ref args, ref expr) => {
write!(f, "function ")?;
if let Some(func_name) = name {
f.write_fmt(format_args!("{}", func_name))?;
write!(f, "{}", func_name)?;
}
write!(f, "{{")?;
join_expr(f, args)?;
write!(f, "}} {}", expr)
f.write_str("} ")?;
expr.def.display(f, indentation + 1)
}
ExprDef::ArrowFunctionDecl(ref args, ref expr) => {
Self::ArrowFunctionDecl(ref args, ref expr) => {
write!(f, "(")?;
join_expr(f, args)?;
write!(f, ") => {}", expr)
f.write_str(") => ")?;
expr.def.display(f, indentation)
}
ExprDef::BinOp(ref op, ref a, ref b) => write!(f, "{} {} {}", a, op, b),
ExprDef::UnaryOp(ref op, ref a) => write!(f, "{}{}", op, a),
ExprDef::Return(Some(ref ex)) => write!(f, "return {}", ex),
ExprDef::Return(None) => write!(f, "return"),
ExprDef::Throw(ref ex) => write!(f, "throw {}", ex),
ExprDef::Assign(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val),
ExprDef::VarDecl(ref vars) | ExprDef::LetDecl(ref vars) => {
if let ExprDef::VarDecl(_) = *self {
Self::BinOp(ref op, ref a, ref b) => write!(f, "{} {} {}", a, op, b),
Self::UnaryOp(ref op, ref a) => write!(f, "{}{}", op, a),
Self::Return(Some(ref ex)) => write!(f, "return {}", ex),
Self::Return(None) => write!(f, "return"),
Self::Throw(ref ex) => write!(f, "throw {}", ex),
Self::Assign(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val),
Self::VarDecl(ref vars) | Self::LetDecl(ref vars) => {
if let Self::VarDecl(_) = *self {
f.write_str("var ")?;
} else {
f.write_str("let ")?;
}
for (key, val) in vars.iter() {
match val {
Some(x) => f.write_fmt(format_args!("{} = {}", key, x))?,
None => f.write_fmt(format_args!("{}", key))?,
Some(x) => write!(f, "{} = {}", key, x)?,
None => write!(f, "{}", key)?,
}
}
Ok(())
}
ExprDef::ConstDecl(ref vars) => {
Self::ConstDecl(ref vars) => {
f.write_str("const ")?;
for (key, val) in vars.iter() {
f.write_fmt(format_args!("{} = {}", key, val))?
write!(f, "{} = {}", key, val)?
}
Ok(())
}
Self::TypeOf(ref e) => write!(f, "typeof {}", e),
Self::TryCatch(ref try_block, ref catch_block, ref finally_block) => {
f.write_str("try ")?;
try_block.def.display(f, indentation)?;
if let Some((catch_binding, catch_expr)) = catch_block {
f.write_str(" catch ")?;
if let Some(exc) = catch_binding {
write!(f, "({}) ", exc)?;
}
catch_expr.def.display(f, indentation)?;
}
if let Some(finally) = finally_block {
f.write_str(" finally ")?;
finally.def.display(f, indentation)?;
}

Ok(())
}
ExprDef::TypeOf(ref e) => write!(f, "typeof {}", e),
}
}
}
Expand Down
Loading