Revision control
Copy as Markdown
Other Tools
//! 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(())
}
}