summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus-emitter/src/ast_emitter.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/jsparagus-emitter/src/ast_emitter.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/jsparagus-emitter/src/ast_emitter.rs')
-rw-r--r--third_party/rust/jsparagus-emitter/src/ast_emitter.rs961
1 files changed, 961 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-emitter/src/ast_emitter.rs b/third_party/rust/jsparagus-emitter/src/ast_emitter.rs
new file mode 100644
index 0000000000..287f5b8d35
--- /dev/null
+++ b/third_party/rust/jsparagus-emitter/src/ast_emitter.rs
@@ -0,0 +1,961 @@
+//! High-level bytecode emitter.
+//!
+//! Converts AST nodes to bytecode.
+
+use crate::array_emitter::*;
+use crate::block_emitter::BlockEmitter;
+use crate::compilation_info::CompilationInfo;
+use crate::emitter::{EmitError, EmitOptions, InstructionWriter};
+use crate::emitter_scope::{EmitterScopeStack, NameLocation};
+use crate::expression_emitter::*;
+use crate::function_declaration_emitter::{
+ AnnexBFunctionDeclarationEmitter, LazyFunctionEmitter, LexicalFunctionDeclarationEmitter,
+};
+use crate::object_emitter::*;
+use crate::reference_op_emitter::{
+ AssignmentEmitter, CallEmitter, DeclarationEmitter, ElemReferenceEmitter, GetElemEmitter,
+ GetNameEmitter, GetPropEmitter, GetSuperElemEmitter, GetSuperPropEmitter, NameReferenceEmitter,
+ NewEmitter, PropReferenceEmitter,
+};
+use crate::script_emitter::ScriptEmitter;
+use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
+use ast::types::*;
+use stencil::opcode::Opcode;
+use stencil::regexp::RegExpItem;
+use stencil::result::EmitResult;
+use stencil::script::ScriptStencil;
+
+use crate::control_structures::{
+ BreakEmitter, CForEmitter, ContinueEmitter, ControlStructureStack, DoWhileEmitter,
+ ForwardJumpEmitter, JumpKind, LabelEmitter, WhileEmitter,
+};
+
+/// Emit a program, converting the AST directly to bytecode.
+pub fn emit_program<'alloc>(
+ ast: &Program,
+ options: &EmitOptions,
+ mut compilation_info: CompilationInfo<'alloc>,
+) -> Result<EmitResult<'alloc>, EmitError> {
+ let emitter = AstEmitter::new(options, &mut compilation_info);
+
+ let script = match ast {
+ Program::Script(script) => emitter.emit_script(script)?,
+ _ => {
+ return Err(EmitError::NotImplemented("TODO: modules"));
+ }
+ };
+
+ compilation_info.scripts.set_top_level(script);
+
+ Ok(EmitResult::new(
+ compilation_info.atoms.into(),
+ compilation_info.slices.into(),
+ compilation_info.scope_data_map.into(),
+ compilation_info.regexps.into(),
+ compilation_info.scripts.into(),
+ compilation_info.script_data_list.into(),
+ ))
+}
+
+pub struct AstEmitter<'alloc, 'opt> {
+ pub emit: InstructionWriter,
+ pub scope_stack: EmitterScopeStack,
+ pub options: &'opt EmitOptions,
+ pub compilation_info: &'opt mut CompilationInfo<'alloc>,
+ pub control_stack: ControlStructureStack,
+}
+
+impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
+ fn new(
+ options: &'opt EmitOptions,
+ compilation_info: &'opt mut CompilationInfo<'alloc>,
+ ) -> Self {
+ Self {
+ emit: InstructionWriter::new(),
+ scope_stack: EmitterScopeStack::new(),
+ options,
+ compilation_info,
+ control_stack: ControlStructureStack::new(),
+ }
+ }
+
+ pub fn lookup_name(&mut self, name: SourceAtomSetIndex) -> NameLocation {
+ self.scope_stack.lookup_name(name)
+ }
+
+ pub fn lookup_name_in_var(&mut self, name: SourceAtomSetIndex) -> NameLocation {
+ self.scope_stack.lookup_name_in_var(name)
+ }
+
+ fn emit_script(mut self, ast: &Script) -> Result<ScriptStencil, EmitError> {
+ let scope_data_map = &self.compilation_info.scope_data_map;
+ let function_declarations = &self.compilation_info.function_declarations;
+
+ let scope_index = scope_data_map.get_global_index();
+ let scope_data = scope_data_map.get_global_at(scope_index);
+
+ let top_level_functions: Vec<&Function> = scope_data
+ .functions
+ .iter()
+ .map(|key| {
+ *function_declarations
+ .get(key)
+ .expect("function should exist")
+ })
+ .collect();
+
+ ScriptEmitter {
+ top_level_functions: top_level_functions.iter(),
+ top_level_function: |emitter, fun| emitter.emit_top_level_function_declaration(fun),
+ statements: ast.statements.iter(),
+ statement: |emitter, statement| emitter.emit_statement(statement),
+ }
+ .emit(&mut self)?;
+
+ let script = self.emit.into_stencil(
+ &mut self.compilation_info.script_data_list,
+ self.options.extent.clone(),
+ )?;
+
+ Ok(script)
+ }
+
+ fn emit_top_level_function_declaration(&mut self, fun: &Function) -> Result<(), EmitError> {
+ if fun.is_generator {
+ return Err(EmitError::NotImplemented("TODO: Generator"));
+ }
+ if fun.is_async {
+ return Err(EmitError::NotImplemented("TODO: Async function"));
+ }
+
+ let stencil_index = *self
+ .compilation_info
+ .function_stencil_indices
+ .get(fun)
+ .expect("ScriptStencil should be created");
+
+ // NOTE: GCIndex for the function is implicitly handled by
+ // global_or_eval_decl_instantiation.
+ LazyFunctionEmitter { stencil_index }.emit(self);
+
+ Ok(())
+ }
+
+ fn emit_non_top_level_function_declaration(&mut self, fun: &Function) -> Result<(), EmitError> {
+ if fun.is_generator {
+ return Err(EmitError::NotImplemented("TODO: Generator"));
+ }
+ if fun.is_async {
+ return Err(EmitError::NotImplemented("TODO: Async function"));
+ }
+
+ let stencil_index = *self
+ .compilation_info
+ .function_stencil_indices
+ .get(fun)
+ .expect("ScriptStencil should be created");
+
+ let is_annex_b = self
+ .compilation_info
+ .function_declaration_properties
+ .is_annex_b(stencil_index);
+
+ let fun_index = LazyFunctionEmitter { stencil_index }.emit(self);
+
+ let name = self
+ .compilation_info
+ .scripts
+ .get(stencil_index)
+ .fun_name()
+ .expect("Function declaration should have name");
+
+ if is_annex_b {
+ AnnexBFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
+ } else {
+ LexicalFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
+ }
+
+ Ok(())
+ }
+
+ fn emit_statement(&mut self, ast: &Statement) -> Result<(), EmitError> {
+ match ast {
+ Statement::ClassDeclaration(_) => {
+ return Err(EmitError::NotImplemented("TODO: ClassDeclaration"));
+ }
+ Statement::BlockStatement { block, .. } => {
+ let scope_data_map = &self.compilation_info.scope_data_map;
+ let function_declarations = &self.compilation_info.function_declarations;
+
+ let scope_index = scope_data_map.get_index(block);
+ let scope_data = scope_data_map.get_lexical_at(scope_index);
+
+ let functions: Vec<&Function> = scope_data
+ .functions
+ .iter()
+ .map(|key| {
+ *function_declarations
+ .get(key)
+ .expect("function should exist")
+ })
+ .collect();
+
+ BlockEmitter {
+ scope_index: self.compilation_info.scope_data_map.get_index(block),
+ functions: functions.iter(),
+ function: |emitter, fun| emitter.emit_non_top_level_function_declaration(fun),
+ statements: block.statements.iter(),
+ statement: |emitter, statement| emitter.emit_statement(statement),
+ }
+ .emit(self)?;
+ }
+ Statement::BreakStatement { label, .. } => {
+ BreakEmitter {
+ label: label.as_ref().map(|x| x.value),
+ }
+ .emit(self);
+ }
+ Statement::ContinueStatement { label, .. } => {
+ ContinueEmitter {
+ label: label.as_ref().map(|x| x.value),
+ }
+ .emit(self);
+ }
+ Statement::DebuggerStatement { .. } => {
+ self.emit.debugger();
+ }
+ Statement::DoWhileStatement { block, test, .. } => {
+ DoWhileEmitter {
+ enclosing_emitter_scope_depth: self.scope_stack.current_depth(),
+ block: |emitter| emitter.emit_statement(block),
+ test: |emitter| emitter.emit_expression(test),
+ }
+ .emit(self)?;
+ }
+ Statement::EmptyStatement { .. } => (),
+ Statement::ExpressionStatement(ast) => {
+ ExpressionEmitter {
+ expr: |emitter| emitter.emit_expression(ast),
+ }
+ .emit(self)?;
+ }
+ Statement::ForInStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: ForInStatement"));
+ }
+ Statement::ForOfStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: ForOfStatement"));
+ }
+ Statement::ForStatement {
+ init,
+ test,
+ update,
+ block,
+ ..
+ } => {
+ CForEmitter {
+ enclosing_emitter_scope_depth: self.scope_stack.current_depth(),
+ maybe_init: init,
+ maybe_test: test,
+ maybe_update: update,
+ init: |emitter, val| match val {
+ VariableDeclarationOrExpression::VariableDeclaration(ast) => {
+ emitter.emit_variable_declaration_statement(ast)
+ }
+ VariableDeclarationOrExpression::Expression(expr) => {
+ emitter.emit_expression(expr)?;
+ emitter.emit.pop();
+ Ok(())
+ }
+ },
+ test: |emitter, expr| emitter.emit_expression(expr),
+ update: |emitter, expr| {
+ emitter.emit_expression(expr)?;
+ emitter.emit.pop();
+ Ok(())
+ },
+ block: |emitter| emitter.emit_statement(block),
+ }
+ .emit(self)?;
+ }
+ Statement::IfStatement(if_statement) => {
+ self.emit_if(if_statement)?;
+ }
+ Statement::LabelledStatement { label, body, .. } => {
+ LabelEmitter {
+ enclosing_emitter_scope_depth: self.scope_stack.current_depth(),
+ name: label.value,
+ body: |emitter| emitter.emit_statement(body),
+ }
+ .emit(self)?;
+ }
+ Statement::ReturnStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: ReturnStatement"));
+ }
+ Statement::SwitchStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: SwitchStatement"));
+ }
+ Statement::SwitchStatementWithDefault { .. } => {
+ return Err(EmitError::NotImplemented(
+ "TODO: SwitchStatementWithDefault",
+ ));
+ }
+ Statement::ThrowStatement { expression, .. } => {
+ self.emit_expression(expression)?;
+ self.emit.throw_();
+ }
+ Statement::TryCatchStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: TryCatchStatement"));
+ }
+ Statement::TryFinallyStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: TryFinallyStatement"));
+ }
+ Statement::VariableDeclarationStatement(ast) => {
+ self.emit_variable_declaration_statement(ast)?;
+ }
+ Statement::WhileStatement { test, block, .. } => {
+ WhileEmitter {
+ enclosing_emitter_scope_depth: self.scope_stack.current_depth(),
+ test: |emitter| emitter.emit_expression(test),
+ block: |emitter| emitter.emit_statement(block),
+ }
+ .emit(self)?;
+ }
+ Statement::WithStatement { .. } => {
+ return Err(EmitError::NotImplemented("TODO: WithStatement"));
+ }
+ Statement::FunctionDeclaration(_) => {}
+ };
+
+ Ok(())
+ }
+
+ fn emit_variable_declaration_statement(
+ &mut self,
+ ast: &VariableDeclaration,
+ ) -> Result<(), EmitError> {
+ match ast.kind {
+ VariableDeclarationKind::Var { .. } => {}
+ VariableDeclarationKind::Let { .. } | VariableDeclarationKind::Const { .. } => {}
+ }
+
+ for decl in &ast.declarators {
+ if let Some(init) = &decl.init {
+ self.emit_declaration_assignment(&decl.binding, &init)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ fn emit_declaration_assignment(
+ &mut self,
+ binding: &Binding,
+ init: &Expression,
+ ) -> Result<(), EmitError> {
+ match binding {
+ Binding::BindingIdentifier(binding) => {
+ let name = binding.name.value;
+ DeclarationEmitter {
+ lhs: |emitter| Ok(NameReferenceEmitter { name }.emit_for_declaration(emitter)),
+ rhs: |emitter| emitter.emit_expression(init),
+ }
+ .emit(self)?;
+ self.emit.pop();
+ }
+ _ => {
+ return Err(EmitError::NotImplemented("BindingPattern"));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn emit_this(&mut self) -> Result<(), EmitError> {
+ Err(EmitError::NotImplemented("TODO: this"))
+ }
+
+ fn emit_if(&mut self, if_statement: &IfStatement) -> Result<(), EmitError> {
+ self.emit_expression(&if_statement.test)?;
+
+ let alternate_jump = ForwardJumpEmitter {
+ jump: JumpKind::JumpIfFalse,
+ }
+ .emit(self);
+
+ // Then branch
+ self.emit.jump_target();
+ self.emit_statement(&if_statement.consequent)?;
+
+ if let Some(alternate) = &if_statement.alternate {
+ let then_jump = ForwardJumpEmitter {
+ jump: JumpKind::Goto,
+ }
+ .emit(self);
+ // ^^ part of then branch
+
+ // Else branch
+ alternate_jump.patch_not_merge(self);
+ self.emit_statement(alternate)?;
+
+ // Merge point after else
+ then_jump.patch_merge(self);
+ } else {
+ // Merge point without else
+ alternate_jump.patch_merge(self);
+ }
+
+ Ok(())
+ }
+
+ fn emit_expression(&mut self, ast: &Expression) -> Result<(), EmitError> {
+ match ast {
+ Expression::ClassExpression(_) => {
+ return Err(EmitError::NotImplemented("TODO: ClassExpression"));
+ }
+
+ Expression::LiteralBooleanExpression { value, .. } => {
+ self.emit.emit_boolean(*value);
+ }
+
+ Expression::LiteralInfinityExpression { .. } => {
+ self.emit.double_(std::f64::INFINITY);
+ }
+
+ Expression::LiteralNullExpression { .. } => {
+ self.emit.null();
+ }
+
+ Expression::LiteralNumericExpression(num) => {
+ self.emit.numeric(num.value);
+ }
+
+ Expression::LiteralRegExpExpression {
+ pattern,
+ global,
+ ignore_case,
+ multi_line,
+ dot_all,
+ sticky,
+ unicode,
+ ..
+ } => {
+ let item = RegExpItem {
+ pattern: *pattern,
+ global: *global,
+ ignore_case: *ignore_case,
+ multi_line: *multi_line,
+ dot_all: *dot_all,
+ sticky: *sticky,
+ unicode: *unicode,
+ };
+ let regexp_index = self.compilation_info.regexps.push(item);
+ let index = self.emit.get_regexp_gcthing_index(regexp_index);
+ self.emit.reg_exp(index);
+ }
+
+ Expression::LiteralStringExpression { value, .. } => {
+ let str_index = self.emit.get_atom_gcthing_index(*value);
+ self.emit.string(str_index);
+ }
+
+ Expression::ArrayExpression(ast) => {
+ self.emit_array_expression(ast)?;
+ }
+
+ Expression::ArrowExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: ArrowExpression"));
+ }
+
+ Expression::AssignmentExpression {
+ binding,
+ expression,
+ ..
+ } => {
+ self.emit_assignment_expression(binding, expression)?;
+ }
+
+ Expression::BinaryExpression {
+ operator,
+ left,
+ right,
+ ..
+ } => {
+ self.emit_binary_expression(operator, left, right)?;
+ }
+
+ Expression::CallExpression(CallExpression {
+ callee, arguments, ..
+ }) => {
+ self.emit_call_expression(callee, arguments)?;
+ }
+
+ Expression::CompoundAssignmentExpression { .. } => {
+ return Err(EmitError::NotImplemented(
+ "TODO: CompoundAssignmentExpression",
+ ));
+ }
+
+ Expression::ConditionalExpression {
+ test,
+ consequent,
+ alternate,
+ ..
+ } => {
+ self.emit_conditional_expression(test, consequent, alternate)?;
+ }
+
+ Expression::FunctionExpression(_) => {
+ return Err(EmitError::NotImplemented("TODO: FunctionExpression"));
+ }
+
+ Expression::IdentifierExpression(ast) => {
+ self.emit_identifier_expression(ast);
+ }
+
+ Expression::MemberExpression(ast) => {
+ self.emit_member_expression(ast)?;
+ }
+
+ Expression::NewExpression {
+ callee, arguments, ..
+ } => {
+ self.emit_new_expression(callee, arguments)?;
+ }
+
+ Expression::NewTargetExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: NewTargetExpression"));
+ }
+
+ Expression::ObjectExpression(ast) => {
+ self.emit_object_expression(ast)?;
+ }
+
+ Expression::OptionalChain { .. } => {
+ return Err(EmitError::NotImplemented("TODO: OptionalChain"));
+ }
+
+ Expression::OptionalExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: OptionalExpression"));
+ }
+
+ Expression::UnaryExpression {
+ operator, operand, ..
+ } => {
+ let opcode = match operator {
+ UnaryOperator::Plus { .. } => Opcode::Pos,
+ UnaryOperator::Minus { .. } => Opcode::Neg,
+ UnaryOperator::LogicalNot { .. } => Opcode::Not,
+ UnaryOperator::BitwiseNot { .. } => Opcode::BitNot,
+ UnaryOperator::Void { .. } => Opcode::Void,
+ UnaryOperator::Typeof { .. } => {
+ return Err(EmitError::NotImplemented("TODO: Typeof"));
+ }
+ UnaryOperator::Delete { .. } => {
+ return Err(EmitError::NotImplemented("TODO: Delete"));
+ }
+ };
+ self.emit_expression(operand)?;
+ self.emit.emit_unary_op(opcode);
+ }
+
+ Expression::TemplateExpression(_) => {
+ return Err(EmitError::NotImplemented("TODO: TemplateExpression"));
+ }
+
+ Expression::ThisExpression { .. } => {
+ self.emit_this()?;
+ }
+
+ Expression::UpdateExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: UpdateExpression"));
+ }
+
+ Expression::YieldExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: YieldExpression"));
+ }
+
+ Expression::YieldGeneratorExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: YieldGeneratorExpression"));
+ }
+
+ Expression::AwaitExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: AwaitExpression"));
+ }
+
+ Expression::ImportCallExpression { .. } => {
+ return Err(EmitError::NotImplemented("TODO: ImportCallExpression"));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn emit_binary_expression(
+ &mut self,
+ operator: &BinaryOperator,
+ left: &Expression,
+ right: &Expression,
+ ) -> Result<(), EmitError> {
+ let opcode = match operator {
+ BinaryOperator::Equals { .. } => Opcode::Eq,
+ BinaryOperator::NotEquals { .. } => Opcode::Ne,
+ BinaryOperator::StrictEquals { .. } => Opcode::StrictEq,
+ BinaryOperator::StrictNotEquals { .. } => Opcode::StrictNe,
+ BinaryOperator::LessThan { .. } => Opcode::Lt,
+ BinaryOperator::LessThanOrEqual { .. } => Opcode::Le,
+ BinaryOperator::GreaterThan { .. } => Opcode::Gt,
+ BinaryOperator::GreaterThanOrEqual { .. } => Opcode::Ge,
+ BinaryOperator::In { .. } => Opcode::In,
+ BinaryOperator::Instanceof { .. } => Opcode::Instanceof,
+ BinaryOperator::LeftShift { .. } => Opcode::Lsh,
+ BinaryOperator::RightShift { .. } => Opcode::Rsh,
+ BinaryOperator::RightShiftExt { .. } => Opcode::Ursh,
+ BinaryOperator::Add { .. } => Opcode::Add,
+ BinaryOperator::Sub { .. } => Opcode::Sub,
+ BinaryOperator::Mul { .. } => Opcode::Mul,
+ BinaryOperator::Div { .. } => Opcode::Div,
+ BinaryOperator::Mod { .. } => Opcode::Mod,
+ BinaryOperator::Pow { .. } => Opcode::Pow,
+ BinaryOperator::BitwiseOr { .. } => Opcode::BitOr,
+ BinaryOperator::BitwiseXor { .. } => Opcode::BitXor,
+ BinaryOperator::BitwiseAnd { .. } => Opcode::BitAnd,
+
+ BinaryOperator::Coalesce { .. } => {
+ self.emit_short_circuit(JumpKind::Coalesce, left, right)?;
+ return Ok(());
+ }
+ BinaryOperator::LogicalOr { .. } => {
+ self.emit_short_circuit(JumpKind::LogicalOr, left, right)?;
+ return Ok(());
+ }
+ BinaryOperator::LogicalAnd { .. } => {
+ self.emit_short_circuit(JumpKind::LogicalAnd, left, right)?;
+ return Ok(());
+ }
+
+ BinaryOperator::Comma { .. } => {
+ self.emit_expression(left)?;
+ self.emit.pop();
+ self.emit_expression(right)?;
+ return Ok(());
+ }
+ };
+
+ self.emit_expression(left)?;
+ self.emit_expression(right)?;
+ self.emit.emit_binary_op(opcode);
+ Ok(())
+ }
+
+ fn emit_short_circuit(
+ &mut self,
+ jump: JumpKind,
+ left: &Expression,
+ right: &Expression,
+ ) -> Result<(), EmitError> {
+ self.emit_expression(left)?;
+ let jump = ForwardJumpEmitter { jump: jump }.emit(self);
+ self.emit.pop();
+ self.emit_expression(right)?;
+ jump.patch_merge(self);
+ return Ok(());
+ }
+
+ fn emit_object_expression(&mut self, object: &ObjectExpression) -> Result<(), EmitError> {
+ ObjectEmitter {
+ properties: object.properties.iter(),
+ prop: |emitter, state, prop| emitter.emit_object_property(state, prop),
+ }
+ .emit(self)
+ }
+
+ fn emit_object_property(
+ &mut self,
+ state: &mut ObjectEmitterState,
+ property: &ObjectProperty,
+ ) -> Result<(), EmitError> {
+ match property {
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::DataProperty(
+ DataProperty {
+ property_name,
+ expression: prop_value,
+ ..
+ },
+ )) => match property_name {
+ PropertyName::StaticPropertyName(StaticPropertyName { value, .. }) => {
+ NamePropertyEmitter {
+ state,
+ key: *value,
+ value: |emitter| emitter.emit_expression(prop_value),
+ }
+ .emit(self)?;
+ }
+ PropertyName::StaticNumericPropertyName(NumericLiteral { value, .. }) => {
+ IndexPropertyEmitter {
+ state,
+ key: *value,
+ value: |emitter| emitter.emit_expression(prop_value),
+ }
+ .emit(self)?;
+ }
+ PropertyName::ComputedPropertyName(ComputedPropertyName {
+ expression: prop_key,
+ ..
+ }) => {
+ ComputedPropertyEmitter {
+ state,
+ key: |emitter| emitter.emit_expression(prop_key),
+ value: |emitter| emitter.emit_expression(prop_value),
+ }
+ .emit(self)?;
+ }
+ },
+ _ => return Err(EmitError::NotImplemented("TODO: non data property")),
+ }
+ Ok(())
+ }
+
+ fn emit_array_expression(&mut self, array: &ArrayExpression) -> Result<(), EmitError> {
+ ArrayEmitter {
+ elements: array.elements.iter(),
+ elem_kind: |e| match e {
+ ArrayExpressionElement::Expression(..) => ArrayElementKind::Normal,
+ ArrayExpressionElement::Elision { .. } => ArrayElementKind::Elision,
+ ArrayExpressionElement::SpreadElement(..) => ArrayElementKind::Spread,
+ },
+ elem: |emitter, state, elem| {
+ match elem {
+ ArrayExpressionElement::Expression(expr) => {
+ ArrayElementEmitter {
+ state,
+ elem: |emitter| emitter.emit_expression(expr),
+ }
+ .emit(emitter)?;
+ }
+ ArrayExpressionElement::Elision { .. } => {
+ ArrayElisionEmitter { state }.emit(emitter);
+ }
+ ArrayExpressionElement::SpreadElement(expr) => {
+ ArraySpreadEmitter {
+ state,
+ elem: |emitter| emitter.emit_expression(expr),
+ }
+ .emit(emitter)?;
+ }
+ }
+ Ok(())
+ },
+ }
+ .emit(self)
+ }
+
+ fn emit_conditional_expression(
+ &mut self,
+ test: &Expression,
+ consequent: &Expression,
+ alternate: &Expression,
+ ) -> Result<(), EmitError> {
+ self.emit_expression(test)?;
+
+ let else_jump = ForwardJumpEmitter {
+ jump: JumpKind::JumpIfFalse,
+ }
+ .emit(self);
+
+ // Then branch
+ self.emit.jump_target();
+ self.emit_expression(consequent)?;
+
+ let finally_jump = ForwardJumpEmitter {
+ jump: JumpKind::Goto,
+ }
+ .emit(self);
+
+ // Else branch
+ else_jump.patch_not_merge(self);
+ self.emit_expression(alternate)?;
+
+ // Merge point
+ finally_jump.patch_merge(self);
+
+ Ok(())
+ }
+
+ fn emit_assignment_expression(
+ &mut self,
+ binding: &AssignmentTarget,
+ expression: &Expression,
+ ) -> Result<(), EmitError> {
+ AssignmentEmitter {
+ lhs: |emitter| match binding {
+ AssignmentTarget::SimpleAssignmentTarget(
+ SimpleAssignmentTarget::AssignmentTargetIdentifier(
+ AssignmentTargetIdentifier { name, .. },
+ ),
+ ) => Ok(NameReferenceEmitter { name: name.value }.emit_for_assignment(emitter)),
+ _ => Err(EmitError::NotImplemented(
+ "non-identifier assignment target",
+ )),
+ },
+ rhs: |emitter| emitter.emit_expression(expression),
+ }
+ .emit(self)
+ }
+
+ fn emit_identifier_expression(&mut self, ast: &IdentifierExpression) {
+ let name = ast.name.value;
+ GetNameEmitter { name }.emit(self);
+ }
+
+ fn emit_member_expression(&mut self, ast: &MemberExpression) -> Result<(), EmitError> {
+ match ast {
+ MemberExpression::ComputedMemberExpression(ComputedMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ expression,
+ ..
+ }) => GetElemEmitter {
+ obj: |emitter| emitter.emit_expression(object),
+ key: |emitter| emitter.emit_expression(expression),
+ }
+ .emit(self),
+
+ MemberExpression::ComputedMemberExpression(ComputedMemberExpression {
+ object: ExpressionOrSuper::Super { .. },
+ expression,
+ ..
+ }) => GetSuperElemEmitter {
+ this: |emitter| emitter.emit_this(),
+ key: |emitter| emitter.emit_expression(expression),
+ }
+ .emit(self),
+
+ MemberExpression::StaticMemberExpression(StaticMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ property,
+ ..
+ }) => GetPropEmitter {
+ obj: |emitter| emitter.emit_expression(object),
+ key: property.value,
+ }
+ .emit(self),
+
+ MemberExpression::StaticMemberExpression(StaticMemberExpression {
+ object: ExpressionOrSuper::Super { .. },
+ property,
+ ..
+ }) => GetSuperPropEmitter {
+ this: |emitter| emitter.emit_this(),
+ key: property.value,
+ }
+ .emit(self),
+
+ MemberExpression::PrivateFieldExpression(PrivateFieldExpression { .. }) => {
+ Err(EmitError::NotImplemented("PrivateFieldExpression"))
+ }
+ }
+ }
+
+ fn emit_new_expression(
+ &mut self,
+ callee: &Expression,
+ arguments: &Arguments,
+ ) -> Result<(), EmitError> {
+ for arg in &arguments.args {
+ if let Argument::SpreadElement(_) = arg {
+ return Err(EmitError::NotImplemented("TODO: SpreadNew"));
+ }
+ }
+
+ NewEmitter {
+ callee: |emitter| emitter.emit_expression(callee),
+ arguments: |emitter| {
+ emitter.emit_arguments(arguments)?;
+ Ok(arguments.args.len())
+ },
+ }
+ .emit(self)?;
+
+ Ok(())
+ }
+
+ fn emit_call_expression(
+ &mut self,
+ callee: &ExpressionOrSuper,
+ arguments: &Arguments,
+ ) -> Result<(), EmitError> {
+ // Don't do super handling in an emit_expresion_or_super because the bytecode heavily
+ // depends on how you're using the super
+
+ CallEmitter {
+ callee: |emitter| match callee {
+ ExpressionOrSuper::Expression(expr) => match &**expr {
+ Expression::IdentifierExpression(IdentifierExpression { name, .. }) => {
+ if name.value == CommonSourceAtomSetIndices::eval() {
+ return Err(EmitError::NotImplemented("TODO: direct eval"));
+ }
+ Ok(NameReferenceEmitter { name: name.value }.emit_for_call(emitter))
+ }
+
+ Expression::MemberExpression(MemberExpression::StaticMemberExpression(
+ StaticMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ property,
+ ..
+ },
+ )) => PropReferenceEmitter {
+ obj: |emitter| emitter.emit_expression(object),
+ key: property.value,
+ }
+ .emit_for_call(emitter),
+
+ Expression::MemberExpression(MemberExpression::ComputedMemberExpression(
+ ComputedMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ expression,
+ ..
+ },
+ )) => ElemReferenceEmitter {
+ obj: |emitter| emitter.emit_expression(object),
+ key: |emitter| emitter.emit_expression(expression),
+ }
+ .emit_for_call(emitter),
+
+ _ => {
+ return Err(EmitError::NotImplemented(
+ "TODO: Call (only global functions are supported)",
+ ));
+ }
+ },
+ _ => {
+ return Err(EmitError::NotImplemented("TODO: Super"));
+ }
+ },
+ arguments: |emitter| {
+ emitter.emit_arguments(arguments)?;
+ Ok(arguments.args.len())
+ },
+ }
+ .emit(self)?;
+
+ Ok(())
+ }
+
+ fn emit_arguments(&mut self, ast: &Arguments) -> Result<(), EmitError> {
+ for argument in &ast.args {
+ self.emit_argument(argument)?;
+ }
+
+ Ok(())
+ }
+
+ fn emit_argument(&mut self, ast: &Argument) -> Result<(), EmitError> {
+ match ast {
+ Argument::Expression(ast) => self.emit_expression(ast)?,
+ Argument::SpreadElement(_) => {
+ return Err(EmitError::NotImplemented("TODO: SpreadElement"));
+ }
+ }
+
+ Ok(())
+ }
+}