Skip to content

Commit

Permalink
Implement async arrow functions
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad committed Oct 30, 2022
1 parent bc2dd9c commit eafdd7e
Show file tree
Hide file tree
Showing 37 changed files with 950 additions and 222 deletions.
40 changes: 19 additions & 21 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,31 +822,29 @@ impl BuiltInFunctionObject {
}
};

match (function, name) {
(
Function::Native {
function: _,
constructor: _,
},
Some(name),
) => Ok(js_string!(
utf16!("function "),
&name,
utf16!("() {{\n [native Code]\n}}")
)
.into()),
(Function::Ordinary { .. }, Some(name)) if name.is_empty() => {
Ok(js_string!("[Function (anonymous)]").into())
let name = if let Some(name) = name {
if name.is_empty() {
"anonymous".into()
} else {
name
}
(Function::Ordinary { .. }, Some(name)) => {
} else {
"anonymous".into()
};

match function {
Function::Native { .. } | Function::Closure { .. } | Function::Ordinary { .. } => {
Ok(js_string!(utf16!("[Function: "), &name, utf16!("]")).into())
}
(Function::Ordinary { .. }, None) => Ok(js_string!("[Function (anonymous)]").into()),
(Function::Generator { .. }, Some(name)) => {
Ok(js_string!(utf16!("[Function*: "), &name, utf16!("]")).into())
Function::Async { .. } => {
Ok(js_string!(utf16!("[AsyncFunction: "), &name, utf16!("]")).into())
}
Function::Generator { .. } => {
Ok(js_string!(utf16!("[GeneratorFunction: "), &name, utf16!("]")).into())
}
Function::AsyncGenerator { .. } => {
Ok(js_string!(utf16!("[AsyncGeneratorFunction: "), &name, utf16!("]")).into())
}
(Function::Generator { .. }, None) => Ok(js_string!("[Function* (anonymous)]").into()),
_ => Ok("TODO".into()),
}
}

Expand Down
27 changes: 23 additions & 4 deletions boa_engine/src/bytecompiler/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub(crate) struct FunctionCompiler {
r#async: bool,
strict: bool,
arrow: bool,
has_binding_identifier: bool,
}

impl FunctionCompiler {
Expand All @@ -30,6 +31,7 @@ impl FunctionCompiler {
r#async: false,
strict: false,
arrow: false,
has_binding_identifier: false,
}
}

Expand Down Expand Up @@ -73,6 +75,13 @@ impl FunctionCompiler {
self
}

/// Indicate if the function has a binding identifier.
#[inline]
pub(crate) fn has_binding_identifier(mut self, has_binding_identifier: bool) -> Self {
self.has_binding_identifier = has_binding_identifier;
self
}

/// Compile a function statement list and it's parameters into bytecode.
pub(crate) fn compile(
mut self,
Expand All @@ -99,6 +108,14 @@ impl FunctionCompiler {
context,
};

if self.has_binding_identifier {
compiler.code_block.has_binding_identifier = true;
compiler.context.push_compile_time_environment(false);
compiler
.context
.create_immutable_binding(self.name.into(), self.strict);
}

compiler.context.push_compile_time_environment(true);

// An arguments object is added when all of the following conditions are met
Expand Down Expand Up @@ -183,13 +200,15 @@ impl FunctionCompiler {
} else {
let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment();
compiler
.code_block
.compile_environments
.push(compile_environment);
compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings;
}

if self.has_binding_identifier {
let (_, compile_environment) = compiler.context.pop_compile_time_environment();
compiler.push_compile_environment(compile_environment);
}

compiler.code_block.params = parameters.clone();

// TODO These are redundant if a function returns so may need to check if a function returns and adding these if it doesn't
Expand Down
79 changes: 48 additions & 31 deletions boa_engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{
Call, Identifier, New, Optional, OptionalOperationKind,
},
function::{
ArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement, FormalParameterList,
Function, Generator,
ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement,
FormalParameterList, Function, Generator,
},
pattern::{ArrayPatternElement, ObjectPatternElement, Pattern},
property::{MethodDefinition, PropertyDefinition, PropertyName},
Expand Down Expand Up @@ -48,6 +48,7 @@ enum NodeKind {
enum FunctionKind {
Ordinary,
Arrow,
AsyncArrow,
Async,
Generator,
AsyncGenerator,
Expand All @@ -60,20 +61,23 @@ struct FunctionSpec<'a> {
name: Option<Identifier>,
parameters: &'a FormalParameterList,
body: &'a StatementList,
has_binding_identifier: bool,
}

impl<'a> FunctionSpec<'a> {
#[inline]
fn is_arrow(&self) -> bool {
self.kind == FunctionKind::Arrow
matches!(self.kind, FunctionKind::Arrow | FunctionKind::AsyncArrow)
}

#[inline]
fn is_async(&self) -> bool {
matches!(
self.kind,
FunctionKind::Async | FunctionKind::AsyncGenerator
FunctionKind::Async | FunctionKind::AsyncGenerator | FunctionKind::AsyncArrow
)
}

#[inline]
fn is_generator(&self) -> bool {
matches!(
Expand All @@ -90,46 +94,67 @@ impl<'a> From<&'a Function> for FunctionSpec<'a> {
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: function.has_binding_identifier(),
}
}
}

impl<'a> From<&'a ArrowFunction> for FunctionSpec<'a> {
fn from(function: &'a ArrowFunction) -> Self {
FunctionSpec {
kind: FunctionKind::Arrow,
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: false,
}
}
}

impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> {
fn from(function: &'a AsyncArrowFunction) -> Self {
FunctionSpec {
kind: FunctionKind::AsyncArrow,
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: false,
}
}
}

impl<'a> From<&'a AsyncFunction> for FunctionSpec<'a> {
fn from(function: &'a AsyncFunction) -> Self {
FunctionSpec {
kind: FunctionKind::Async,
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: function.has_binding_identifier(),
}
}
}

impl<'a> From<&'a Generator> for FunctionSpec<'a> {
fn from(function: &'a Generator) -> Self {
FunctionSpec {
kind: FunctionKind::Generator,
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: function.has_binding_identifier(),
}
}
}

impl<'a> From<&'a AsyncGenerator> for FunctionSpec<'a> {
fn from(function: &'a AsyncGenerator) -> Self {
FunctionSpec {
kind: FunctionKind::AsyncGenerator,
name: function.name(),
parameters: function.parameters(),
body: function.body(),
has_binding_identifier: function.has_binding_identifier(),
}
}
}
Expand Down Expand Up @@ -1335,6 +1360,9 @@ impl<'b> ByteCompiler<'b> {
Expression::ArrowFunction(function) => {
self.function(function.into(), NodeKind::Expression, use_expr)?;
}
Expression::AsyncArrowFunction(function) => {
self.function(function.into(), NodeKind::Expression, use_expr)?;
}
Expression::Generator(function) => {
self.function(function.into(), NodeKind::Expression, use_expr)?;
}
Expand Down Expand Up @@ -1946,12 +1974,12 @@ impl<'b> ByteCompiler<'b> {
},
IterableLoopInitializer::Const(declaration) => match declaration {
Binding::Identifier(ident) => {
self.context.create_immutable_binding(*ident);
self.context.create_immutable_binding(*ident, true);
self.emit_binding(BindingOpcode::InitConst, *ident);
}
Binding::Pattern(pattern) => {
for ident in pattern.idents() {
self.context.create_immutable_binding(ident);
self.context.create_immutable_binding(ident, true);
}
self.compile_declaration_pattern(pattern, BindingOpcode::InitConst)?;
}
Expand Down Expand Up @@ -2071,12 +2099,12 @@ impl<'b> ByteCompiler<'b> {
},
IterableLoopInitializer::Const(declaration) => match declaration {
Binding::Identifier(ident) => {
self.context.create_immutable_binding(*ident);
self.context.create_immutable_binding(*ident, true);
self.emit_binding(BindingOpcode::InitConst, *ident);
}
Binding::Pattern(pattern) => {
for ident in pattern.idents() {
self.context.create_immutable_binding(ident);
self.context.create_immutable_binding(ident, true);
}
self.compile_declaration_pattern(pattern, BindingOpcode::InitConst)?;
}
Expand Down Expand Up @@ -2559,6 +2587,7 @@ impl<'b> ByteCompiler<'b> {
name,
parameters,
body,
has_binding_identifier,
..
} = function;

Expand All @@ -2568,15 +2597,18 @@ impl<'b> ByteCompiler<'b> {
.r#async(r#async)
.strict(self.code_block.strict)
.arrow(arrow)
.has_binding_identifier(has_binding_identifier)
.compile(parameters, body, self.context)?;

let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code);

if generator && r#async {
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[index]);
} else if generator {
self.emit(Opcode::GetGenerator, &[index]);
} else if r#async && arrow {
self.emit(Opcode::GetAsyncArrowFunction, &[index]);
} else if r#async {
self.emit(Opcode::GetFunctionAsync, &[index]);
} else if arrow {
Expand Down Expand Up @@ -2986,14 +3018,14 @@ impl<'b> ByteCompiler<'b> {
if *ident == Sym::ARGUMENTS {
has_identifier_argument = true;
}
self.context.create_immutable_binding(*ident);
self.context.create_immutable_binding(*ident, true);
}
Binding::Pattern(pattern) => {
for ident in pattern.idents() {
if ident == Sym::ARGUMENTS {
has_identifier_argument = true;
}
self.context.create_immutable_binding(ident);
self.context.create_immutable_binding(ident, true);
}
}
}
Expand Down Expand Up @@ -3157,10 +3189,7 @@ impl<'b> ByteCompiler<'b> {
} else {
let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment();
compiler
.code_block
.compile_environments
.push(compile_environment);
compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings;
compiler.code_block.is_class_constructor = true;
}
Expand All @@ -3170,10 +3199,7 @@ impl<'b> ByteCompiler<'b> {
}
let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment();
compiler
.code_block
.compile_environments
.push(compile_environment);
compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings;
compiler.code_block.is_class_constructor = true;
}
Expand Down Expand Up @@ -3348,10 +3374,7 @@ impl<'b> ByteCompiler<'b> {
}
let (num_bindings, compile_environment) =
field_compiler.context.pop_compile_time_environment();
field_compiler
.code_block
.compile_environments
.push(compile_environment);
field_compiler.push_compile_environment(compile_environment);
field_compiler.code_block.num_bindings = num_bindings;
field_compiler.emit_opcode(Opcode::Return);

Expand Down Expand Up @@ -3382,10 +3405,7 @@ impl<'b> ByteCompiler<'b> {
}
let (num_bindings, compile_environment) =
field_compiler.context.pop_compile_time_environment();
field_compiler
.code_block
.compile_environments
.push(compile_environment);
field_compiler.push_compile_environment(compile_environment);
field_compiler.code_block.num_bindings = num_bindings;
field_compiler.emit_opcode(Opcode::Return);

Expand Down Expand Up @@ -3437,10 +3457,7 @@ impl<'b> ByteCompiler<'b> {
compiler.compile_statement_list(statement_list, false)?;
let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment();
compiler
.code_block
.compile_environments
.push(compile_environment);
compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings;

let code = Gc::new(compiler.finish());
Expand Down
Loading

0 comments on commit eafdd7e

Please sign in to comment.