From c95dd77fae45d1e916ea2f0a6683d5cb3e0737ce Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Sun, 5 Jul 2020 13:50:58 +0100 Subject: [PATCH 01/13] start on label --- .../parser/statement/labelled_stm/mod.rs | 47 +++++++++++++++++++ boa/src/syntax/parser/statement/mod.rs | 6 ++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 boa/src/syntax/parser/statement/labelled_stm/mod.rs diff --git a/boa/src/syntax/parser/statement/labelled_stm/mod.rs b/boa/src/syntax/parser/statement/labelled_stm/mod.rs new file mode 100644 index 00000000000..bb7ae581f2a --- /dev/null +++ b/boa/src/syntax/parser/statement/labelled_stm/mod.rs @@ -0,0 +1,47 @@ +use super::LabelIdentifier; +use crate::{ + syntax::{ + ast::Punctuator, + parser::{ + cursor::Cursor, error::ParseError, AllowAwait, AllowReturn, AllowYield, TokenParser, + }, + }, + BoaProfiler, +}; +/// Labelled Statement Parsing +/// +/// More information +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label +/// [spec]: https://tc39.es/ecma262/#sec-labelled-statements +#[derive(Debug, Clone, Copy)] +pub(super) struct Label { + allow_yield: AllowYield, + allow_await: AllowAwait, + allow_return: AllowReturn, +} + +impl Label { + pub(super) fn new(allow_yield: Y, allow_await: A, allow_return: R) -> Self + where + Y: Into, + A: Into, + R: Into, + { + Self { + allow_yield: allow_yield.into(), + allow_await: allow_await.into(), + allow_return: allow_return.into(), + } + } +} + +impl TokenParser for Label { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { + let _timer = BoaProfiler::global().start_event("Label", "Parsing"); + let name = LabelIdentifier::new(false, false).try_parse(cursor); + cursor.expect(Punctuator::Colon, "Labelled Statement")?; + } +} diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 6b93bdc7e88..49b90910de0 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -14,6 +14,7 @@ mod declaration; mod expression; mod if_stm; mod iteration; +mod labelled_stm; mod return_stm; mod switch; mod throw; @@ -170,6 +171,9 @@ where .parse(cursor) .map(Node::from) } + // TokenKind::Identifier(name) => LabelIdentifier::new(self.allow_yield, self.allow_await) + // .parse(cursor) + // .map(Node::from), // TODO: https://tc39.es/ecma262/#prod-LabelledStatement _ => ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor), } @@ -367,7 +371,7 @@ where /// - [ECMAScript specification][spec] /// /// [spec]: https://tc39.es/ecma262/#prod-LabelIdentifier -type LabelIdentifier = BindingIdentifier; +pub(super) type LabelIdentifier = BindingIdentifier; /// Binding identifier parsing. /// From c483171f9dd555e251b365140a5fe4b837109402 Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Sun, 5 Jul 2020 14:46:19 +0100 Subject: [PATCH 02/13] Parse optional label at the beginning of statement --- boa/src/syntax/parser/statement/labelled_stm/mod.rs | 5 ++++- boa/src/syntax/parser/statement/mod.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/labelled_stm/mod.rs b/boa/src/syntax/parser/statement/labelled_stm/mod.rs index bb7ae581f2a..751173cd51f 100644 --- a/boa/src/syntax/parser/statement/labelled_stm/mod.rs +++ b/boa/src/syntax/parser/statement/labelled_stm/mod.rs @@ -39,9 +39,12 @@ impl Label { } impl TokenParser for Label { + type Output = Box; + fn parse(self, cursor: &mut Cursor<'_>) -> Result { let _timer = BoaProfiler::global().start_event("Label", "Parsing"); - let name = LabelIdentifier::new(false, false).try_parse(cursor); + let name = LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; cursor.expect(Punctuator::Colon, "Labelled Statement")?; + Ok(name) } } diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 49b90910de0..02b9b8646d3 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -43,6 +43,7 @@ use crate::{ syntax::ast::{node, Keyword, Node, Punctuator}, BoaProfiler, }; +use labelled_stm::Label; use std::io::Read; From 81e6b35068ef4e10ca71edb60f4a69dee17713c7 Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Sun, 5 Jul 2020 16:14:19 +0100 Subject: [PATCH 03/13] * Working proof of concept for breaking with labels --- boa/src/exec/iteration/mod.rs | 13 +++++++++++-- boa/src/syntax/ast/node/iteration.rs | 10 +++++++++- .../parser/statement/iteration/for_statement.rs | 7 +++++-- boa/src/syntax/parser/statement/labelled_stm/mod.rs | 4 ++-- boa/src/syntax/parser/statement/mod.rs | 2 +- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index 29d04b2c027..ace74e72e38 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -34,8 +34,17 @@ impl Executable for ForLoop { let result = self.body().run(interpreter)?; match interpreter.executor().get_current_state() { - InterpreterState::Break(_label) => { - // TODO break to label. + InterpreterState::Break(label) => { + // If a label is set we want to break the current block and still keep state as Break if the label is a block above + if let Some(stmt_label) = &self.label { + if let Some(brk_label) = label { + // We have a label, but not for the current statement + // break without resetting to executing + if stmt_label != brk_label { + break; + } + } + } // Loops 'consume' breaks. interpreter diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index d84a12499f3..8a5918dea7b 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -21,11 +21,18 @@ use serde::{Deserialize, Serialize}; pub struct ForLoop { #[cfg_attr(feature = "serde", serde(flatten))] inner: Box, + pub label: Option, } impl ForLoop { /// Creates a new for loop AST node. - pub(in crate::syntax) fn new(init: I, condition: C, final_expr: E, body: B) -> Self + pub(in crate::syntax) fn new( + init: I, + condition: C, + final_expr: E, + body: B, + label: Option, + ) -> Self where I: Into>, C: Into>, @@ -34,6 +41,7 @@ impl ForLoop { { Self { inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)), + label, } } diff --git a/boa/src/syntax/parser/statement/iteration/for_statement.rs b/boa/src/syntax/parser/statement/iteration/for_statement.rs index 8e53392fb73..d377d76bb04 100644 --- a/boa/src/syntax/parser/statement/iteration/for_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/for_statement.rs @@ -34,11 +34,12 @@ use std::io::Read; /// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for /// [spec]: https://tc39.es/ecma262/#sec-for-statement -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub(in crate::syntax::parser::statement) struct ForStatement { allow_yield: AllowYield, allow_await: AllowAwait, allow_return: AllowReturn, + label: Option, } impl ForStatement { @@ -47,6 +48,7 @@ impl ForStatement { allow_yield: Y, allow_await: A, allow_return: R, + label: Option, ) -> Self where Y: Into, @@ -57,6 +59,7 @@ impl ForStatement { allow_yield: allow_yield.into(), allow_await: allow_await.into(), allow_return: allow_return.into(), + label, } } } @@ -124,6 +127,6 @@ where Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; // TODO: do not encapsulate the `for` in a block just to have an inner scope. - Ok(ForLoop::new(init, cond, step, body)) + Ok(ForLoop::new(init, cond, step, body, self.label)) } } diff --git a/boa/src/syntax/parser/statement/labelled_stm/mod.rs b/boa/src/syntax/parser/statement/labelled_stm/mod.rs index 751173cd51f..95bc350f069 100644 --- a/boa/src/syntax/parser/statement/labelled_stm/mod.rs +++ b/boa/src/syntax/parser/statement/labelled_stm/mod.rs @@ -39,12 +39,12 @@ impl Label { } impl TokenParser for Label { - type Output = Box; + type Output = String; fn parse(self, cursor: &mut Cursor<'_>) -> Result { let _timer = BoaProfiler::global().start_event("Label", "Parsing"); let name = LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; cursor.expect(Punctuator::Colon, "Labelled Statement")?; - Ok(name) + Ok(name.to_string()) } } diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 02b9b8646d3..f1c0db1aa69 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -129,7 +129,7 @@ where .map(Node::from) } TokenKind::Keyword(Keyword::For) => { - ForStatement::new(self.allow_yield, self.allow_await, self.allow_return) + ForStatement::new(self.allow_yield, self.allow_await, self.allow_return, label) .parse(cursor) .map(Node::from) } From cee2e0f1d70732cd66a4e3893344b5c5024452e5 Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Thu, 16 Jul 2020 19:20:19 +0100 Subject: [PATCH 04/13] use labelled_stmt as a node --- boa/src/exec/iteration/mod.rs | 7 ++++ boa/src/syntax/ast/node/iteration.rs | 10 +---- boa/src/syntax/ast/node/labelled_smt.rs | 38 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 6 +++ .../statement/iteration/for_statement.rs | 5 +-- .../parser/statement/labelled_stm/mod.rs | 16 ++++---- boa/src/syntax/parser/statement/mod.rs | 23 ++++++++--- 7 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 boa/src/syntax/ast/node/labelled_smt.rs diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index ace74e72e38..55138ea5fce 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -51,6 +51,13 @@ impl Executable for ForLoop { .executor() .set_current_state(InterpreterState::Executing); break; + // } + // } + // } + + // // Loops 'consume' breaks. + // interpreter.set_current_state(InterpreterState::Executing); + // break; } InterpreterState::Continue(_label) => { // TODO continue to label. diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index 8a5918dea7b..d84a12499f3 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -21,18 +21,11 @@ use serde::{Deserialize, Serialize}; pub struct ForLoop { #[cfg_attr(feature = "serde", serde(flatten))] inner: Box, - pub label: Option, } impl ForLoop { /// Creates a new for loop AST node. - pub(in crate::syntax) fn new( - init: I, - condition: C, - final_expr: E, - body: B, - label: Option, - ) -> Self + pub(in crate::syntax) fn new(init: I, condition: C, final_expr: E, body: B) -> Self where I: Into>, C: Into>, @@ -41,7 +34,6 @@ impl ForLoop { { Self { inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)), - label, } } diff --git a/boa/src/syntax/ast/node/labelled_smt.rs b/boa/src/syntax/ast/node/labelled_smt.rs new file mode 100644 index 00000000000..f669f435e6b --- /dev/null +++ b/boa/src/syntax/ast/node/labelled_smt.rs @@ -0,0 +1,38 @@ +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Label { + stmt: Box, + label: Box, +} + +impl Label { + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", format!("{}: {}", self.label, self.stmt)) + } + + pub fn new(stmt: Node, label: Box) -> Self { + Self { + stmt: stmt.into(), + label, + } + } +} + +impl From