Skip to content

Commit

Permalink
* Working proof of concept for breaking with labels
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonwilliams committed Jul 5, 2020
1 parent 343a743 commit dc7346f
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 8 deletions.
13 changes: 11 additions & 2 deletions boa/src/exec/iteration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 9 additions & 1 deletion boa/src/syntax/ast/node/iteration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ use serde::{Deserialize, Serialize};
pub struct ForLoop {
#[cfg_attr(feature = "serde", serde(flatten))]
inner: Box<InnerForLoop>,
pub label: Option<String>,
}

impl ForLoop {
/// Creates a new for loop AST node.
pub(in crate::syntax) fn new<I, C, E, B>(init: I, condition: C, final_expr: E, body: B) -> Self
pub(in crate::syntax) fn new<I, C, E, B>(
init: I,
condition: C,
final_expr: E,
body: B,
label: Option<String>,
) -> Self
where
I: Into<Option<Node>>,
C: Into<Option<Node>>,
Expand All @@ -34,6 +41,7 @@ impl ForLoop {
{
Self {
inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)),
label,
}
}

Expand Down
7 changes: 5 additions & 2 deletions boa/src/syntax/parser/statement/iteration/for_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
}

impl ForStatement {
Expand All @@ -44,6 +45,7 @@ impl ForStatement {
allow_yield: Y,
allow_await: A,
allow_return: R,
label: Option<String>,
) -> Self
where
Y: Into<AllowYield>,
Expand All @@ -54,6 +56,7 @@ impl ForStatement {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
allow_return: allow_return.into(),
label,
}
}
}
Expand Down Expand Up @@ -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))
}
}
4 changes: 2 additions & 2 deletions boa/src/syntax/parser/statement/labelled_stm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ impl Label {
}

impl TokenParser for Label {
type Output = Box<str>;
type Output = String;

fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
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())
}
}
3 changes: 2 additions & 1 deletion boa/src/syntax/parser/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit dc7346f

Please sign in to comment.