reader/wgsl: Tail-call optimize expression methods
Fixes stack overflows in complex arithmetic expressions
Fixed: chromium:1182709
Change-Id: I5f5470cf59525725a437f26672904e9653b447a7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43940
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 07c22ec..80d4770 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -2256,32 +2256,34 @@
// | MODULO unary_expression multiplicative_expr
Expect<ast::Expression*> ParserImpl::expect_multiplicative_expr(
ast::Expression* lhs) {
- auto t = peek();
+ while (synchronized_) {
+ auto t = peek();
- ast::BinaryOp op = ast::BinaryOp::kNone;
- if (t.IsStar())
- op = ast::BinaryOp::kMultiply;
- else if (t.IsForwardSlash())
- op = ast::BinaryOp::kDivide;
- else if (t.IsMod())
- op = ast::BinaryOp::kModulo;
- else
- return lhs;
+ ast::BinaryOp op = ast::BinaryOp::kNone;
+ if (t.IsStar())
+ op = ast::BinaryOp::kMultiply;
+ else if (t.IsForwardSlash())
+ op = ast::BinaryOp::kDivide;
+ else if (t.IsMod())
+ op = ast::BinaryOp::kModulo;
+ else
+ return lhs;
- auto source = t.source();
- auto name = t.to_name();
- next(); // Consume the peek
+ auto source = t.source();
+ auto name = t.to_name();
+ next(); // Consume the peek
- auto rhs = unary_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + name + " expression");
+ auto rhs = unary_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched) {
+ return add_error(peek(),
+ "unable to parse right side of " + name + " expression");
+ }
+
+ lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
}
-
- return expect_multiplicative_expr(
- create<ast::BinaryExpression>(source, op, lhs, rhs.value));
+ return Failure::kErrored;
}
// multiplicative_expression
@@ -2302,27 +2304,29 @@
// | MINUS multiplicative_expression additive_expr
Expect<ast::Expression*> ParserImpl::expect_additive_expr(
ast::Expression* lhs) {
- auto t = peek();
+ while (synchronized_) {
+ auto t = peek();
- ast::BinaryOp op = ast::BinaryOp::kNone;
- if (t.IsPlus())
- op = ast::BinaryOp::kAdd;
- else if (t.IsMinus())
- op = ast::BinaryOp::kSubtract;
- else
- return lhs;
+ ast::BinaryOp op = ast::BinaryOp::kNone;
+ if (t.IsPlus())
+ op = ast::BinaryOp::kAdd;
+ else if (t.IsMinus())
+ op = ast::BinaryOp::kSubtract;
+ else
+ return lhs;
- auto source = t.source();
- next(); // Consume the peek
+ auto source = t.source();
+ next(); // Consume the peek
- auto rhs = multiplicative_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of + expression");
+ auto rhs = multiplicative_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of + expression");
- return expect_additive_expr(
- create<ast::BinaryExpression>(source, op, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+ }
+ return Failure::kErrored;
}
// additive_expression
@@ -2342,33 +2346,36 @@
// | SHIFT_LEFT additive_expression shift_expr
// | SHIFT_RIGHT additive_expression shift_expr
Expect<ast::Expression*> ParserImpl::expect_shift_expr(ast::Expression* lhs) {
- auto t = peek();
- auto source = t.source();
+ while (synchronized_) {
+ auto t = peek();
+ auto source = t.source();
- auto* name = "";
- ast::BinaryOp op = ast::BinaryOp::kNone;
- if (t.IsShiftLeft()) {
- next(); // Consume the peek
- op = ast::BinaryOp::kShiftLeft;
- name = "<<";
- } else if (t.IsShiftRight()) {
- next(); // Consume the peek
- op = ast::BinaryOp::kShiftRight;
- name = ">>";
- } else {
- return lhs;
- }
+ auto* name = "";
+ ast::BinaryOp op = ast::BinaryOp::kNone;
+ if (t.IsShiftLeft()) {
+ next(); // Consume the peek
+ op = ast::BinaryOp::kShiftLeft;
+ name = "<<";
+ } else if (t.IsShiftRight()) {
+ next(); // Consume the peek
+ op = ast::BinaryOp::kShiftRight;
+ name = ">>";
+ } else {
+ return lhs;
+ }
- auto rhs = additive_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched) {
- return add_error(peek(), std::string("unable to parse right side of ") +
- name + " expression");
+ auto rhs = additive_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched) {
+ return add_error(peek(), std::string("unable to parse right side of ") +
+ name + " expression");
+ }
+
+ return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
}
- return expect_shift_expr(
- create<ast::BinaryExpression>(source, op, lhs, rhs.value));
-} // namespace wgsl
+ return Failure::kErrored;
+}
// shift_expression
// : additive_expression shift_expr
@@ -2390,33 +2397,35 @@
// | GREATER_THAN_EQUAL shift_expression relational_expr
Expect<ast::Expression*> ParserImpl::expect_relational_expr(
ast::Expression* lhs) {
- auto t = peek();
- ast::BinaryOp op = ast::BinaryOp::kNone;
- if (t.IsLessThan())
- op = ast::BinaryOp::kLessThan;
- else if (t.IsGreaterThan())
- op = ast::BinaryOp::kGreaterThan;
- else if (t.IsLessThanEqual())
- op = ast::BinaryOp::kLessThanEqual;
- else if (t.IsGreaterThanEqual())
- op = ast::BinaryOp::kGreaterThanEqual;
- else
- return lhs;
+ while (synchronized_) {
+ auto t = peek();
+ ast::BinaryOp op = ast::BinaryOp::kNone;
+ if (t.IsLessThan())
+ op = ast::BinaryOp::kLessThan;
+ else if (t.IsGreaterThan())
+ op = ast::BinaryOp::kGreaterThan;
+ else if (t.IsLessThanEqual())
+ op = ast::BinaryOp::kLessThanEqual;
+ else if (t.IsGreaterThanEqual())
+ op = ast::BinaryOp::kGreaterThanEqual;
+ else
+ return lhs;
- auto source = t.source();
- auto name = t.to_name();
- next(); // Consume the peek
+ auto source = t.source();
+ auto name = t.to_name();
+ next(); // Consume the peek
- auto rhs = shift_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + name + " expression");
+ auto rhs = shift_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched) {
+ return add_error(peek(),
+ "unable to parse right side of " + name + " expression");
+ }
+
+ lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
}
-
- return expect_relational_expr(
- create<ast::BinaryExpression>(source, op, lhs, rhs.value));
+ return Failure::kErrored;
}
// relational_expression
@@ -2437,29 +2446,31 @@
// | NOT_EQUAL relational_expression equality_expr
Expect<ast::Expression*> ParserImpl::expect_equality_expr(
ast::Expression* lhs) {
- auto t = peek();
- ast::BinaryOp op = ast::BinaryOp::kNone;
- if (t.IsEqualEqual())
- op = ast::BinaryOp::kEqual;
- else if (t.IsNotEqual())
- op = ast::BinaryOp::kNotEqual;
- else
- return lhs;
+ while (synchronized_) {
+ auto t = peek();
+ ast::BinaryOp op = ast::BinaryOp::kNone;
+ if (t.IsEqualEqual())
+ op = ast::BinaryOp::kEqual;
+ else if (t.IsNotEqual())
+ op = ast::BinaryOp::kNotEqual;
+ else
+ return lhs;
- auto source = t.source();
- auto name = t.to_name();
- next(); // Consume the peek
+ auto source = t.source();
+ auto name = t.to_name();
+ next(); // Consume the peek
- auto rhs = relational_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched) {
- return add_error(peek(),
- "unable to parse right side of " + name + " expression");
+ auto rhs = relational_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched) {
+ return add_error(peek(),
+ "unable to parse right side of " + name + " expression");
+ }
+
+ lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
}
-
- return expect_equality_expr(
- create<ast::BinaryExpression>(source, op, lhs, rhs.value));
+ return Failure::kErrored;
}
// equality_expression
@@ -2478,21 +2489,24 @@
// :
// | AND equality_expression and_expr
Expect<ast::Expression*> ParserImpl::expect_and_expr(ast::Expression* lhs) {
- auto t = peek();
- if (!t.IsAnd())
- return lhs;
+ while (synchronized_) {
+ auto t = peek();
+ if (!t.IsAnd())
+ return lhs;
- auto source = t.source();
- next(); // Consume the peek
+ auto source = t.source();
+ next(); // Consume the peek
- auto rhs = equality_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of & expression");
+ auto rhs = equality_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of & expression");
- return expect_and_expr(create<ast::BinaryExpression>(
- source, ast::BinaryOp::kAnd, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs,
+ rhs.value);
+ }
+ return Failure::kErrored;
}
// and_expression
@@ -2512,18 +2526,21 @@
// | XOR and_expression exclusive_or_expr
Expect<ast::Expression*> ParserImpl::expect_exclusive_or_expr(
ast::Expression* lhs) {
- Source source;
- if (!match(Token::Type::kXor, &source))
- return lhs;
+ while (synchronized_) {
+ Source source;
+ if (!match(Token::Type::kXor, &source))
+ return lhs;
- auto rhs = and_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of ^ expression");
+ auto rhs = and_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of ^ expression");
- return expect_exclusive_or_expr(create<ast::BinaryExpression>(
- source, ast::BinaryOp::kXor, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kXor, lhs,
+ rhs.value);
+ }
+ return Failure::kErrored;
}
// exclusive_or_expression
@@ -2543,18 +2560,21 @@
// | OR exclusive_or_expression inclusive_or_expr
Expect<ast::Expression*> ParserImpl::expect_inclusive_or_expr(
ast::Expression* lhs) {
- Source source;
- if (!match(Token::Type::kOr))
- return lhs;
+ while (synchronized_) {
+ Source source;
+ if (!match(Token::Type::kOr))
+ return lhs;
- auto rhs = exclusive_or_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of | expression");
+ auto rhs = exclusive_or_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of | expression");
- return expect_inclusive_or_expr(create<ast::BinaryExpression>(
- source, ast::BinaryOp::kOr, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kOr, lhs,
+ rhs.value);
+ }
+ return Failure::kErrored;
}
// inclusive_or_expression
@@ -2574,21 +2594,24 @@
// | AND_AND inclusive_or_expression logical_and_expr
Expect<ast::Expression*> ParserImpl::expect_logical_and_expr(
ast::Expression* lhs) {
- auto t = peek();
- if (!t.IsAndAnd())
- return lhs;
+ while (synchronized_) {
+ auto t = peek();
+ if (!t.IsAndAnd())
+ return lhs;
- auto source = t.source();
- next(); // Consume the peek
+ auto source = t.source();
+ next(); // Consume the peek
- auto rhs = inclusive_or_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of && expression");
+ auto rhs = inclusive_or_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of && expression");
- return expect_logical_and_expr(create<ast::BinaryExpression>(
- source, ast::BinaryOp::kLogicalAnd, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs,
+ rhs.value);
+ }
+ return Failure::kErrored;
}
// logical_and_expression
@@ -2608,18 +2631,21 @@
// | OR_OR logical_and_expression logical_or_expr
Expect<ast::Expression*> ParserImpl::expect_logical_or_expr(
ast::Expression* lhs) {
- Source source;
- if (!match(Token::Type::kOrOr))
- return lhs;
+ while (synchronized_) {
+ Source source;
+ if (!match(Token::Type::kOrOr))
+ return lhs;
- auto rhs = logical_and_expression();
- if (rhs.errored)
- return Failure::kErrored;
- if (!rhs.matched)
- return add_error(peek(), "unable to parse right side of || expression");
+ auto rhs = logical_and_expression();
+ if (rhs.errored)
+ return Failure::kErrored;
+ if (!rhs.matched)
+ return add_error(peek(), "unable to parse right side of || expression");
- return expect_logical_or_expr(create<ast::BinaryExpression>(
- source, ast::BinaryOp::kLogicalOr, lhs, rhs.value));
+ lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalOr, lhs,
+ rhs.value);
+ }
+ return Failure::kErrored;
}
// logical_or_expression