From dc7346f438990aa83ad90e9a99935a8c0f4c3c7b Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Sun, 5 Jul 2020 16:14:19 +0100 Subject: [PATCH] * 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 | 3 ++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index 8835207ec9f..fbbc0421aa7 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -36,8 +36,17 @@ impl Executable for ForLoop { let result = self.body().run(interpreter)?; match interpreter.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.set_current_state(InterpreterState::Executing); 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 bd1ed7c6a43..41e2472e359 100644 --- a/boa/src/syntax/parser/statement/iteration/for_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/for_statement.rs @@ -31,11 +31,12 @@ use crate::{ /// /// [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 { @@ -44,6 +45,7 @@ impl ForStatement { allow_yield: Y, allow_await: A, allow_return: R, + label: Option, ) -> Self where Y: Into, @@ -54,6 +56,7 @@ impl ForStatement { allow_yield: allow_yield.into(), allow_await: allow_await.into(), allow_return: allow_return.into(), + label, } } } @@ -104,6 +107,6 @@ impl TokenParser for ForStatement { 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 a5e89b8250f..3b88492ae93 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -99,6 +99,7 @@ impl TokenParser for Statement { // TODO: add BreakableStatement and divide Whiles, fors and so on to another place. let mut tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; + // Is this statement prefixed with a label? let label = Label::new(self.allow_yield, self.allow_await, self.allow_return).try_parse(cursor); @@ -128,7 +129,7 @@ impl TokenParser for Statement { .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) }