From 3aacba0ddfceac5fd8dbf9bfde42f244ae8bce4b Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sun, 12 Feb 2023 03:05:29 +0100 Subject: [PATCH] Remove Syntax Errors from Bytecompiler --- boa_ast/src/operations.rs | 354 +++++++++++++++++- boa_engine/src/builtins/eval/mod.rs | 2 +- boa_engine/src/builtins/function/mod.rs | 6 +- boa_engine/src/builtins/json/mod.rs | 2 +- boa_engine/src/bytecompiler/class.rs | 130 +++---- .../declaration/declaration_pattern.rs | 43 +-- .../src/bytecompiler/expression/assign.rs | 48 ++- .../src/bytecompiler/expression/binary.rs | 32 +- boa_engine/src/bytecompiler/expression/mod.rs | 88 ++--- .../bytecompiler/expression/object_literal.rs | 70 ++-- .../src/bytecompiler/expression/unary.rs | 13 +- .../src/bytecompiler/expression/update.rs | 25 +- boa_engine/src/bytecompiler/function.rs | 14 +- boa_engine/src/bytecompiler/mod.rs | 197 ++++------ boa_engine/src/bytecompiler/module.rs | 22 +- .../src/bytecompiler/statement/block.rs | 8 +- .../src/bytecompiler/statement/break.rs | 45 +-- .../src/bytecompiler/statement/continue.rs | 40 +- boa_engine/src/bytecompiler/statement/if.rs | 12 +- .../src/bytecompiler/statement/labelled.rs | 28 +- boa_engine/src/bytecompiler/statement/loop.rs | 69 ++-- boa_engine/src/bytecompiler/statement/mod.rs | 42 +-- .../src/bytecompiler/statement/switch.rs | 19 +- boa_engine/src/bytecompiler/statement/try.rs | 39 +- boa_engine/src/context/mod.rs | 19 +- boa_engine/src/tests.rs | 9 +- boa_parser/src/parser/function/mod.rs | 24 +- boa_parser/src/parser/mod.rs | 25 +- .../src/parser/statement/break_stm/tests.rs | 73 ++-- .../parser/statement/continue_stm/tests.rs | 73 ++-- .../declaration/hoistable/class_decl/mod.rs | 24 +- boa_parser/src/parser/statement/mod.rs | 22 +- 32 files changed, 895 insertions(+), 722 deletions(-) diff --git a/boa_ast/src/operations.rs b/boa_ast/src/operations.rs index 14ebb9a5a06..525f5fdb078 100644 --- a/boa_ast/src/operations.rs +++ b/boa_ast/src/operations.rs @@ -5,7 +5,7 @@ use core::ops::ControlFlow; use std::convert::Infallible; -use boa_interner::Sym; +use boa_interner::{Interner, Sym}; use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ @@ -848,3 +848,355 @@ pub fn class_private_name_resolver(node: &mut Class, top_level_class_index: usiz visitor.visit_class_mut(node).is_continue() } + +/// This function checks multiple syntax errors conditions for labels, `break` and `continue`. +/// +/// The following syntax errors are checked: +/// - [`ContainsDuplicateLabels`][https://tc39.es/ecma262/#sec-static-semantics-containsduplicatelabels] +/// - [`ContainsUndefinedBreakTarget`][https://tc39.es/ecma262/#sec-static-semantics-containsundefinedbreaktarget] +/// - [`ContainsUndefinedContinueTarget`][https://tc39.es/ecma262/#sec-static-semantics-containsundefinedcontinuetarget] +/// - Early errors for [`BreakStatement`][https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors] +/// - Early errors for [`ContinueStatement`][https://tc39.es/ecma262/#sec-continue-statement-static-semantics-early-errors] +#[must_use] +pub fn check_labels(node: &N, interner: &Interner) -> Option +where + N: VisitWith, +{ + enum CheckLabelsError { + DuplicateLabel(Sym), + UndefinedBreakTarget(Sym), + UndefinedContinueTarget(Sym), + IllegalBreakStatement, + IllegalContinueStatement, + } + + #[derive(Debug, Clone)] + struct CheckLabelsResolver { + labels: FxHashSet, + continue_iteration_labels: FxHashSet, + continue_labels: Option>, + iteration: bool, + switch: bool, + } + + impl<'ast> Visitor<'ast> for CheckLabelsResolver { + type BreakTy = CheckLabelsError; + + fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow { + match node { + Statement::Block(node) => self.visit_block(node), + Statement::Var(_) + | Statement::Empty + | Statement::Expression(_) + | Statement::Return(_) + | Statement::Throw(_) => ControlFlow::Continue(()), + Statement::If(node) => self.visit_if(node), + Statement::DoWhileLoop(node) => self.visit_do_while_loop(node), + Statement::WhileLoop(node) => self.visit_while_loop(node), + Statement::ForLoop(node) => self.visit_for_loop(node), + Statement::ForInLoop(node) => self.visit_for_in_loop(node), + Statement::ForOfLoop(node) => self.visit_for_of_loop(node), + Statement::Switch(node) => self.visit_switch(node), + Statement::Labelled(node) => self.visit_labelled(node), + Statement::Try(node) => self.visit_try(node), + Statement::Continue(node) => self.visit_continue(node), + Statement::Break(node) => self.visit_break(node), + } + } + + fn visit_block( + &mut self, + node: &'ast crate::statement::Block, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + try_break!(self.visit_statement_list(node.statement_list())); + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_break( + &mut self, + node: &'ast crate::statement::Break, + ) -> ControlFlow { + if let Some(label) = node.label() { + if !self.labels.contains(&label) { + return ControlFlow::Break(CheckLabelsError::UndefinedBreakTarget(label)); + } + } else if !self.iteration && !self.switch { + return ControlFlow::Break(CheckLabelsError::IllegalBreakStatement); + } + ControlFlow::Continue(()) + } + + fn visit_continue( + &mut self, + node: &'ast crate::statement::Continue, + ) -> ControlFlow { + if !self.iteration { + return ControlFlow::Break(CheckLabelsError::IllegalContinueStatement); + } + + if let Some(label) = node.label() { + if !self.continue_iteration_labels.contains(&label) { + return ControlFlow::Break(CheckLabelsError::UndefinedContinueTarget(label)); + } + } + ControlFlow::Continue(()) + } + + fn visit_do_while_loop( + &mut self, + node: &'ast crate::statement::DoWhileLoop, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let continue_iteration_labels = self.continue_iteration_labels.clone(); + if let Some(continue_labels) = &continue_labels { + self.continue_iteration_labels.extend(continue_labels); + } + let iteration = self.iteration; + self.iteration = true; + try_break!(self.visit_statement(node.body())); + self.continue_iteration_labels = continue_iteration_labels; + self.continue_labels = continue_labels; + self.iteration = iteration; + ControlFlow::Continue(()) + } + + fn visit_while_loop( + &mut self, + node: &'ast crate::statement::WhileLoop, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let continue_iteration_labels = self.continue_iteration_labels.clone(); + if let Some(continue_labels) = &continue_labels { + self.continue_iteration_labels.extend(continue_labels); + } + let iteration = self.iteration; + self.iteration = true; + try_break!(self.visit_statement(node.body())); + self.continue_iteration_labels = continue_iteration_labels; + self.continue_labels = continue_labels; + self.iteration = iteration; + ControlFlow::Continue(()) + } + + fn visit_for_loop( + &mut self, + node: &'ast crate::statement::ForLoop, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let continue_iteration_labels = self.continue_iteration_labels.clone(); + if let Some(continue_labels) = &continue_labels { + self.continue_iteration_labels.extend(continue_labels); + } + let iteration = self.iteration; + self.iteration = true; + try_break!(self.visit_statement(node.body())); + self.continue_iteration_labels = continue_iteration_labels; + self.continue_labels = continue_labels; + self.iteration = iteration; + ControlFlow::Continue(()) + } + + fn visit_for_in_loop( + &mut self, + node: &'ast crate::statement::ForInLoop, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let continue_iteration_labels = self.continue_iteration_labels.clone(); + if let Some(continue_labels) = &continue_labels { + self.continue_iteration_labels.extend(continue_labels); + } + let iteration = self.iteration; + self.iteration = true; + try_break!(self.visit_statement(node.body())); + self.continue_iteration_labels = continue_iteration_labels; + self.continue_labels = continue_labels; + self.iteration = iteration; + ControlFlow::Continue(()) + } + + fn visit_for_of_loop( + &mut self, + node: &'ast crate::statement::ForOfLoop, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let continue_iteration_labels = self.continue_iteration_labels.clone(); + if let Some(continue_labels) = &continue_labels { + self.continue_iteration_labels.extend(continue_labels); + } + let iteration = self.iteration; + self.iteration = true; + try_break!(self.visit_statement(node.body())); + self.continue_iteration_labels = continue_iteration_labels; + self.continue_labels = continue_labels; + self.iteration = iteration; + ControlFlow::Continue(()) + } + + fn visit_statement_list_item( + &mut self, + node: &'ast StatementListItem, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + if let StatementListItem::Statement(stmt) = node { + try_break!(self.visit_statement(stmt)); + } + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + try_break!(self.visit_statement(node.body())); + if let Some(stmt) = node.else_node() { + try_break!(self.visit_statement(stmt)); + } + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_switch( + &mut self, + node: &'ast crate::statement::Switch, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + let switch = self.switch; + self.switch = true; + for case in node.cases() { + try_break!(self.visit_statement_list(case.body())); + } + if let Some(default) = node.default() { + try_break!(self.visit_statement_list(default)); + } + self.continue_labels = continue_labels; + self.switch = switch; + ControlFlow::Continue(()) + } + + fn visit_labelled( + &mut self, + node: &'ast crate::statement::Labelled, + ) -> ControlFlow { + let continue_labels = self.continue_labels.clone(); + if let Some(continue_labels) = &mut self.continue_labels { + continue_labels.insert(node.label()); + } else { + let mut continue_labels = FxHashSet::default(); + continue_labels.insert(node.label()); + self.continue_labels = Some(continue_labels); + } + + if !self.labels.insert(node.label()) { + return ControlFlow::Break(CheckLabelsError::DuplicateLabel(node.label())); + } + try_break!(self.visit_labelled_item(node.item())); + self.labels.remove(&node.label()); + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { + match node { + LabelledItem::Statement(stmt) => self.visit_statement(stmt), + LabelledItem::Function(_) => ControlFlow::Continue(()), + } + } + + fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + try_break!(self.visit_block(node.block())); + if let Some(catch) = node.catch() { + try_break!(self.visit_block(catch.block())); + } + if let Some(finally) = node.finally() { + try_break!(self.visit_block(finally.block())); + } + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_module_item_list( + &mut self, + node: &'ast crate::ModuleItemList, + ) -> ControlFlow { + let continue_labels = self.continue_labels.take(); + for item in node.items() { + try_break!(self.visit_module_item(item)); + } + self.continue_labels = continue_labels; + ControlFlow::Continue(()) + } + + fn visit_module_item( + &mut self, + node: &'ast crate::ModuleItem, + ) -> ControlFlow { + match node { + crate::ModuleItem::ImportDeclaration(_) + | crate::ModuleItem::ExportDeclaration(_) => ControlFlow::Continue(()), + crate::ModuleItem::StatementListItem(node) => self.visit_statement_list_item(node), + } + } + } + + let mut visitor = CheckLabelsResolver { + labels: FxHashSet::default(), + continue_iteration_labels: FxHashSet::default(), + continue_labels: None, + iteration: false, + switch: false, + }; + + if let ControlFlow::Break(error) = node.visit_with(&mut visitor) { + let msg = match error { + CheckLabelsError::DuplicateLabel(label) => { + format!("duplicate label: {}", interner.resolve_expect(label)) + } + CheckLabelsError::UndefinedBreakTarget(label) => { + format!("undefined break target: {}", interner.resolve_expect(label)) + } + CheckLabelsError::UndefinedContinueTarget(label) => format!( + "undefined continue target: {}", + interner.resolve_expect(label) + ), + CheckLabelsError::IllegalBreakStatement => "illegal break statement".into(), + CheckLabelsError::IllegalContinueStatement => "illegal continue statement".into(), + }; + + Some(msg) + } else { + None + } +} + +/// Returns `true` if the given node contains a `CoverInitializedName`. +#[must_use] +pub fn contains_invalid_object_literal(node: &N) -> bool +where + N: VisitWith, +{ + #[derive(Debug, Clone)] + struct ContainsInvalidObjectLiteral {} + + impl<'ast> Visitor<'ast> for ContainsInvalidObjectLiteral { + type BreakTy = (); + + fn visit_object_literal( + &mut self, + node: &'ast crate::expression::literal::ObjectLiteral, + ) -> ControlFlow { + for pd in node.properties() { + if let PropertyDefinition::CoverInitializedName(..) = pd { + return ControlFlow::Break(()); + } + try_break!(self.visit_property_definition(pd)); + } + ControlFlow::Continue(()) + } + } + + let mut visitor = ContainsInvalidObjectLiteral {}; + + node.visit_with(&mut visitor).is_break() +} diff --git a/boa_engine/src/builtins/eval/mod.rs b/boa_engine/src/builtins/eval/mod.rs index 242216d0a0d..d246c9c8e8e 100644 --- a/boa_engine/src/builtins/eval/mod.rs +++ b/boa_engine/src/builtins/eval/mod.rs @@ -250,7 +250,7 @@ impl Eval { // TODO: check if private identifiers inside `eval` are valid. // Compile and execute the eval statement list. - let code_block = context.compile_with_new_declarative(&body, strict)?; + let code_block = context.compile_with_new_declarative(&body, strict); // Indirect calls don't need extensions, because a non-strict indirect call modifies only // the global object. // Strict direct calls also don't need extensions, since all strict eval calls push a new diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index 2676d8585b1..adc2c8f2b9f 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -605,7 +605,7 @@ impl BuiltInFunctionObject { .name(Sym::ANONYMOUS) .generator(generator) .r#async(r#async) - .compile(¶meters, &body, context)?; + .compile(¶meters, &body, context); let environments = context.realm.environments.pop_to_global(); @@ -633,7 +633,7 @@ impl BuiltInFunctionObject { &FormalParameterList::default(), &StatementList::default(), context, - )?; + ); let environments = context.realm.environments.pop_to_global(); let function_object = @@ -646,7 +646,7 @@ impl BuiltInFunctionObject { &FormalParameterList::default(), &StatementList::default(), context, - )?; + ); let environments = context.realm.environments.pop_to_global(); let function_object = crate::vm::create_function_object( diff --git a/boa_engine/src/builtins/json/mod.rs b/boa_engine/src/builtins/json/mod.rs index 92a328a72ff..354dd4bdd18 100644 --- a/boa_engine/src/builtins/json/mod.rs +++ b/boa_engine/src/builtins/json/mod.rs @@ -206,7 +206,7 @@ impl Json { let mut parser = Parser::new(Source::from_bytes(&script_string)); parser.set_json_parse(); let statement_list = parser.parse_script(context.interner_mut())?; - let code_block = context.compile_json_parse(&statement_list)?; + let code_block = context.compile_json_parse(&statement_list); let unfiltered = context.execute(code_block)?; // 11. If IsCallable(reviver) is true, then diff --git a/boa_engine/src/bytecompiler/class.rs b/boa_engine/src/bytecompiler/class.rs index 7cbc9fb8b6c..bd36e5d2ff8 100644 --- a/boa_engine/src/bytecompiler/class.rs +++ b/boa_engine/src/bytecompiler/class.rs @@ -1,3 +1,5 @@ +use super::{ByteCompiler, Literal, NodeKind}; +use crate::vm::{BindingOpcode, CodeBlock, Opcode}; use boa_ast::{ declaration::Binding, expression::Identifier, @@ -9,20 +11,13 @@ use boa_gc::Gc; use boa_interner::Sym; use rustc_hash::FxHashMap; -use crate::{ - vm::{BindingOpcode, CodeBlock, Opcode}, - JsResult, -}; - -use super::{ByteCompiler, Literal, NodeKind}; - impl ByteCompiler<'_, '_> { /// This function compiles a class declaration or expression. /// /// The compilation of a class declaration and expression is mostly equal. /// A class declaration binds the resulting class object to it's identifier. /// A class expression leaves the resulting class object on the stack for following operations. - pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) -> JsResult<()> { + pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) { let class_name = class.name().map_or(Sym::EMPTY_STRING, Identifier::sym); let code = CodeBlock::new(class_name, 0, true); @@ -72,7 +67,7 @@ impl ByteCompiler<'_, '_> { if let Some(init) = parameter.variable().init() { let skip = compiler.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - compiler.compile_expr(init, true)?; + compiler.compile_expr(init, true); compiler.patch_jump(skip); } compiler.emit_binding(BindingOpcode::InitArg, *ident); @@ -81,7 +76,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { compiler.context.create_mutable_binding(ident, false, false); } - compiler.compile_declaration_pattern(pattern, BindingOpcode::InitArg)?; + compiler.compile_declaration_pattern(pattern, BindingOpcode::InitArg); } } } @@ -98,7 +93,7 @@ impl ByteCompiler<'_, '_> { None }; compiler.create_script_decls(expr.body(), false); - compiler.compile_statement_list(expr.body(), false, false)?; + compiler.compile_statement_list(expr.body(), false, false); if let Some(env_label) = env_label { let (num_bindings, compile_environment) = compiler.context.pop_compile_time_environment(); @@ -142,7 +137,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); if let Some(node) = class.super_ref() { - self.compile_expr(node, true)?; + self.compile_expr(node, true); self.emit_opcode(Opcode::PushClassPrototype); } else { self.emit_opcode(Opcode::PushUndefined); @@ -158,79 +153,79 @@ impl ByteCompiler<'_, '_> { match method_definition { MethodDefinition::Get(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticGetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticGetterByValue); } }, MethodDefinition::Set(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticSetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticSetterByValue); } }, MethodDefinition::Ordinary(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticMethodByValue); } }, MethodDefinition::Async(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticMethodByValue); } }, MethodDefinition::Generator(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticMethodByValue); } }, MethodDefinition::AsyncGenerator(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassStaticMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassStaticMethodByValue); } }, @@ -241,32 +236,32 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); match method_definition { MethodDefinition::Get(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateGetter, &[index]); } MethodDefinition::Set(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateSetter, &[index]); } MethodDefinition::Ordinary(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateMethod, &[index]); } MethodDefinition::Async(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateMethod, &[index]); } MethodDefinition::Generator(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateMethod, &[index]); } MethodDefinition::AsyncGenerator(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::SetPrivateMethod, &[index]); } @@ -281,7 +276,7 @@ impl ByteCompiler<'_, '_> { )); } PropertyName::Computed(name) => { - self.compile_expr(name, true)?; + self.compile_expr(name, true); } } let field_code = CodeBlock::new(Sym::EMPTY_STRING, 0, true); @@ -302,7 +297,7 @@ impl ByteCompiler<'_, '_> { .create_immutable_binding(class_name.into(), true); field_compiler.context.push_compile_time_environment(true); if let Some(node) = field { - field_compiler.compile_expr(node, true)?; + field_compiler.compile_expr(node, true); } else { field_compiler.emit_opcode(Opcode::PushUndefined); } @@ -345,7 +340,7 @@ impl ByteCompiler<'_, '_> { .create_immutable_binding(class_name.into(), true); field_compiler.context.push_compile_time_environment(true); if let Some(node) = field { - field_compiler.compile_expr(node, true)?; + field_compiler.compile_expr(node, true); } else { field_compiler.emit_opcode(Opcode::PushUndefined); } @@ -375,7 +370,7 @@ impl ByteCompiler<'_, '_> { Some(self.get_or_insert_name((*name).into())) } PropertyName::Computed(name) => { - self.compile_expr(name, true)?; + self.compile_expr(name, true); self.emit_opcode(Opcode::Swap); None } @@ -398,7 +393,7 @@ impl ByteCompiler<'_, '_> { .create_immutable_binding(class_name.into(), true); field_compiler.context.push_compile_time_environment(true); if let Some(node) = field { - field_compiler.compile_expr(node, true)?; + field_compiler.compile_expr(node, true); } else { field_compiler.emit_opcode(Opcode::PushUndefined); } @@ -429,7 +424,7 @@ impl ByteCompiler<'_, '_> { ClassElement::PrivateStaticFieldDefinition(name, field) => { self.emit_opcode(Opcode::Dup); if let Some(node) = field { - self.compile_expr(node, true)?; + self.compile_expr(node, true); } else { self.emit_opcode(Opcode::PushUndefined); } @@ -446,7 +441,7 @@ impl ByteCompiler<'_, '_> { .create_immutable_binding(class_name.into(), true); compiler.context.push_compile_time_environment(true); compiler.create_script_decls(statement_list, false); - compiler.compile_statement_list(statement_list, false, false)?; + compiler.compile_statement_list(statement_list, false, false); let (num_bindings, compile_environment) = compiler.context.pop_compile_time_environment(); compiler.push_compile_environment(compile_environment); @@ -468,32 +463,32 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); match method_definition { MethodDefinition::Get(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateGetter, &[index]); } MethodDefinition::Set(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateSetter, &[index]); } MethodDefinition::Ordinary(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateMethod, &[index]); } MethodDefinition::Async(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateMethod, &[index]); } MethodDefinition::Generator(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateMethod, &[index]); } MethodDefinition::AsyncGenerator(expr) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_private_name(*name); self.emit(Opcode::PushClassPrivateMethod, &[index]); } @@ -513,79 +508,79 @@ impl ByteCompiler<'_, '_> { match method_definition { MethodDefinition::Get(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassGetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassGetterByValue); } }, MethodDefinition::Set(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassSetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassSetterByValue); } }, MethodDefinition::Ordinary(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassMethodByValue); } }, MethodDefinition::Async(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassMethodByValue); } }, MethodDefinition::Generator(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassMethodByValue); } }, MethodDefinition::AsyncGenerator(expr) => match name { PropertyName::Literal(name) => { - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineClassMethodByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into(), NodeKind::Expression, class_name, true)?; + self.method(expr.into(), NodeKind::Expression, class_name, true); self.emit_opcode(Opcode::DefineClassMethodByValue); } }, @@ -610,6 +605,5 @@ impl ByteCompiler<'_, '_> { class.name().expect("class statements must have a name"), ); } - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs b/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs index 357955130c7..eaa86159888 100644 --- a/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs +++ b/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs @@ -1,12 +1,10 @@ -use boa_ast::{ - pattern::{ArrayPatternElement, ObjectPatternElement, Pattern}, - property::PropertyName, -}; - use crate::{ bytecompiler::{Access, ByteCompiler, Literal}, vm::{BindingOpcode, Opcode}, - JsResult, +}; +use boa_ast::{ + pattern::{ArrayPatternElement, ObjectPatternElement, Pattern}, + property::PropertyName, }; impl ByteCompiler<'_, '_> { @@ -14,7 +12,7 @@ impl ByteCompiler<'_, '_> { &mut self, pattern: &Pattern, def: BindingOpcode, - ) -> JsResult<()> { + ) { match pattern { Pattern::Object(pattern) => { self.emit_opcode(Opcode::ValueNotNullOrUndefined); @@ -44,7 +42,7 @@ impl ByteCompiler<'_, '_> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyName::Computed(node) => { - self.compile_expr(node, true)?; + self.compile_expr(node, true); if rest_exits { self.emit_opcode(Opcode::GetPropertyByValuePush); } else { @@ -56,7 +54,7 @@ impl ByteCompiler<'_, '_> { if let Some(init) = default_init { let skip = self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.patch_jump(skip); } self.emit_binding(def, *ident); @@ -101,7 +99,7 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); } AssignmentPropertyAccess { name, @@ -115,7 +113,7 @@ impl ByteCompiler<'_, '_> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyName::Computed(node) => { - self.compile_expr(node, true)?; + self.compile_expr(node, true); if rest_exits { self.emit_opcode(Opcode::GetPropertyByValuePush); } else { @@ -127,7 +125,7 @@ impl ByteCompiler<'_, '_> { if let Some(init) = default_init { let skip = self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.patch_jump(skip); } @@ -135,7 +133,7 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); if rest_exits && name.computed().is_some() { self.emit_opcode(Opcode::Swap); @@ -154,7 +152,7 @@ impl ByteCompiler<'_, '_> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyName::Computed(node) => { - self.compile_expr(node, true)?; + self.compile_expr(node, true); self.emit_opcode(Opcode::GetPropertyByValue); } } @@ -162,11 +160,11 @@ impl ByteCompiler<'_, '_> { if let Some(init) = default_init { let skip = self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.patch_jump(skip); } - self.compile_declaration_pattern(pattern, def)?; + self.compile_declaration_pattern(pattern, def); } } } @@ -200,7 +198,7 @@ impl ByteCompiler<'_, '_> { if let Some(init) = default_init { let skip = self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.patch_jump(skip); } self.emit_binding(def, *ident); @@ -211,7 +209,7 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); } // BindingElement : BindingPattern Initializer[opt] Pattern { @@ -223,11 +221,11 @@ impl ByteCompiler<'_, '_> { if let Some(init) = default_init { let skip = self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.patch_jump(skip); } - self.compile_declaration_pattern(pattern, def)?; + self.compile_declaration_pattern(pattern, def); } // BindingRestElement : ... BindingIdentifier SingleNameRest { ident } => { @@ -240,12 +238,12 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); } // BindingRestElement : ... BindingPattern PatternRest { pattern } => { self.emit_opcode(Opcode::IteratorToArray); - self.compile_declaration_pattern(pattern, def)?; + self.compile_declaration_pattern(pattern, def); } } } @@ -253,6 +251,5 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::IteratorClose); } } - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/assign.rs b/boa_engine/src/bytecompiler/expression/assign.rs index 7b4327ca148..c046d670815 100644 --- a/boa_engine/src/bytecompiler/expression/assign.rs +++ b/boa_engine/src/bytecompiler/expression/assign.rs @@ -1,7 +1,6 @@ use crate::{ bytecompiler::{Access, ByteCompiler}, vm::{BindingOpcode, Opcode}, - JsResult, }; use boa_ast::expression::{ access::{PropertyAccess, PropertyAccessField}, @@ -9,19 +8,18 @@ use boa_ast::expression::{ }; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_assign(&mut self, assign: &Assign, use_expr: bool) -> JsResult<()> { + pub(crate) fn compile_assign(&mut self, assign: &Assign, use_expr: bool) { if assign.op() == AssignOp::Assign { match Access::from_assign_target(assign.lhs()) { Ok(access) => self.access_set(access, use_expr, |compiler, _| { - compiler.compile_expr(assign.rhs(), true)?; - Ok(()) - })?, + compiler.compile_expr(assign.rhs(), true); + }), Err(pattern) => { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); if use_expr { self.emit_opcode(Opcode::Dup); } - self.compile_declaration_pattern(pattern, BindingOpcode::SetName)?; + self.compile_declaration_pattern(pattern, BindingOpcode::SetName); } } } else { @@ -62,9 +60,9 @@ impl ByteCompiler<'_, '_> { if short_circuit { early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } if use_expr { @@ -79,7 +77,7 @@ impl ByteCompiler<'_, '_> { PropertyAccess::Simple(access) => match access.field() { PropertyAccessField::Const(name) => { let index = self.get_or_insert_name((*name).into()); - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); @@ -87,9 +85,9 @@ impl ByteCompiler<'_, '_> { if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } @@ -99,17 +97,17 @@ impl ByteCompiler<'_, '_> { } } PropertyAccessField::Expr(expr) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::GetPropertyByValuePush); if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } @@ -121,16 +119,16 @@ impl ByteCompiler<'_, '_> { }, PropertyAccess::Private(access) => { let index = self.get_or_insert_private_name(access.field()); - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); self.emit(Opcode::GetPrivateField, &[index]); if short_circuit { pop_count = 1; early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } @@ -151,9 +149,9 @@ impl ByteCompiler<'_, '_> { if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } @@ -165,15 +163,15 @@ impl ByteCompiler<'_, '_> { PropertyAccessField::Expr(expr) => { self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Dup); - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::GetPropertyByValuePush); if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); } else { - self.compile_expr(assign.rhs(), true)?; + self.compile_expr(assign.rhs(), true); self.emit_opcode(opcode); } @@ -201,7 +199,5 @@ impl ByteCompiler<'_, '_> { } } } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/binary.rs b/boa_engine/src/bytecompiler/expression/binary.rs index 44b0615a688..0d15a3189f1 100644 --- a/boa_engine/src/bytecompiler/expression/binary.rs +++ b/boa_engine/src/bytecompiler/expression/binary.rs @@ -3,14 +3,14 @@ use boa_ast::expression::operator::{ Binary, BinaryInPrivate, }; -use crate::{bytecompiler::ByteCompiler, vm::Opcode, JsResult}; +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_binary(&mut self, binary: &Binary, use_expr: bool) -> JsResult<()> { - self.compile_expr(binary.lhs(), true)?; + pub(crate) fn compile_binary(&mut self, binary: &Binary, use_expr: bool) { + self.compile_expr(binary.lhs(), true); match binary.op() { BinaryOp::Arithmetic(op) => { - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); match op { ArithmeticOp::Add => self.emit_opcode(Opcode::Add), ArithmeticOp::Sub => self.emit_opcode(Opcode::Sub), @@ -25,7 +25,7 @@ impl ByteCompiler<'_, '_> { } } BinaryOp::Bitwise(op) => { - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); match op { BitwiseOp::And => self.emit_opcode(Opcode::BitAnd), BitwiseOp::Or => self.emit_opcode(Opcode::BitOr), @@ -40,7 +40,7 @@ impl ByteCompiler<'_, '_> { } } BinaryOp::Relational(op) => { - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); match op { RelationalOp::Equal => self.emit_opcode(Opcode::Eq), RelationalOp::NotEqual => self.emit_opcode(Opcode::NotEq), @@ -64,17 +64,17 @@ impl ByteCompiler<'_, '_> { match op { LogicalOp::And => { let exit = self.emit_opcode_with_operand(Opcode::LogicalAnd); - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); self.patch_jump(exit); } LogicalOp::Or => { let exit = self.emit_opcode_with_operand(Opcode::LogicalOr); - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); self.patch_jump(exit); } LogicalOp::Coalesce => { let exit = self.emit_opcode_with_operand(Opcode::Coalesce); - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); self.patch_jump(exit); } }; @@ -85,30 +85,22 @@ impl ByteCompiler<'_, '_> { } BinaryOp::Comma => { self.emit(Opcode::Pop, &[]); - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); if !use_expr { self.emit(Opcode::Pop, &[]); } } }; - - Ok(()) } - pub(crate) fn compile_binary_in_private( - &mut self, - binary: &BinaryInPrivate, - use_expr: bool, - ) -> JsResult<()> { + pub(crate) fn compile_binary_in_private(&mut self, binary: &BinaryInPrivate, use_expr: bool) { let index = self.get_or_insert_private_name(*binary.lhs()); - self.compile_expr(binary.rhs(), true)?; + self.compile_expr(binary.rhs(), true); self.emit(Opcode::InPrivate, &[index]); if !use_expr { self.emit_opcode(Opcode::Pop); } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/mod.rs b/boa_engine/src/bytecompiler/expression/mod.rs index 89558959bf9..d00752a763f 100644 --- a/boa_engine/src/bytecompiler/expression/mod.rs +++ b/boa_engine/src/bytecompiler/expression/mod.rs @@ -8,7 +8,6 @@ use super::{Access, Callable, NodeKind}; use crate::{ bytecompiler::{ByteCompiler, Literal}, vm::Opcode, - JsResult, }; use boa_ast::{ expression::{ @@ -41,34 +40,28 @@ impl ByteCompiler<'_, '_> { } } - fn compile_conditional(&mut self, op: &Conditional, use_expr: bool) -> JsResult<()> { - self.compile_expr(op.condition(), true)?; + fn compile_conditional(&mut self, op: &Conditional, use_expr: bool) { + self.compile_expr(op.condition(), true); let jelse = self.jump_if_false(); - self.compile_expr(op.if_true(), true)?; + self.compile_expr(op.if_true(), true); let exit = self.jump(); self.patch_jump(jelse); - self.compile_expr(op.if_false(), true)?; + self.compile_expr(op.if_false(), true); self.patch_jump(exit); if !use_expr { self.emit(Opcode::Pop, &[]); }; - - Ok(()) } - fn compile_template_literal( - &mut self, - template_literal: &TemplateLiteral, - use_expr: bool, - ) -> JsResult<()> { + fn compile_template_literal(&mut self, template_literal: &TemplateLiteral, use_expr: bool) { for element in template_literal.elements() { match element { TemplateElement::String(s) => self.emit_push_literal(Literal::String( self.interner().resolve_expect(*s).into_common(false), )), TemplateElement::Expr(expr) => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } } } @@ -81,37 +74,35 @@ impl ByteCompiler<'_, '_> { if !use_expr { self.emit(Opcode::Pop, &[]); } - - Ok(()) } - pub(crate) fn compile_expr_impl(&mut self, expr: &Expression, use_expr: bool) -> JsResult<()> { + pub(crate) fn compile_expr_impl(&mut self, expr: &Expression, use_expr: bool) { match expr { Expression::Literal(lit) => self.compile_literal(lit, use_expr), - Expression::Unary(unary) => self.compile_unary(unary, use_expr)?, - Expression::Update(update) => self.compile_update(update, use_expr)?, - Expression::Binary(binary) => self.compile_binary(binary, use_expr)?, + Expression::Unary(unary) => self.compile_unary(unary, use_expr), + Expression::Update(update) => self.compile_update(update, use_expr), + Expression::Binary(binary) => self.compile_binary(binary, use_expr), Expression::BinaryInPrivate(binary) => { - self.compile_binary_in_private(binary, use_expr)?; + self.compile_binary_in_private(binary, use_expr); } - Expression::Assign(assign) => self.compile_assign(assign, use_expr)?, + Expression::Assign(assign) => self.compile_assign(assign, use_expr), Expression::ObjectLiteral(object) => { - self.compile_object_literal(object, use_expr)?; + self.compile_object_literal(object, use_expr); } Expression::Identifier(name) => { - self.access_get(Access::Variable { name: *name }, use_expr)?; + self.access_get(Access::Variable { name: *name }, use_expr); } Expression::PropertyAccess(access) => { - self.access_get(Access::Property { access }, use_expr)?; + self.access_get(Access::Property { access }, use_expr); } - Expression::Conditional(op) => self.compile_conditional(op, use_expr)?, + Expression::Conditional(op) => self.compile_conditional(op, use_expr), Expression::ArrayLiteral(array) => { self.emit_opcode(Opcode::PushNewArray); self.emit_opcode(Opcode::PopOnReturnAdd); for element in array.as_ref() { if let Some(element) = element { - self.compile_expr(element, true)?; + self.compile_expr(element, true); if let Expression::Spread(_) = element { self.emit_opcode(Opcode::InitIterator); self.emit_opcode(Opcode::PushIteratorToArray); @@ -129,34 +120,34 @@ impl ByteCompiler<'_, '_> { } } Expression::This => { - self.access_get(Access::This, use_expr)?; + self.access_get(Access::This, use_expr); } - Expression::Spread(spread) => self.compile_expr(spread.target(), true)?, + Expression::Spread(spread) => self.compile_expr(spread.target(), true), Expression::Function(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } Expression::ArrowFunction(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } Expression::AsyncArrowFunction(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } Expression::Generator(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } Expression::AsyncFunction(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } Expression::AsyncGenerator(function) => { - self.function(function.into(), NodeKind::Expression, use_expr)?; + self.function(function.into(), NodeKind::Expression, use_expr); } - Expression::Call(call) => self.call(Callable::Call(call), use_expr)?, - Expression::New(new) => self.call(Callable::New(new), use_expr)?, + Expression::Call(call) => self.call(Callable::Call(call), use_expr), + Expression::New(new) => self.call(Callable::New(new), use_expr), Expression::TemplateLiteral(template_literal) => { - self.compile_template_literal(template_literal, use_expr)?; + self.compile_template_literal(template_literal, use_expr); } Expression::Await(expr) => { - self.compile_expr(expr.target(), true)?; + self.compile_expr(expr.target(), true); self.emit_opcode(Opcode::Await); self.emit_opcode(Opcode::GeneratorNext); if !use_expr { @@ -165,7 +156,7 @@ impl ByteCompiler<'_, '_> { } Expression::Yield(r#yield) => { if let Some(expr) = r#yield.target() { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } else { self.emit_opcode(Opcode::PushUndefined); } @@ -204,7 +195,7 @@ impl ByteCompiler<'_, '_> { Expression::TaggedTemplate(template) => { match template.tag() { Expression::PropertyAccess(PropertyAccess::Simple(access)) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit(Opcode::Dup, &[]); match access.field() { PropertyAccessField::Const(field) => { @@ -212,19 +203,19 @@ impl ByteCompiler<'_, '_> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyAccessField::Expr(field) => { - self.compile_expr(field, true)?; + self.compile_expr(field, true); self.emit(Opcode::GetPropertyByValue, &[]); } } } Expression::PropertyAccess(PropertyAccess::Private(access)) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit(Opcode::Dup, &[]); let index = self.get_or_insert_private_name(access.field()); self.emit(Opcode::GetPrivateField, &[index]); } expr => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::Swap); } @@ -257,12 +248,12 @@ impl ByteCompiler<'_, '_> { self.emit(Opcode::Pop, &[]); for expr in template.exprs() { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } self.emit(Opcode::Call, &[(template.exprs().len() + 1) as u32]); } - Expression::Class(class) => self.class(class, true)?, + Expression::Class(class) => self.class(class, true), Expression::SuperCall(super_call) => { let contains_spread = super_call .arguments() @@ -272,7 +263,7 @@ impl ByteCompiler<'_, '_> { if contains_spread { self.emit_opcode(Opcode::PushNewArray); for arg in super_call.arguments() { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); if let Expression::Spread(_) = arg { self.emit_opcode(Opcode::InitIterator); self.emit_opcode(Opcode::PushIteratorToArray); @@ -282,7 +273,7 @@ impl ByteCompiler<'_, '_> { } } else { for arg in super_call.arguments() { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); } } @@ -302,7 +293,7 @@ impl ByteCompiler<'_, '_> { } } Expression::Optional(opt) => { - self.compile_optional_preserve_this(opt)?; + self.compile_optional_preserve_this(opt); self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Pop); @@ -314,6 +305,5 @@ impl ByteCompiler<'_, '_> { // TODO: try to remove this variant somehow Expression::FormalParameterList(_) => unreachable!(), } - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/object_literal.rs b/boa_engine/src/bytecompiler/expression/object_literal.rs index 80bf42ec545..9a5810b5f99 100644 --- a/boa_engine/src/bytecompiler/expression/object_literal.rs +++ b/boa_engine/src/bytecompiler/expression/object_literal.rs @@ -1,32 +1,27 @@ +use crate::{ + bytecompiler::{Access, ByteCompiler, NodeKind}, + vm::Opcode, +}; use boa_ast::{ expression::literal::ObjectLiteral, property::{MethodDefinition, PropertyDefinition, PropertyName}, }; use boa_interner::Sym; -use crate::{ - bytecompiler::{Access, ByteCompiler, NodeKind}, - vm::Opcode, - JsNativeError, JsResult, -}; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_object_literal( - &mut self, - object: &ObjectLiteral, - use_expr: bool, - ) -> JsResult<()> { + pub(crate) fn compile_object_literal(&mut self, object: &ObjectLiteral, use_expr: bool) { self.emit_opcode(Opcode::PushEmptyObject); for property in object.properties() { self.emit_opcode(Opcode::Dup); match property { PropertyDefinition::IdentifierReference(ident) => { let index = self.get_or_insert_name(*ident); - self.access_get(Access::Variable { name: *ident }, true)?; + self.access_get(Access::Variable { name: *ident }, true); self.emit(Opcode::DefineOwnPropertyByName, &[index]); } PropertyDefinition::Property(name, expr) => match name { PropertyName::Literal(name) => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); let index = self.get_or_insert_name((*name).into()); if *name == Sym::__PROTO__ && !self.json_parse { self.emit_opcode(Opcode::SetPrototype); @@ -35,15 +30,15 @@ impl ByteCompiler<'_, '_> { } } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); if expr.is_anonymous_function_definition() { self.emit_opcode(Opcode::Dup); - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(0); } else { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } self.emit_opcode(Opcode::DefineOwnPropertyByValue); } @@ -51,15 +46,15 @@ impl ByteCompiler<'_, '_> { PropertyDefinition::MethodDefinition(name, kind) => match kind { MethodDefinition::Get(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::SetPropertyGetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(1); self.emit_opcode(Opcode::SetPropertyGetterByValue); @@ -67,15 +62,15 @@ impl ByteCompiler<'_, '_> { }, MethodDefinition::Set(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::SetPropertySetterByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(2); self.emit_opcode(Opcode::SetPropertySetterByValue); @@ -83,15 +78,15 @@ impl ByteCompiler<'_, '_> { }, MethodDefinition::Ordinary(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineOwnPropertyByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(0); self.emit_opcode(Opcode::DefineOwnPropertyByValue); @@ -99,15 +94,15 @@ impl ByteCompiler<'_, '_> { }, MethodDefinition::Async(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineOwnPropertyByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(0); self.emit_opcode(Opcode::DefineOwnPropertyByValue); @@ -115,15 +110,15 @@ impl ByteCompiler<'_, '_> { }, MethodDefinition::Generator(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineOwnPropertyByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(0); self.emit_opcode(Opcode::DefineOwnPropertyByValue); @@ -131,15 +126,15 @@ impl ByteCompiler<'_, '_> { }, MethodDefinition::AsyncGenerator(expr) => match name { PropertyName::Literal(name) => { - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::DefineOwnPropertyByName, &[index]); } PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true)?; + self.compile_expr(name_node, true); self.emit_opcode(Opcode::ToPropertyKey); self.emit_opcode(Opcode::Dup); - self.function(expr.into(), NodeKind::Expression, true)?; + self.function(expr.into(), NodeKind::Expression, true); self.emit_opcode(Opcode::SetFunctionName); self.emit_u8(0); self.emit_opcode(Opcode::DefineOwnPropertyByValue); @@ -147,16 +142,13 @@ impl ByteCompiler<'_, '_> { }, }, PropertyDefinition::SpreadObject(expr) => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::Swap); self.emit(Opcode::CopyDataProperties, &[0, 0]); self.emit_opcode(Opcode::Pop); } - // TODO: Promote to early errors PropertyDefinition::CoverInitializedName(_, _) => { - return Err(JsNativeError::syntax() - .with_message("invalid assignment pattern in object literal") - .into()) + unreachable!("invalid assignment pattern in object literal") } } } @@ -164,7 +156,5 @@ impl ByteCompiler<'_, '_> { if !use_expr { self.emit(Opcode::Pop, &[]); } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/unary.rs b/boa_engine/src/bytecompiler/expression/unary.rs index 338991b7b40..2c948eaad38 100644 --- a/boa_engine/src/bytecompiler/expression/unary.rs +++ b/boa_engine/src/bytecompiler/expression/unary.rs @@ -6,17 +6,16 @@ use boa_ast::{ use crate::{ bytecompiler::{Access, ByteCompiler}, vm::Opcode, - JsResult, }; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_unary(&mut self, unary: &Unary, use_expr: bool) -> JsResult<()> { + pub(crate) fn compile_unary(&mut self, unary: &Unary, use_expr: bool) { let opcode = match unary.op() { UnaryOp::Delete => { if let Some(access) = Access::from_expression(unary.target()) { - self.access_delete(access)?; + self.access_delete(access); } else { - self.compile_expr(unary.target(), false)?; + self.compile_expr(unary.target(), false); self.emit(Opcode::PushTrue, &[]); } None @@ -32,7 +31,7 @@ impl ByteCompiler<'_, '_> { let index = self.get_or_insert_binding(binding); self.emit(Opcode::GetNameOrUndefined, &[index]); } - expr => self.compile_expr(expr, true)?, + expr => self.compile_expr(expr, true), } self.emit_opcode(Opcode::TypeOf); None @@ -41,14 +40,12 @@ impl ByteCompiler<'_, '_> { }; if let Some(opcode) = opcode { - self.compile_expr(unary.target(), true)?; + self.compile_expr(unary.target(), true); self.emit(opcode, &[]); } if !use_expr { self.emit(Opcode::Pop, &[]); } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/expression/update.rs b/boa_engine/src/bytecompiler/expression/update.rs index 6f7040b6fb0..cb3a2d10b67 100644 --- a/boa_engine/src/bytecompiler/expression/update.rs +++ b/boa_engine/src/bytecompiler/expression/update.rs @@ -1,53 +1,46 @@ use crate::{ bytecompiler::{Access, ByteCompiler}, vm::Opcode, - JsResult, }; use boa_ast::expression::operator::{update::UpdateOp, Update}; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_update(&mut self, update: &Update, use_expr: bool) -> JsResult<()> { + pub(crate) fn compile_update(&mut self, update: &Update, use_expr: bool) { let access = Access::from_update_target(update.target()); match update.op() { UpdateOp::IncrementPre => { self.access_set(access, true, |compiler, _| { - compiler.access_get(access, true)?; + compiler.access_get(access, true); compiler.emit_opcode(Opcode::Inc); - Ok(()) - })?; + }); } UpdateOp::DecrementPre => { self.access_set(access, true, |compiler, _| { - compiler.access_get(access, true)?; + compiler.access_get(access, true); compiler.emit_opcode(Opcode::Dec); - Ok(()) - })?; + }); } UpdateOp::IncrementPost => { self.access_set(access, false, |compiler, level| { - compiler.access_get(access, true)?; + compiler.access_get(access, true); compiler.emit_opcode(Opcode::IncPost); compiler.emit_opcode(Opcode::RotateRight); compiler.emit_u8(level + 2); - Ok(()) - })?; + }); } UpdateOp::DecrementPost => { self.access_set(access, false, |compiler, level| { - compiler.access_get(access, true)?; + compiler.access_get(access, true); compiler.emit_opcode(Opcode::DecPost); compiler.emit_opcode(Opcode::RotateRight); compiler.emit_u8(level + 2); - Ok(()) - })?; + }); } } if !use_expr { self.emit_opcode(Opcode::Pop); } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/function.rs b/boa_engine/src/bytecompiler/function.rs index ed28e53eb0f..f91f4c37c7b 100644 --- a/boa_engine/src/bytecompiler/function.rs +++ b/boa_engine/src/bytecompiler/function.rs @@ -2,7 +2,7 @@ use crate::{ builtins::function::ThisMode, bytecompiler::ByteCompiler, vm::{BindingOpcode, CodeBlock, Opcode}, - Context, JsResult, + Context, }; use boa_ast::{ declaration::Binding, function::FormalParameterList, operations::bound_names, StatementList, @@ -91,7 +91,7 @@ impl FunctionCompiler { parameters: &FormalParameterList, body: &StatementList, context: &mut Context<'_>, - ) -> JsResult> { + ) -> Gc { self.strict = self.strict || body.strict(); let length = parameters.length(); @@ -159,7 +159,7 @@ impl FunctionCompiler { // TODO: throw custom error if ident is in init if let Some(init) = parameter.variable().init() { let skip = compiler.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - compiler.compile_expr(init, true)?; + compiler.compile_expr(init, true); compiler.patch_jump(skip); } compiler.emit_binding(BindingOpcode::InitArg, *ident); @@ -171,10 +171,10 @@ impl FunctionCompiler { // TODO: throw custom error if ident is in init if let Some(init) = parameter.variable().init() { let skip = compiler.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - compiler.compile_expr(init, true)?; + compiler.compile_expr(init, true); compiler.patch_jump(skip); } - compiler.compile_declaration_pattern(pattern, BindingOpcode::InitArg)?; + compiler.compile_declaration_pattern(pattern, BindingOpcode::InitArg); } } } @@ -200,7 +200,7 @@ impl FunctionCompiler { } compiler.create_script_decls(body, false); - compiler.compile_statement_list(body, false, false)?; + compiler.compile_statement_list(body, false, false); if let Some(env_label) = env_label { let (num_bindings, compile_environment) = @@ -234,6 +234,6 @@ impl FunctionCompiler { compiler.emit(Opcode::PushUndefined, &[]); compiler.emit(Opcode::Return, &[]); - Ok(Gc::new(compiler.finish())) + Gc::new(compiler.finish()) } } diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index 1551f63685f..98fbcfe207e 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -11,7 +11,7 @@ mod statement; use crate::{ environments::{BindingLocator, CompileTimeEnvironment}, vm::{BindingOpcode, CodeBlock, Opcode}, - Context, JsBigInt, JsResult, JsString, JsValue, + Context, JsBigInt, JsString, JsValue, }; use boa_ast::{ declaration::{Binding, LexicalDeclaration, VarDeclaration}, @@ -484,7 +484,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.patch_jump_with_target(label, target); } - fn access_get(&mut self, access: Access<'_>, use_expr: bool) -> JsResult<()> { + fn access_get(&mut self, access: Access<'_>, use_expr: bool) { match access { Access::Variable { name } => { let binding = self.context.get_binding_value(name); @@ -495,18 +495,18 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { PropertyAccess::Simple(access) => match access.field() { PropertyAccessField::Const(name) => { let index = self.get_or_insert_name((*name).into()); - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit(Opcode::GetPropertyByName, &[index]); } PropertyAccessField::Expr(expr) => { - self.compile_expr(access.target(), true)?; - self.compile_expr(expr, true)?; + self.compile_expr(access.target(), true); + self.compile_expr(expr, true); self.emit(Opcode::GetPropertyByValue, &[]); } }, PropertyAccess::Private(access) => { let index = self.get_or_insert_private_name(access.field()); - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit(Opcode::GetPrivateField, &[index]); } PropertyAccess::Super(access) => match access.field() { @@ -517,7 +517,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } PropertyAccessField::Expr(expr) => { self.emit_opcode(Opcode::Super); - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::GetPropertyByValue); } }, @@ -530,15 +530,11 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { if !use_expr { self.emit(Opcode::Pop, &[]); } - Ok(()) } // The wrap is needed so it can match the function signature. #[allow(clippy::unnecessary_wraps)] - fn access_set_top_of_stack_expr_fn( - compiler: &mut ByteCompiler<'_, '_>, - level: u8, - ) -> JsResult<()> { + fn access_set_top_of_stack_expr_fn(compiler: &mut ByteCompiler<'_, '_>, level: u8) { match level { 0 => {} 1 => compiler.emit_opcode(Opcode::Swap), @@ -547,80 +543,73 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { compiler.emit_u8(level + 1); } } - Ok(()) } - fn access_set(&mut self, access: Access<'_>, use_expr: bool, expr_fn: F) -> JsResult + fn access_set(&mut self, access: Access<'_>, use_expr: bool, expr_fn: F) where - F: FnOnce(&mut ByteCompiler<'_, '_>, u8) -> JsResult, + F: FnOnce(&mut ByteCompiler<'_, '_>, u8) -> R, { match access { Access::Variable { name } => { - let result = expr_fn(self, 0); + expr_fn(self, 0); if use_expr { self.emit(Opcode::Dup, &[]); } let binding = self.context.set_mutable_binding(name); let index = self.get_or_insert_binding(binding); self.emit(Opcode::SetName, &[index]); - result } Access::Property { access } => match access { PropertyAccess::Simple(access) => match access.field() { PropertyAccessField::Const(name) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); - let result = expr_fn(self, 2); + expr_fn(self, 2); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::SetPropertyByName, &[index]); if !use_expr { self.emit(Opcode::Pop, &[]); } - result } PropertyAccessField::Expr(expr) => { - self.compile_expr(access.target(), true)?; - self.compile_expr(expr, true)?; - let result = expr_fn(self, 2); + self.compile_expr(access.target(), true); + self.compile_expr(expr, true); + expr_fn(self, 2); self.emit(Opcode::SetPropertyByValue, &[]); if !use_expr { self.emit(Opcode::Pop, &[]); } - result } }, PropertyAccess::Private(access) => { - self.compile_expr(access.target(), true)?; - let result = expr_fn(self, 1); + self.compile_expr(access.target(), true); + expr_fn(self, 1); let index = self.get_or_insert_private_name(access.field()); self.emit(Opcode::SetPrivateField, &[index]); if !use_expr { self.emit(Opcode::Pop, &[]); } - result } PropertyAccess::Super(access) => match access.field() { PropertyAccessField::Const(name) => { self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::This); - let result = expr_fn(self, 1); + expr_fn(self, 1); let index = self.get_or_insert_name((*name).into()); self.emit(Opcode::SetPropertyByName, &[index]); if !use_expr { self.emit(Opcode::Pop, &[]); } - result } PropertyAccessField::Expr(expr) => { self.emit(Opcode::Super, &[]); - self.compile_expr(expr, true)?; - let result = expr_fn(self, 0); + self.compile_expr(expr, true); + expr_fn(self, 0); self.emit(Opcode::SetPropertyByValue, &[]); if !use_expr { self.emit(Opcode::Pop, &[]); } - result } }, }, @@ -628,18 +617,18 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } } - fn access_delete(&mut self, access: Access<'_>) -> JsResult<()> { + fn access_delete(&mut self, access: Access<'_>) { match access { Access::Property { access } => match access { PropertyAccess::Simple(access) => match access.field() { PropertyAccessField::Const(name) => { let index = self.get_or_insert_name((*name).into()); - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit(Opcode::DeletePropertyByName, &[index]); } PropertyAccessField::Expr(expr) => { - self.compile_expr(access.target(), true)?; - self.compile_expr(expr, true)?; + self.compile_expr(access.target(), true); + self.compile_expr(expr, true); self.emit_opcode(Opcode::DeletePropertyByValue); } }, @@ -658,7 +647,6 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit_opcode(Opcode::PushTrue); } } - Ok(()) } /// Compile a [`StatementList`]. @@ -667,7 +655,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { list: &StatementList, use_expr: bool, configurable_globals: bool, - ) -> JsResult<()> { + ) { if use_expr { let expr_index = list .statements() @@ -683,15 +671,13 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { .count(); for (i, item) in list.statements().iter().enumerate() { - self.compile_stmt_list_item(item, i + 1 == expr_index, configurable_globals)?; + self.compile_stmt_list_item(item, i + 1 == expr_index, configurable_globals); } } else { for item in list.statements() { - self.compile_stmt_list_item(item, false, configurable_globals)?; + self.compile_stmt_list_item(item, false, configurable_globals); } } - - Ok(()) } /// Compile a statement list in a new declarative environment. @@ -700,7 +686,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { list: &StatementList, use_expr: bool, strict: bool, - ) -> JsResult<()> { + ) { self.context.push_compile_time_environment(strict); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); @@ -721,11 +707,11 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { .count(); for (i, item) in list.statements().iter().enumerate() { - self.compile_stmt_list_item(item, i + 1 == expr_index, true)?; + self.compile_stmt_list_item(item, i + 1 == expr_index, true); } } else { for item in list.statements() { - self.compile_stmt_list_item(item, false, true)?; + self.compile_stmt_list_item(item, false, true); } } @@ -734,14 +720,12 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.patch_jump_with_target(push_env.0, num_bindings as u32); self.patch_jump_with_target(push_env.1, index_compile_environment as u32); self.emit_opcode(Opcode::PopEnvironment); - - Ok(()) } /// Compile an [`Expression`]. #[inline] - pub fn compile_expr(&mut self, expr: &Expression, use_expr: bool) -> JsResult<()> { - self.compile_expr_impl(expr, use_expr) + pub fn compile_expr(&mut self, expr: &Expression, use_expr: bool) { + self.compile_expr_impl(expr, use_expr); } /// Compile a property access expression, prepending `this` to the property value in the stack. @@ -754,10 +738,10 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { /// with calls (`a.b()`), since both of them must have `a` be the value of `this` for the function /// call `b()`, but a regular compilation of the access would lose the `this` value after accessing /// `b`. - fn compile_access_preserve_this(&mut self, access: &PropertyAccess) -> JsResult<()> { + fn compile_access_preserve_this(&mut self, access: &PropertyAccess) { match access { PropertyAccess::Simple(access) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); match access.field() { PropertyAccessField::Const(field) => { @@ -765,13 +749,13 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyAccessField::Expr(field) => { - self.compile_expr(field, true)?; + self.compile_expr(field, true); self.emit_opcode(Opcode::GetPropertyByValue); } } } PropertyAccess::Private(access) => { - self.compile_expr(access.target(), true)?; + self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); let index = self.get_or_insert_private_name(access.field()); self.emit(Opcode::GetPrivateField, &[index]); @@ -785,13 +769,12 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyAccessField::Expr(expr) => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_opcode(Opcode::GetPropertyByValue); } } } } - Ok(()) } /// Compile an optional chain expression, prepending `this` to the property value in the stack. @@ -805,17 +788,17 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { /// would only return the result of the chain without preserving the `this` value. In other words, /// `this` would be set to `undefined` for that call, which is incorrect since `a` should be the /// `this` value of the call. - fn compile_optional_preserve_this(&mut self, optional: &Optional) -> JsResult<()> { + fn compile_optional_preserve_this(&mut self, optional: &Optional) { let mut jumps = Vec::with_capacity(optional.chain().len()); match optional.target() { Expression::PropertyAccess(access) => { - self.compile_access_preserve_this(access)?; + self.compile_access_preserve_this(access); } - Expression::Optional(opt) => self.compile_optional_preserve_this(opt)?, + Expression::Optional(opt) => self.compile_optional_preserve_this(opt), expr => { self.emit(Opcode::PushUndefined, &[]); - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } } jumps.push(self.jump_if_null_or_undefined()); @@ -826,13 +809,13 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { .expect("chain must have at least one element"); assert!(first.shorted()); - self.compile_optional_item_kind(first.kind())?; + self.compile_optional_item_kind(first.kind()); for item in rest { if item.shorted() { jumps.push(self.jump_if_null_or_undefined()); } - self.compile_optional_item_kind(item.kind())?; + self.compile_optional_item_kind(item.kind()); } let skip_undef = self.jump(); @@ -844,8 +827,6 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit_opcode(Opcode::PushUndefined); self.patch_jump(skip_undef); - - Ok(()) } /// Compile a single operation in an optional chain. @@ -864,7 +845,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { /// is not null or undefined (if the operator `?.` was used). /// - This assumes that the state of the stack before compiling is `...rest, this, value`, /// since the operation compiled by this function could be a call. - fn compile_optional_item_kind(&mut self, kind: &OptionalOperationKind) -> JsResult<()> { + fn compile_optional_item_kind(&mut self, kind: &OptionalOperationKind) { match kind { OptionalOperationKind::SimplePropertyAccess { field } => { self.emit_opcode(Opcode::Dup); @@ -874,7 +855,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit(Opcode::GetPropertyByName, &[index]); } PropertyAccessField::Expr(expr) => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit(Opcode::GetPropertyByValue, &[]); } } @@ -897,7 +878,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { if contains_spread { self.emit_opcode(Opcode::PushNewArray); for arg in args { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); if let Expression::Spread(_) = arg { self.emit_opcode(Opcode::InitIterator); self.emit_opcode(Opcode::PushIteratorToArray); @@ -908,7 +889,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit_opcode(Opcode::CallSpread); } else { for arg in args { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); } self.emit(Opcode::Call, &[args.len() as u32]); } @@ -917,17 +898,16 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.emit_opcode(Opcode::Swap); } } - Ok(()) } /// Compile a [`VarDeclaration`]. - fn compile_var_decl(&mut self, decl: &VarDeclaration) -> JsResult<()> { + fn compile_var_decl(&mut self, decl: &VarDeclaration) { for variable in decl.0.as_ref() { match variable.binding() { Binding::Identifier(ident) => { let ident = ident; if let Some(expr) = variable.init() { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_binding(BindingOpcode::InitVar, *ident); } else { self.emit_binding(BindingOpcode::Var, *ident); @@ -935,20 +915,19 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } Binding::Pattern(pattern) => { if let Some(init) = variable.init() { - self.compile_expr(init, true)?; + self.compile_expr(init, true); } else { self.emit_opcode(Opcode::PushUndefined); }; - self.compile_declaration_pattern(pattern, BindingOpcode::InitVar)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitVar); } } } - Ok(()) } /// Compile a [`LexicalDeclaration`]. - fn compile_lexical_decl(&mut self, decl: &LexicalDeclaration) -> JsResult<()> { + fn compile_lexical_decl(&mut self, decl: &LexicalDeclaration) { match decl { LexicalDeclaration::Let(decls) => { for variable in decls.as_ref() { @@ -956,7 +935,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { Binding::Identifier(ident) => { let ident = ident; if let Some(expr) = variable.init() { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); self.emit_binding(BindingOpcode::InitLet, *ident); } else { self.emit_binding(BindingOpcode::Let, *ident); @@ -964,12 +943,12 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } Binding::Pattern(pattern) => { if let Some(init) = variable.init() { - self.compile_expr(init, true)?; + self.compile_expr(init, true); } else { self.emit_opcode(Opcode::PushUndefined); }; - self.compile_declaration_pattern(pattern, BindingOpcode::InitLet)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitLet); } } } @@ -981,24 +960,22 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { let init = variable .init() .expect("const declaration must have initializer"); - self.compile_expr(init, true)?; + self.compile_expr(init, true); self.emit_binding(BindingOpcode::InitConst, *ident); } Binding::Pattern(pattern) => { if let Some(init) = variable.init() { - self.compile_expr(init, true)?; + self.compile_expr(init, true); } else { self.emit_opcode(Opcode::PushUndefined); }; - self.compile_declaration_pattern(pattern, BindingOpcode::InitConst)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitConst); } } } - return Ok(()); } }; - Ok(()) } /// Compile a [`StatementListItem`]. @@ -1007,29 +984,29 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { item: &StatementListItem, use_expr: bool, configurable_globals: bool, - ) -> JsResult<()> { + ) { match item { StatementListItem::Statement(stmt) => { - self.compile_stmt(stmt, use_expr, configurable_globals) + self.compile_stmt(stmt, use_expr, configurable_globals); } StatementListItem::Declaration(decl) => self.compile_decl(decl), } } /// Compile a [`Declaration`]. - pub fn compile_decl(&mut self, decl: &Declaration) -> JsResult<()> { + pub fn compile_decl(&mut self, decl: &Declaration) { match decl { Declaration::Function(function) => { - self.function(function.into(), NodeKind::Declaration, false) + self.function(function.into(), NodeKind::Declaration, false); } Declaration::Generator(function) => { - self.function(function.into(), NodeKind::Declaration, false) + self.function(function.into(), NodeKind::Declaration, false); } Declaration::AsyncFunction(function) => { - self.function(function.into(), NodeKind::Declaration, false) + self.function(function.into(), NodeKind::Declaration, false); } Declaration::AsyncGenerator(function) => { - self.function(function.into(), NodeKind::Declaration, false) + self.function(function.into(), NodeKind::Declaration, false); } Declaration::Class(class) => self.class(class, false), Declaration::Lexical(lexical) => self.compile_lexical_decl(lexical), @@ -1037,12 +1014,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } /// Compile a function AST Node into bytecode. - fn function( - &mut self, - function: FunctionSpec<'_>, - node_kind: NodeKind, - use_expr: bool, - ) -> JsResult<()> { + fn function(&mut self, function: FunctionSpec<'_>, node_kind: NodeKind, use_expr: bool) { let (generator, r#async, arrow) = ( function.is_generator(), function.is_async(), @@ -1073,7 +1045,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { .strict(self.code_block.strict) .arrow(arrow) .binding_identifier(binding_identifier) - .compile(parameters, body, self.context)?; + .compile(parameters, body, self.context); let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); @@ -1106,8 +1078,6 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } } } - - Ok(()) } /// Compile a class method AST Node into bytecode. @@ -1117,7 +1087,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { node_kind: NodeKind, class_name: Sym, use_expr: bool, - ) -> JsResult<()> { + ) { let (generator, r#async, arrow) = ( function.is_generator(), function.is_async(), @@ -1149,7 +1119,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { .arrow(arrow) .binding_identifier(binding_identifier) .class_name(class_name) - .compile(parameters, body, self.context)?; + .compile(parameters, body, self.context); let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); @@ -1182,11 +1152,9 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } } } - - Ok(()) } - fn call(&mut self, callable: Callable<'_>, use_expr: bool) -> JsResult<()> { + fn call(&mut self, callable: Callable<'_>, use_expr: bool) { #[derive(PartialEq)] enum CallKind { CallEval, @@ -1204,14 +1172,14 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { match call.function() { Expression::PropertyAccess(access) if kind == CallKind::Call => { - self.compile_access_preserve_this(access)?; + self.compile_access_preserve_this(access); } Expression::Optional(opt) if kind == CallKind::Call => { - self.compile_optional_preserve_this(opt)?; + self.compile_optional_preserve_this(opt); } expr => { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); if kind == CallKind::Call || kind == CallKind::CallEval { self.emit_opcode(Opcode::PushUndefined); self.emit_opcode(Opcode::Swap); @@ -1227,7 +1195,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { if contains_spread { self.emit_opcode(Opcode::PushNewArray); for arg in call.args() { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); if let Expression::Spread(_) = arg { self.emit_opcode(Opcode::InitIterator); self.emit_opcode(Opcode::PushIteratorToArray); @@ -1237,7 +1205,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } } else { for arg in call.args() { - self.compile_expr(arg, true)?; + self.compile_expr(arg, true); } } @@ -1253,7 +1221,6 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { if !use_expr { self.emit(Opcode::Pop, &[]); } - Ok(()) } /// Finish compiling code with the [`ByteCompiler`] and return the generated [`CodeBlock`]. @@ -1264,12 +1231,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.code_block } - fn compile_declaration_pattern( - &mut self, - pattern: &Pattern, - def: BindingOpcode, - ) -> JsResult<()> { - self.compile_declaration_pattern_impl(pattern, def) + fn compile_declaration_pattern(&mut self, pattern: &Pattern, def: BindingOpcode) { + self.compile_declaration_pattern_impl(pattern, def); } /// Creates the declarations for a sript. @@ -1451,7 +1414,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } } - fn class(&mut self, class: &Class, expression: bool) -> JsResult<()> { - self.compile_class(class, expression) + fn class(&mut self, class: &Class, expression: bool) { + self.compile_class(class, expression); } } diff --git a/boa_engine/src/bytecompiler/module.rs b/boa_engine/src/bytecompiler/module.rs index f5a21429595..41ed75320b5 100644 --- a/boa_engine/src/bytecompiler/module.rs +++ b/boa_engine/src/bytecompiler/module.rs @@ -1,36 +1,24 @@ -use boa_ast::{ModuleItem, ModuleItemList}; - -use crate::JsResult; - use super::ByteCompiler; +use boa_ast::{ModuleItem, ModuleItemList}; impl ByteCompiler<'_, '_> { /// Compiles a [`ModuleItemList`]. #[inline] - pub fn compile_module_item_list( - &mut self, - list: &ModuleItemList, - configurable_globals: bool, - ) -> JsResult<()> { + pub fn compile_module_item_list(&mut self, list: &ModuleItemList, configurable_globals: bool) { for node in list.items() { - self.compile_module_item(node, configurable_globals)?; + self.compile_module_item(node, configurable_globals); } - Ok(()) } /// Compiles a [`ModuleItem`]. #[inline] #[allow(unused_variables, clippy::missing_panics_doc)] // Unimplemented - pub fn compile_module_item( - &mut self, - item: &ModuleItem, - configurable_globals: bool, - ) -> JsResult<()> { + pub fn compile_module_item(&mut self, item: &ModuleItem, configurable_globals: bool) { match item { ModuleItem::ImportDeclaration(import) => todo!("import declaration compilation"), ModuleItem::ExportDeclaration(export) => todo!("export declaration compilation"), ModuleItem::StatementListItem(stmt) => { - self.compile_stmt_list_item(stmt, false, configurable_globals) + self.compile_stmt_list_item(stmt, false, configurable_globals); } } } diff --git a/boa_engine/src/bytecompiler/statement/block.rs b/boa_engine/src/bytecompiler/statement/block.rs index dff9e872497..d6b535f8575 100644 --- a/boa_engine/src/bytecompiler/statement/block.rs +++ b/boa_engine/src/bytecompiler/statement/block.rs @@ -1,4 +1,4 @@ -use crate::{bytecompiler::ByteCompiler, vm::Opcode, JsResult}; +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; use boa_ast::statement::Block; @@ -9,12 +9,12 @@ impl ByteCompiler<'_, '_> { block: &Block, use_expr: bool, configurable_globals: bool, - ) -> JsResult<()> { + ) { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); self.create_script_decls(block.statement_list(), configurable_globals); - self.compile_statement_list(block.statement_list(), use_expr, configurable_globals)?; + self.compile_statement_list(block.statement_list(), use_expr, configurable_globals); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -22,7 +22,5 @@ impl ByteCompiler<'_, '_> { self.patch_jump_with_target(push_env.1, index_compile_environment as u32); self.emit_opcode(Opcode::PopEnvironment); - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/break.rs b/boa_engine/src/bytecompiler/statement/break.rs index 190ff3cb9b0..f175565f8ca 100644 --- a/boa_engine/src/bytecompiler/statement/break.rs +++ b/boa_engine/src/bytecompiler/statement/break.rs @@ -1,16 +1,13 @@ -use boa_ast::statement::Break; - use crate::{ bytecompiler::{ByteCompiler, Label}, vm::Opcode, - JsNativeError, JsResult, }; - +use boa_ast::statement::Break; use boa_interner::Sym; impl ByteCompiler<'_, '_> { /// Compile a [`Break`] `boa_ast` node - pub(crate) fn compile_break(&mut self, node: Break) -> JsResult<()> { + pub(crate) fn compile_break(&mut self, node: Break) { if let Some(info) = self.jump_info.last().filter(|info| info.is_try_block()) { let in_finally = info.in_finally(); let in_catch_no_finally = info.in_catch() && !info.has_finally(); @@ -27,11 +24,11 @@ impl ByteCompiler<'_, '_> { self.emit_opcode_with_two_operands(Opcode::Break); if let Some(node_label) = node.label() { - self.search_jump_info_label(target_jump_label, node_label)?; + self.search_jump_info_label(target_jump_label, node_label); if !has_finally_or_is_finally { - self.search_jump_info_label(break_label, node_label)?; - return Ok(()); + self.search_jump_info_label(break_label, node_label); + return; } } else { self.jump_info @@ -43,13 +40,11 @@ impl ByteCompiler<'_, '_> { let info = self .jump_info .last_mut() - // TODO: Currently would allow unlabelled breaks in try_blocks with no - // loops or switch. This can prevented by the early error referenced in line 66. .expect("This try block must exist"); info.push_break_label(break_label); - return Ok(()); + return; } // Emit the break opcode -> (Label, Label) @@ -58,27 +53,21 @@ impl ByteCompiler<'_, '_> { self.search_jump_info_label( break_label, node.label().expect("must exist in this block"), - )?; - self.search_jump_info_label(target_label, node.label().expect("must exist"))?; - return Ok(()); + ); + self.search_jump_info_label(target_label, node.label().expect("must exist")); + return; }; let info = self .jump_info .last_mut() - // TODO: promote to an early error. - .ok_or_else(|| { - JsNativeError::syntax() - .with_message("unlabeled break must be inside loop or switch") - })?; + .expect("unlabeled break must be inside loop or switch"); info.push_break_label(break_label); info.push_break_label(target_label); - - Ok(()) } - fn search_jump_info_label(&mut self, address: Label, node_label: Sym) -> JsResult<()> { + fn search_jump_info_label(&mut self, address: Label, node_label: Sym) { let mut found = false; for info in self.jump_info.iter_mut().rev() { if info.label() == Some(node_label) { @@ -87,16 +76,6 @@ impl ByteCompiler<'_, '_> { break; } } - // TODO: promote to an early error. - if !found { - return Err(JsNativeError::syntax() - .with_message(format!( - "Cannot use the undeclared label '{}'", - self.interner().resolve_expect(node_label) - )) - .into()); - } - - Ok(()) + assert!(found, "Cannot use the undeclared label"); } } diff --git a/boa_engine/src/bytecompiler/statement/continue.rs b/boa_engine/src/bytecompiler/statement/continue.rs index 416715a32ae..9bb1e7455cc 100644 --- a/boa_engine/src/bytecompiler/statement/continue.rs +++ b/boa_engine/src/bytecompiler/statement/continue.rs @@ -1,9 +1,9 @@ +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; use boa_ast::statement::Continue; -use crate::{bytecompiler::ByteCompiler, vm::Opcode, JsNativeError, JsResult}; - impl ByteCompiler<'_, '_> { - pub(crate) fn compile_continue(&mut self, node: Continue) -> JsResult<()> { + #[allow(clippy::unnecessary_wraps)] + pub(crate) fn compile_continue(&mut self, node: Continue) { if let Some(info) = self.jump_info.last().filter(|info| info.is_try_block()) { let in_finally = info.in_finally(); let in_finally_or_has_finally = in_finally || info.has_finally(); @@ -31,13 +31,7 @@ impl ByteCompiler<'_, '_> { } } - // TODO: promote to an early error. - loop_info.ok_or_else(|| { - JsNativeError::syntax().with_message(format!( - "Cannot use the undeclared label '{}'", - self.context.interner().resolve_expect(node_label) - )) - })?; + loop_info.expect("Cannot use the undeclared label"); for _ in 0..emit_for_of_in_exit { self.emit_opcode(Opcode::Pop); @@ -85,19 +79,12 @@ impl ByteCompiler<'_, '_> { .iter_mut() .rev() .filter(|info| info.is_loop()); - let jump_info = items - .next() - // TODO: promote to an early error. - .ok_or_else(|| { - JsNativeError::syntax().with_message("continue must be inside loop") - })?; + let jump_info = items.next().expect("continue must be inside loop"); if !in_finally_or_has_finally { jump_info.push_try_continue_label(cont_label); }; jump_info.push_try_continue_label(set_label); }; - - return Ok(()); } else if let Some(node_label) = node.label() { let items = self.jump_info.iter().rev().filter(|info| info.is_loop()); let mut emit_for_of_in_exit = 0_u32; @@ -113,13 +100,7 @@ impl ByteCompiler<'_, '_> { } } - // TODO: promote to an early error. - loop_info.ok_or_else(|| { - JsNativeError::syntax().with_message(format!( - "Cannot use the undeclared label '{}'", - self.context.interner().resolve_expect(node_label) - )) - })?; + loop_info.expect("Cannot use the undeclared label"); for _ in 0..emit_for_of_in_exit { self.emit_opcode(Opcode::Pop); @@ -147,16 +128,9 @@ impl ByteCompiler<'_, '_> { .iter_mut() .rev() .filter(|info| info.is_loop()); - let jump_info = items - .next() - // TODO: promote to an early error. - .ok_or_else(|| { - JsNativeError::syntax().with_message("continue must be inside loop") - })?; + let jump_info = items.next().expect("continue must be inside loop"); jump_info.push_try_continue_label(cont_label); jump_info.push_try_continue_label(set_label); } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/if.rs b/boa_engine/src/bytecompiler/statement/if.rs index fc828936cef..73ace44ba2c 100644 --- a/boa_engine/src/bytecompiler/statement/if.rs +++ b/boa_engine/src/bytecompiler/statement/if.rs @@ -1,12 +1,12 @@ -use crate::{bytecompiler::ByteCompiler, JsResult}; +use crate::bytecompiler::ByteCompiler; use boa_ast::statement::If; impl ByteCompiler<'_, '_> { - pub(crate) fn compile_if(&mut self, node: &If, configurable_globals: bool) -> JsResult<()> { - self.compile_expr(node.cond(), true)?; + pub(crate) fn compile_if(&mut self, node: &If, configurable_globals: bool) { + self.compile_expr(node.cond(), true); let jelse = self.jump_if_false(); - self.compile_stmt(node.body(), false, configurable_globals)?; + self.compile_stmt(node.body(), false, configurable_globals); match node.else_node() { None => { @@ -15,11 +15,9 @@ impl ByteCompiler<'_, '_> { Some(else_body) => { let exit = self.jump(); self.patch_jump(jelse); - self.compile_stmt(else_body, false, configurable_globals)?; + self.compile_stmt(else_body, false, configurable_globals); self.patch_jump(exit); } } - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/labelled.rs b/boa_engine/src/bytecompiler/statement/labelled.rs index 7491fb16f6e..42f4f8a3903 100644 --- a/boa_engine/src/bytecompiler/statement/labelled.rs +++ b/boa_engine/src/bytecompiler/statement/labelled.rs @@ -1,12 +1,10 @@ -use boa_ast::{ - statement::{Labelled, LabelledItem}, - Statement, -}; - use crate::{ bytecompiler::{ByteCompiler, NodeKind}, vm::Opcode, - JsResult, +}; +use boa_ast::{ + statement::{Labelled, LabelledItem}, + Statement, }; impl ByteCompiler<'_, '_> { @@ -16,7 +14,7 @@ impl ByteCompiler<'_, '_> { labelled: &Labelled, use_expr: bool, configurable_globals: bool, - ) -> JsResult<()> { + ) { let labelled_loc = self.next_opcode_location(); let end_label = self.emit_opcode_with_operand(Opcode::LabelledStart); self.push_labelled_control_info(labelled.label(), labelled_loc); @@ -24,40 +22,40 @@ impl ByteCompiler<'_, '_> { match labelled.item() { LabelledItem::Statement(stmt) => match stmt { Statement::ForLoop(for_loop) => { - self.compile_for_loop(for_loop, Some(labelled.label()), configurable_globals)?; + self.compile_for_loop(for_loop, Some(labelled.label()), configurable_globals); } Statement::ForInLoop(for_in_loop) => { self.compile_for_in_loop( for_in_loop, Some(labelled.label()), configurable_globals, - )?; + ); } Statement::ForOfLoop(for_of_loop) => { self.compile_for_of_loop( for_of_loop, Some(labelled.label()), configurable_globals, - )?; + ); } Statement::WhileLoop(while_loop) => { self.compile_while_loop( while_loop, Some(labelled.label()), configurable_globals, - )?; + ); } Statement::DoWhileLoop(do_while_loop) => { self.compile_do_while_loop( do_while_loop, Some(labelled.label()), configurable_globals, - )?; + ); } - stmt => self.compile_stmt(stmt, use_expr, configurable_globals)?, + stmt => self.compile_stmt(stmt, use_expr, configurable_globals), }, LabelledItem::Function(f) => { - self.function(f.into(), NodeKind::Declaration, false)?; + self.function(f.into(), NodeKind::Declaration, false); } } @@ -65,7 +63,5 @@ impl ByteCompiler<'_, '_> { self.patch_jump_with_target(end_label, labelled_end); self.pop_labelled_control_info(); self.emit_opcode(Opcode::LabelledEnd); - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/loop.rs b/boa_engine/src/bytecompiler/statement/loop.rs index d8c23813eee..0c5d873bf46 100644 --- a/boa_engine/src/bytecompiler/statement/loop.rs +++ b/boa_engine/src/bytecompiler/statement/loop.rs @@ -11,7 +11,6 @@ use boa_interner::Sym; use crate::{ bytecompiler::{Access, ByteCompiler}, vm::{BindingOpcode, Opcode}, - JsResult, }; impl ByteCompiler<'_, '_> { @@ -20,21 +19,21 @@ impl ByteCompiler<'_, '_> { for_loop: &ForLoop, label: Option, configurable_globals: bool, - ) -> JsResult<()> { + ) { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); self.push_empty_loop_jump_control(); if let Some(init) = for_loop.init() { match init { - ForLoopInitializer::Expression(expr) => self.compile_expr(expr, false)?, + ForLoopInitializer::Expression(expr) => self.compile_expr(expr, false), ForLoopInitializer::Var(decl) => { self.create_decls_from_var_decl(decl, configurable_globals); - self.compile_var_decl(decl)?; + self.compile_var_decl(decl); } ForLoopInitializer::Lexical(decl) => { self.create_decls_from_lexical_decl(decl); - self.compile_lexical_decl(decl)?; + self.compile_lexical_decl(decl); } } } @@ -56,19 +55,19 @@ impl ByteCompiler<'_, '_> { self.patch_jump_with_target(continue_start, start_address); if let Some(final_expr) = for_loop.final_expr() { - self.compile_expr(final_expr, false)?; + self.compile_expr(final_expr, false); } self.patch_jump(initial_jump); if let Some(condition) = for_loop.condition() { - self.compile_expr(condition, true)?; + self.compile_expr(condition, true); } else { self.emit_opcode(Opcode::PushTrue); } let exit = self.jump_if_false(); - self.compile_stmt(for_loop.body(), false, configurable_globals)?; + self.compile_stmt(for_loop.body(), false, configurable_globals); self.emit(Opcode::Jump, &[start_address]); @@ -83,8 +82,6 @@ impl ByteCompiler<'_, '_> { self.pop_loop_control_info(); self.emit_opcode(Opcode::LoopEnd); self.emit_opcode(Opcode::PopEnvironment); - - Ok(()) } pub(crate) fn compile_for_in_loop( @@ -92,10 +89,10 @@ impl ByteCompiler<'_, '_> { for_in_loop: &ForInLoop, label: Option, configurable_globals: bool, - ) -> JsResult<()> { + ) { let init_bound_names = bound_names(for_in_loop.initializer()); if init_bound_names.is_empty() { - self.compile_expr(for_in_loop.target(), true)?; + self.compile_expr(for_in_loop.target(), true); } else { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); @@ -103,7 +100,7 @@ impl ByteCompiler<'_, '_> { for name in init_bound_names { self.context.create_mutable_binding(name, false, false); } - self.compile_expr(for_in_loop.target(), true)?; + self.compile_expr(for_in_loop.target(), true); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -138,7 +135,7 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); } IterableLoopInitializer::Var(declaration) => match declaration { Binding::Identifier(ident) => { @@ -150,7 +147,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, true, false); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitVar)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitVar); } }, IterableLoopInitializer::Let(declaration) => match declaration { @@ -162,7 +159,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, false, false); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitLet)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitLet); } }, IterableLoopInitializer::Const(declaration) => match declaration { @@ -174,18 +171,18 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_immutable_binding(ident, true); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitConst)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitConst); } }, IterableLoopInitializer::Pattern(pattern) => { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, true, true); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitVar)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitVar); } } - self.compile_stmt(for_in_loop.body(), false, configurable_globals)?; + self.compile_stmt(for_in_loop.body(), false, configurable_globals); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -203,7 +200,6 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::IteratorClose); self.patch_jump(early_exit); - Ok(()) } pub(crate) fn compile_for_of_loop( @@ -211,10 +207,10 @@ impl ByteCompiler<'_, '_> { for_of_loop: &ForOfLoop, label: Option, configurable_globals: bool, - ) -> JsResult<()> { + ) { let init_bound_names = bound_names(for_of_loop.initializer()); if init_bound_names.is_empty() { - self.compile_expr(for_of_loop.iterable(), true)?; + self.compile_expr(for_of_loop.iterable(), true); } else { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); @@ -222,7 +218,7 @@ impl ByteCompiler<'_, '_> { for name in init_bound_names { self.context.create_mutable_binding(name, false, false); } - self.compile_expr(for_of_loop.iterable(), true)?; + self.compile_expr(for_of_loop.iterable(), true); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -269,7 +265,7 @@ impl ByteCompiler<'_, '_> { Access::Property { access }, false, ByteCompiler::access_set_top_of_stack_expr_fn, - )?; + ); } IterableLoopInitializer::Var(declaration) => match declaration { Binding::Identifier(ident) => { @@ -280,7 +276,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, true, false); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitVar)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitVar); } }, IterableLoopInitializer::Let(declaration) => match declaration { @@ -292,7 +288,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, false, false); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitLet)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitLet); } }, IterableLoopInitializer::Const(declaration) => match declaration { @@ -304,18 +300,18 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_immutable_binding(ident, true); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitConst)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitConst); } }, IterableLoopInitializer::Pattern(pattern) => { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, true, true); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitVar)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitVar); } } - self.compile_stmt(for_of_loop.body(), false, configurable_globals)?; + self.compile_stmt(for_of_loop.body(), false, configurable_globals); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -331,7 +327,6 @@ impl ByteCompiler<'_, '_> { self.pop_loop_control_info(); self.emit_opcode(Opcode::LoopEnd); self.emit_opcode(Opcode::IteratorClose); - Ok(()) } pub(crate) fn compile_while_loop( @@ -339,7 +334,7 @@ impl ByteCompiler<'_, '_> { while_loop: &WhileLoop, label: Option, configurable_globals: bool, - ) -> JsResult<()> { + ) { let (loop_start, loop_exit) = self.emit_opcode_with_two_operands(Opcode::LoopStart); let start_address = self.next_opcode_location(); let (continue_start, continue_exit) = @@ -348,9 +343,9 @@ impl ByteCompiler<'_, '_> { self.patch_jump_with_target(loop_start, start_address); self.patch_jump_with_target(continue_start, start_address); - self.compile_expr(while_loop.condition(), true)?; + self.compile_expr(while_loop.condition(), true); let exit = self.jump_if_false(); - self.compile_stmt(while_loop.body(), false, configurable_globals)?; + self.compile_stmt(while_loop.body(), false, configurable_globals); self.emit(Opcode::Jump, &[start_address]); self.patch_jump(exit); @@ -358,7 +353,6 @@ impl ByteCompiler<'_, '_> { self.patch_jump(continue_exit); self.pop_loop_control_info(); self.emit_opcode(Opcode::LoopEnd); - Ok(()) } pub(crate) fn compile_do_while_loop( @@ -366,7 +360,7 @@ impl ByteCompiler<'_, '_> { do_while_loop: &DoWhileLoop, label: Option, configurable_globals: bool, - ) -> JsResult<()> { + ) { let (loop_start, loop_exit) = self.emit_opcode_with_two_operands(Opcode::LoopStart); let initial_label = self.jump(); @@ -378,12 +372,12 @@ impl ByteCompiler<'_, '_> { self.push_loop_control_info(label, start_address); let condition_label_address = self.next_opcode_location(); - self.compile_expr(do_while_loop.cond(), true)?; + self.compile_expr(do_while_loop.cond(), true); let exit = self.jump_if_false(); self.patch_jump(initial_label); - self.compile_stmt(do_while_loop.body(), false, configurable_globals)?; + self.compile_stmt(do_while_loop.body(), false, configurable_globals); self.emit(Opcode::Jump, &[condition_label_address]); self.patch_jump(exit); self.patch_jump(loop_exit); @@ -391,6 +385,5 @@ impl ByteCompiler<'_, '_> { self.pop_loop_control_info(); self.emit_opcode(Opcode::LoopEnd); - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/mod.rs b/boa_engine/src/bytecompiler/statement/mod.rs index 5f509c41f2c..d7b82424bad 100644 --- a/boa_engine/src/bytecompiler/statement/mod.rs +++ b/boa_engine/src/bytecompiler/statement/mod.rs @@ -1,4 +1,4 @@ -use crate::{bytecompiler::ByteCompiler, vm::Opcode, JsResult}; +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; use boa_ast::Statement; @@ -13,57 +13,51 @@ mod r#try; impl ByteCompiler<'_, '_> { /// Compiles a [`Statement`] `boa_ast` node. - pub fn compile_stmt( - &mut self, - node: &Statement, - use_expr: bool, - configurable_globals: bool, - ) -> JsResult<()> { + pub fn compile_stmt(&mut self, node: &Statement, use_expr: bool, configurable_globals: bool) { match node { - Statement::Var(var) => self.compile_var_decl(var)?, - Statement::If(node) => self.compile_if(node, configurable_globals)?, + Statement::Var(var) => self.compile_var_decl(var), + Statement::If(node) => self.compile_if(node, configurable_globals), Statement::ForLoop(for_loop) => { - self.compile_for_loop(for_loop, None, configurable_globals)?; + self.compile_for_loop(for_loop, None, configurable_globals); } Statement::ForInLoop(for_in_loop) => { - self.compile_for_in_loop(for_in_loop, None, configurable_globals)?; + self.compile_for_in_loop(for_in_loop, None, configurable_globals); } Statement::ForOfLoop(for_of_loop) => { - self.compile_for_of_loop(for_of_loop, None, configurable_globals)?; + self.compile_for_of_loop(for_of_loop, None, configurable_globals); } Statement::WhileLoop(while_loop) => { - self.compile_while_loop(while_loop, None, configurable_globals)?; + self.compile_while_loop(while_loop, None, configurable_globals); } Statement::DoWhileLoop(do_while_loop) => { - self.compile_do_while_loop(do_while_loop, None, configurable_globals)?; + self.compile_do_while_loop(do_while_loop, None, configurable_globals); } Statement::Block(block) => { - self.compile_block(block, use_expr, configurable_globals)?; + self.compile_block(block, use_expr, configurable_globals); } Statement::Labelled(labelled) => { - self.compile_labelled(labelled, use_expr, configurable_globals)?; + self.compile_labelled(labelled, use_expr, configurable_globals); } - Statement::Continue(node) => self.compile_continue(*node)?, - Statement::Break(node) => self.compile_break(*node)?, + Statement::Continue(node) => self.compile_continue(*node), + Statement::Break(node) => self.compile_break(*node), Statement::Throw(throw) => { - self.compile_expr(throw.target(), true)?; + self.compile_expr(throw.target(), true); self.emit(Opcode::Throw, &[]); } Statement::Switch(switch) => { - self.compile_switch(switch, configurable_globals)?; + self.compile_switch(switch, configurable_globals); } Statement::Return(ret) => { if let Some(expr) = ret.target() { - self.compile_expr(expr, true)?; + self.compile_expr(expr, true); } else { self.emit(Opcode::PushUndefined, &[]); } self.emit(Opcode::Return, &[]); } - Statement::Try(t) => self.compile_try(t, use_expr, configurable_globals)?, + Statement::Try(t) => self.compile_try(t, use_expr, configurable_globals), Statement::Empty => {} - Statement::Expression(expr) => self.compile_expr(expr, use_expr)?, + Statement::Expression(expr) => self.compile_expr(expr, use_expr), } - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/switch.rs b/boa_engine/src/bytecompiler/statement/switch.rs index 82b4f751853..f9e96fd2182 100644 --- a/boa_engine/src/bytecompiler/statement/switch.rs +++ b/boa_engine/src/bytecompiler/statement/switch.rs @@ -1,14 +1,9 @@ +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; use boa_ast::statement::Switch; -use crate::{bytecompiler::ByteCompiler, vm::Opcode, JsResult}; - impl ByteCompiler<'_, '_> { /// Compile a [`Switch`] `boa_ast` node - pub(crate) fn compile_switch( - &mut self, - switch: &Switch, - configurable_globals: bool, - ) -> JsResult<()> { + pub(crate) fn compile_switch(&mut self, switch: &Switch, configurable_globals: bool) { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); for case in switch.cases() { @@ -20,10 +15,10 @@ impl ByteCompiler<'_, '_> { self.push_switch_control_info(None, start_address); self.patch_jump_with_target(start_label, start_address); - self.compile_expr(switch.val(), true)?; + self.compile_expr(switch.val(), true); let mut labels = Vec::with_capacity(switch.cases().len()); for case in switch.cases() { - self.compile_expr(case.condition(), true)?; + self.compile_expr(case.condition(), true); labels.push(self.emit_opcode_with_operand(Opcode::Case)); } @@ -31,13 +26,13 @@ impl ByteCompiler<'_, '_> { for (label, case) in labels.into_iter().zip(switch.cases()) { self.patch_jump(label); - self.compile_statement_list(case.body(), false, configurable_globals)?; + self.compile_statement_list(case.body(), false, configurable_globals); } self.patch_jump(exit); if let Some(body) = switch.default() { self.create_script_decls(body, configurable_globals); - self.compile_statement_list(body, false, configurable_globals)?; + self.compile_statement_list(body, false, configurable_globals); } self.pop_switch_control_info(); @@ -49,7 +44,5 @@ impl ByteCompiler<'_, '_> { self.patch_jump_with_target(push_env.0, num_bindings as u32); self.patch_jump_with_target(push_env.1, index_compile_environment as u32); self.emit_opcode(Opcode::PopEnvironment); - - Ok(()) } } diff --git a/boa_engine/src/bytecompiler/statement/try.rs b/boa_engine/src/bytecompiler/statement/try.rs index 8255e548cba..178392e6ea4 100644 --- a/boa_engine/src/bytecompiler/statement/try.rs +++ b/boa_engine/src/bytecompiler/statement/try.rs @@ -1,22 +1,15 @@ +use crate::{ + bytecompiler::{ByteCompiler, Label}, + vm::{BindingOpcode, Opcode}, +}; use boa_ast::{ declaration::Binding, operations::bound_names, statement::{Finally, Try}, }; -use crate::{ - bytecompiler::{ByteCompiler, Label}, - vm::{BindingOpcode, Opcode}, - JsResult, -}; - impl ByteCompiler<'_, '_> { - pub(crate) fn compile_try( - &mut self, - t: &Try, - use_expr: bool, - configurable_globals: bool, - ) -> JsResult<()> { + pub(crate) fn compile_try(&mut self, t: &Try, use_expr: bool, configurable_globals: bool) { let try_start = self.next_opcode_location(); let (catch_start, finally_loc) = self.emit_opcode_with_two_operands(Opcode::TryStart); self.patch_jump_with_target(finally_loc, u32::MAX); @@ -31,7 +24,7 @@ impl ByteCompiler<'_, '_> { let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); self.create_script_decls(t.block().statement_list(), configurable_globals); - self.compile_statement_list(t.block().statement_list(), use_expr, configurable_globals)?; + self.compile_statement_list(t.block().statement_list(), use_expr, configurable_globals); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -44,7 +37,7 @@ impl ByteCompiler<'_, '_> { self.patch_jump(catch_start); if t.catch().is_some() { - self.compile_catch_stmt(t, use_expr, configurable_globals)?; + self.compile_catch_stmt(t, use_expr, configurable_globals); } self.patch_jump(finally); @@ -58,13 +51,11 @@ impl ByteCompiler<'_, '_> { self.set_jump_control_start_address(finally_start); self.patch_jump_with_target(finally_loc, finally_start); // Compile finally statement body - self.compile_finally_stmt(finally, finally_end, configurable_globals)?; + self.compile_finally_stmt(finally, finally_end, configurable_globals); } else { let try_end = self.next_opcode_location(); self.pop_try_control_info(try_end); } - - Ok(()) } pub(crate) fn compile_catch_stmt( @@ -72,7 +63,7 @@ impl ByteCompiler<'_, '_> { parent_try: &Try, use_expr: bool, configurable_globals: bool, - ) -> JsResult<()> { + ) { let catch = parent_try .catch() .expect("Catch must exist for compile_catch_stmt to have been invoked"); @@ -92,7 +83,7 @@ impl ByteCompiler<'_, '_> { for ident in bound_names(pattern) { self.context.create_mutable_binding(ident, false, false); } - self.compile_declaration_pattern(pattern, BindingOpcode::InitLet)?; + self.compile_declaration_pattern(pattern, BindingOpcode::InitLet); } } } else { @@ -104,7 +95,7 @@ impl ByteCompiler<'_, '_> { catch.block().statement_list(), use_expr, configurable_globals, - )?; + ); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -119,8 +110,6 @@ impl ByteCompiler<'_, '_> { self.patch_jump(catch_end); self.set_jump_control_in_finally(false); - - Ok(()) } pub(crate) fn compile_finally_stmt( @@ -128,7 +117,7 @@ impl ByteCompiler<'_, '_> { finally: &Finally, finally_end_label: Label, configurable_globals: bool, - ) -> JsResult<()> { + ) { self.context.push_compile_time_environment(false); let push_env = self.emit_opcode_with_two_operands(Opcode::PushDeclarativeEnvironment); @@ -137,7 +126,7 @@ impl ByteCompiler<'_, '_> { finally.block().statement_list(), false, configurable_globals, - )?; + ); let (num_bindings, compile_environment) = self.context.pop_compile_time_environment(); let index_compile_environment = self.push_compile_environment(compile_environment); @@ -148,7 +137,5 @@ impl ByteCompiler<'_, '_> { self.pop_finally_control_info(); self.patch_jump(finally_end_label); self.emit_opcode(Opcode::FinallyEnd); - - Ok(()) } } diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index e15ff9e27d1..e3ff42256bf 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -230,7 +230,7 @@ impl Context<'_> { let _timer = Profiler::global().start_event("Script compilation", "Main"); let mut compiler = ByteCompiler::new(Sym::MAIN, statement_list.strict(), false, self); compiler.create_script_decls(statement_list, false); - compiler.compile_statement_list(statement_list, true, false)?; + compiler.compile_statement_list(statement_list, true, false); Ok(Gc::new(compiler.finish())) } @@ -240,7 +240,7 @@ impl Context<'_> { let mut compiler = ByteCompiler::new(Sym::MAIN, true, false, self); compiler.create_module_decls(statement_list, false); - compiler.compile_module_item_list(statement_list, false)?; + compiler.compile_module_item_list(statement_list, false); Ok(Gc::new(compiler.finish())) } @@ -464,15 +464,12 @@ impl Context<'_> { } /// Compile the AST into a `CodeBlock` ready to be executed by the VM in a `JSON.parse` context. - pub(crate) fn compile_json_parse( - &mut self, - statement_list: &StatementList, - ) -> JsResult> { + pub(crate) fn compile_json_parse(&mut self, statement_list: &StatementList) -> Gc { let _timer = Profiler::global().start_event("Compilation", "Main"); let mut compiler = ByteCompiler::new(Sym::MAIN, statement_list.strict(), true, self); compiler.create_script_decls(statement_list, false); - compiler.compile_statement_list(statement_list, true, false)?; - Ok(Gc::new(compiler.finish())) + compiler.compile_statement_list(statement_list, true, false); + Gc::new(compiler.finish()) } /// Compile the AST into a `CodeBlock` with an additional declarative environment. @@ -480,11 +477,11 @@ impl Context<'_> { &mut self, statement_list: &StatementList, strict: bool, - ) -> JsResult> { + ) -> Gc { let _timer = Profiler::global().start_event("Compilation", "Main"); let mut compiler = ByteCompiler::new(Sym::MAIN, statement_list.strict(), false, self); - compiler.compile_statement_list_with_new_declarative(statement_list, true, strict)?; - Ok(Gc::new(compiler.finish())) + compiler.compile_statement_list_with_new_declarative(statement_list, true, strict); + Gc::new(compiler.finish()) } } diff --git a/boa_engine/src/tests.rs b/boa_engine/src/tests.rs index e11b109bdc3..189122a0f51 100644 --- a/boa_engine/src/tests.rs +++ b/boa_engine/src/tests.rs @@ -471,7 +471,7 @@ fn test_invalid_break() { let string = forward(&mut context, src); assert_eq!( string, - "Uncaught SyntaxError: unlabeled break must be inside loop or switch" + "Uncaught SyntaxError: Syntax Error: illegal break statement at position: 1:1" ); } @@ -486,7 +486,7 @@ fn test_invalid_continue_target() { let string = forward(&mut context, src); assert_eq!( string, - "Uncaught SyntaxError: Cannot use the undeclared label 'nonexistent'" + "Uncaught SyntaxError: Syntax Error: undefined continue target: nonexistent at position: 1:1" ); } @@ -494,7 +494,10 @@ fn test_invalid_continue_target() { fn test_invalid_continue() { let mut context = Context::default(); let string = forward(&mut context, r"continue;"); - assert_eq!(string, "Uncaught SyntaxError: continue must be inside loop"); + assert_eq!( + string, + "Uncaught SyntaxError: Syntax Error: illegal continue statement at position: 1:1" + ); } #[test] diff --git a/boa_parser/src/parser/function/mod.rs b/boa_parser/src/parser/function/mod.rs index 0607aeba5dd..7b9517e5273 100644 --- a/boa_parser/src/parser/function/mod.rs +++ b/boa_parser/src/parser/function/mod.rs @@ -19,6 +19,10 @@ use crate::{ }, Error, }; +use ast::{ + operations::{check_labels, contains_invalid_object_literal}, + Position, +}; use boa_ast::{ self as ast, declaration::Variable, @@ -448,7 +452,7 @@ where fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("FunctionStatementList", "Parsing"); - StatementList::new( + let statement_list = StatementList::new( self.allow_yield, self.allow_await, true, @@ -456,6 +460,22 @@ where true, false, ) - .parse(cursor, interner) + .parse(cursor, interner)?; + + if let Some(error) = check_labels(&statement_list, interner) { + return Err(Error::lex(LexError::Syntax( + error.into_boxed_str(), + Position::new(1, 1), + ))); + } + + if contains_invalid_object_literal(&statement_list) { + return Err(Error::lex(LexError::Syntax( + "invalid object literal in function statement list".into(), + Position::new(1, 1), + ))); + } + + Ok(statement_list) } } diff --git a/boa_parser/src/parser/mod.rs b/boa_parser/src/parser/mod.rs index acd177c88a7..19e91db93ed 100644 --- a/boa_parser/src/parser/mod.rs +++ b/boa_parser/src/parser/mod.rs @@ -11,6 +11,7 @@ mod tests; use crate::{ error::ParseResult, + lexer::Error as LexError, parser::{ cursor::Cursor, function::{FormalParameters, FunctionStatementList}, @@ -21,8 +22,9 @@ use boa_ast::{ expression::Identifier, function::FormalParameterList, operations::{ - contains, lexically_declared_names, top_level_lexically_declared_names, - top_level_var_declared_names, var_declared_names, ContainsSymbol, + check_labels, contains, contains_invalid_object_literal, lexically_declared_names, + top_level_lexically_declared_names, top_level_var_declared_names, var_declared_names, + ContainsSymbol, }, ModuleItemList, Position, StatementList, }; @@ -330,13 +332,20 @@ where Position::new(1, 1), )); } + } - // TODO: - // It is a Syntax Error if ContainsDuplicateLabels of StatementList with argument « » is true. - // It is a Syntax Error if ContainsUndefinedBreakTarget of StatementList with argument « » is true. - // It is a Syntax Error if ContainsUndefinedContinueTarget of StatementList with arguments « » and « » is true. - // It is a Syntax Error if AllPrivateIdentifiersValid of StatementList with argument « » is false unless the - // source text containing ScriptBody is eval code that is being processed by a direct eval. + if let Some(error) = check_labels(&body, interner) { + return Err(Error::lex(LexError::Syntax( + error.into_boxed_str(), + Position::new(1, 1), + ))); + } + + if contains_invalid_object_literal(&body) { + return Err(Error::lex(LexError::Syntax( + "invalid object literal in script statement list".into(), + Position::new(1, 1), + ))); } Ok(body) diff --git a/boa_parser/src/parser/statement/break_stm/tests.rs b/boa_parser/src/parser/statement/break_stm/tests.rs index 62376923f29..af6bbe979ea 100644 --- a/boa_parser/src/parser/statement/break_stm/tests.rs +++ b/boa_parser/src/parser/statement/break_stm/tests.rs @@ -1,10 +1,10 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ expression::literal::Literal, - statement::{Block, Break, WhileLoop}, + statement::{Block, Break, Labelled, LabelledItem, WhileLoop}, Statement, StatementListItem, }; -use boa_interner::{Interner, Sym}; +use boa_interner::Interner; use boa_macros::utf16; #[test] @@ -54,15 +54,18 @@ fn inline_block_semicolon_insertion() { fn new_line_semicolon_insertion() { let interner = &mut Interner::default(); check_script_parser( - "while (true) { + "test: while (true) { break test }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Break( - Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))), - ))]) - .into(), + vec![Statement::Labelled(Labelled::new( + LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new( + Literal::from(true).into(), + Block::from(vec![StatementListItem::Statement(Statement::Break( + Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))), + ))]) + .into(), + ))), + interner.get_or_intern_static("test", utf16!("test")), )) .into()], interner, @@ -89,50 +92,18 @@ fn inline_block() { fn new_line_block() { let interner = &mut Interner::default(); check_script_parser( - "while (true) { + "test: while (true) { break test; }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Break( - Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))), - ))]) - .into(), - )) - .into()], - interner, - ); -} - -#[test] -fn reserved_label() { - let interner = &mut Interner::default(); - check_script_parser( - "while (true) { - break await; - }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Break( - Break::new(Some(Sym::AWAIT)), - ))]) - .into(), - )) - .into()], - interner, - ); - - let interner = &mut Interner::default(); - check_script_parser( - "while (true) { - break yield; - }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Break( - Break::new(Some(Sym::YIELD)), - ))]) - .into(), + vec![Statement::Labelled(Labelled::new( + LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new( + Literal::from(true).into(), + Block::from(vec![StatementListItem::Statement(Statement::Break( + Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))), + ))]) + .into(), + ))), + interner.get_or_intern_static("test", utf16!("test")), )) .into()], interner, diff --git a/boa_parser/src/parser/statement/continue_stm/tests.rs b/boa_parser/src/parser/statement/continue_stm/tests.rs index 9a951411094..9020ad07096 100644 --- a/boa_parser/src/parser/statement/continue_stm/tests.rs +++ b/boa_parser/src/parser/statement/continue_stm/tests.rs @@ -1,10 +1,10 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ expression::literal::Literal, - statement::{Block, Continue, WhileLoop}, + statement::{Block, Continue, Labelled, LabelledItem, WhileLoop}, Statement, StatementListItem, }; -use boa_interner::{Interner, Sym}; +use boa_interner::Interner; use boa_macros::utf16; #[test] @@ -54,15 +54,18 @@ fn inline_block_semicolon_insertion() { fn new_line_semicolon_insertion() { let interner = &mut Interner::default(); check_script_parser( - "while (true) { + "test: while (true) { continue test }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Continue( - Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))), - ))]) - .into(), + vec![Statement::Labelled(Labelled::new( + LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new( + Literal::from(true).into(), + Block::from(vec![StatementListItem::Statement(Statement::Continue( + Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))), + ))]) + .into(), + ))), + interner.get_or_intern_static("test", utf16!("test")), )) .into()], interner, @@ -89,50 +92,18 @@ fn inline_block() { fn new_line_block() { let interner = &mut Interner::default(); check_script_parser( - "while (true) { + "test: while (true) { continue test; }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Continue( - Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))), - ))]) - .into(), - )) - .into()], - interner, - ); -} - -#[test] -fn reserved_label() { - let interner = &mut Interner::default(); - check_script_parser( - "while (true) { - continue await; - }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Continue( - Continue::new(Some(Sym::AWAIT)), - ))]) - .into(), - )) - .into()], - interner, - ); - - let interner = &mut Interner::default(); - check_script_parser( - "while (true) { - continue yield; - }", - vec![Statement::WhileLoop(WhileLoop::new( - Literal::from(true).into(), - Block::from(vec![StatementListItem::Statement(Statement::Continue( - Continue::new(Some(Sym::YIELD)), - ))]) - .into(), + vec![Statement::Labelled(Labelled::new( + LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new( + Literal::from(true).into(), + Block::from(vec![StatementListItem::Statement(Statement::Continue( + Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))), + ))]) + .into(), + ))), + interner.get_or_intern_static("test", utf16!("test")), )) .into()], interner, diff --git a/boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs b/boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs index deaa12066e1..781677151e7 100644 --- a/boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs +++ b/boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs @@ -16,7 +16,10 @@ use crate::{ }; use ast::{ function::PrivateName, - operations::{class_private_name_resolver, lexically_declared_names, var_declared_names}, + operations::{ + check_labels, class_private_name_resolver, contains_invalid_object_literal, + lexically_declared_names, var_declared_names, + }, }; use boa_ast::{ self as ast, @@ -1358,20 +1361,35 @@ where } } // ClassStaticBlockBody : ClassStaticBlockStatementList - // It is a Syntax Error if ContainsArguments of ClassStaticBlockStatementList is true. - // It is a Syntax Error if ClassStaticBlockStatementList Contains SuperCall is true. function::ClassElement::StaticBlock(block) => { for node in block.statements() { + // It is a Syntax Error if ContainsArguments of ClassStaticBlockStatementList is true. if contains_arguments(node) { return Err(Error::general( "'arguments' not allowed in class static block", position, )); } + + // It is a Syntax Error if ClassStaticBlockStatementList Contains SuperCall is true. if contains(node, ContainsSymbol::SuperCall) { return Err(Error::general("invalid super usage", position)); } } + + if let Some(error) = check_labels(block, interner) { + return Err(Error::lex(LexError::Syntax( + error.into_boxed_str(), + position, + ))); + } + + if contains_invalid_object_literal(block) { + return Err(Error::lex(LexError::Syntax( + "invalid object literal in class static block statement list".into(), + position, + ))); + } } _ => {} } diff --git a/boa_parser/src/parser/statement/mod.rs b/boa_parser/src/parser/statement/mod.rs index 3ed2b7ab19e..ada4728d717 100644 --- a/boa_parser/src/parser/statement/mod.rs +++ b/boa_parser/src/parser/statement/mod.rs @@ -47,6 +47,10 @@ use crate::{ }, Error, }; +use ast::{ + operations::{check_labels, contains_invalid_object_literal}, + Position, +}; use boa_ast::{ self as ast, pattern::{ArrayPattern, ArrayPatternElement, ObjectPatternElement}, @@ -890,7 +894,23 @@ where fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let mut list = Vec::new(); while cursor.peek(0, interner)?.is_some() { - list.push(ModuleItem.parse(cursor, interner)?); + let item = ModuleItem.parse(cursor, interner)?; + + if let Some(error) = check_labels(&item, interner) { + return Err(Error::lex(LexError::Syntax( + error.into_boxed_str(), + Position::new(1, 1), + ))); + } + + if contains_invalid_object_literal(&item) { + return Err(Error::lex(LexError::Syntax( + "invalid object literal in module item list".into(), + Position::new(1, 1), + ))); + } + + list.push(item); } Ok(list.into())