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>
This commit is contained in:
parent
d1781fd0af
commit
dee7d36f8a
|
@ -2256,32 +2256,34 @@ Maybe<ast::Expression*> ParserImpl::unary_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::multiplicative_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::additive_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::shift_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::relational_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::equality_expression() {
|
|||
// :
|
||||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::and_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::exclusive_or_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::inclusive_or_expression() {
|
|||
// | 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 @@ Maybe<ast::Expression*> ParserImpl::logical_and_expression() {
|
|||
// | 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
|
||||
|
|
Loading…
Reference in New Issue