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
|
// | MODULO unary_expression multiplicative_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_multiplicative_expr(
|
Expect<ast::Expression*> ParserImpl::expect_multiplicative_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
|
auto t = peek();
|
||||||
|
|
||||||
ast::BinaryOp op = ast::BinaryOp::kNone;
|
ast::BinaryOp op = ast::BinaryOp::kNone;
|
||||||
if (t.IsStar())
|
if (t.IsStar())
|
||||||
op = ast::BinaryOp::kMultiply;
|
op = ast::BinaryOp::kMultiply;
|
||||||
else if (t.IsForwardSlash())
|
else if (t.IsForwardSlash())
|
||||||
op = ast::BinaryOp::kDivide;
|
op = ast::BinaryOp::kDivide;
|
||||||
else if (t.IsMod())
|
else if (t.IsMod())
|
||||||
op = ast::BinaryOp::kModulo;
|
op = ast::BinaryOp::kModulo;
|
||||||
else
|
else
|
||||||
return lhs;
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
auto name = t.to_name();
|
auto name = t.to_name();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = unary_expression();
|
auto rhs = unary_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched) {
|
if (!rhs.matched) {
|
||||||
return add_error(peek(),
|
return add_error(peek(),
|
||||||
"unable to parse right side of " + name + " expression");
|
"unable to parse right side of " + name + " expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
|
||||||
}
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
return expect_multiplicative_expr(
|
|
||||||
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiplicative_expression
|
// multiplicative_expression
|
||||||
|
@ -2302,27 +2304,29 @@ Maybe<ast::Expression*> ParserImpl::multiplicative_expression() {
|
||||||
// | MINUS multiplicative_expression additive_expr
|
// | MINUS multiplicative_expression additive_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_additive_expr(
|
Expect<ast::Expression*> ParserImpl::expect_additive_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
|
auto t = peek();
|
||||||
|
|
||||||
ast::BinaryOp op = ast::BinaryOp::kNone;
|
ast::BinaryOp op = ast::BinaryOp::kNone;
|
||||||
if (t.IsPlus())
|
if (t.IsPlus())
|
||||||
op = ast::BinaryOp::kAdd;
|
op = ast::BinaryOp::kAdd;
|
||||||
else if (t.IsMinus())
|
else if (t.IsMinus())
|
||||||
op = ast::BinaryOp::kSubtract;
|
op = ast::BinaryOp::kSubtract;
|
||||||
else
|
else
|
||||||
return lhs;
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = multiplicative_expression();
|
auto rhs = multiplicative_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of + expression");
|
return add_error(peek(), "unable to parse right side of + expression");
|
||||||
|
|
||||||
return expect_additive_expr(
|
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
|
||||||
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// additive_expression
|
// additive_expression
|
||||||
|
@ -2342,33 +2346,36 @@ Maybe<ast::Expression*> ParserImpl::additive_expression() {
|
||||||
// | SHIFT_LEFT additive_expression shift_expr
|
// | SHIFT_LEFT additive_expression shift_expr
|
||||||
// | SHIFT_RIGHT additive_expression shift_expr
|
// | SHIFT_RIGHT additive_expression shift_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_shift_expr(ast::Expression* lhs) {
|
Expect<ast::Expression*> ParserImpl::expect_shift_expr(ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
auto source = t.source();
|
auto t = peek();
|
||||||
|
auto source = t.source();
|
||||||
|
|
||||||
auto* name = "";
|
auto* name = "";
|
||||||
ast::BinaryOp op = ast::BinaryOp::kNone;
|
ast::BinaryOp op = ast::BinaryOp::kNone;
|
||||||
if (t.IsShiftLeft()) {
|
if (t.IsShiftLeft()) {
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
op = ast::BinaryOp::kShiftLeft;
|
op = ast::BinaryOp::kShiftLeft;
|
||||||
name = "<<";
|
name = "<<";
|
||||||
} else if (t.IsShiftRight()) {
|
} else if (t.IsShiftRight()) {
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
op = ast::BinaryOp::kShiftRight;
|
op = ast::BinaryOp::kShiftRight;
|
||||||
name = ">>";
|
name = ">>";
|
||||||
} else {
|
} else {
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rhs = additive_expression();
|
auto rhs = additive_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched) {
|
if (!rhs.matched) {
|
||||||
return add_error(peek(), std::string("unable to parse right side of ") +
|
return add_error(peek(), std::string("unable to parse right side of ") +
|
||||||
name + " expression");
|
name + " expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
|
||||||
}
|
}
|
||||||
return expect_shift_expr(
|
return Failure::kErrored;
|
||||||
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
|
}
|
||||||
} // namespace wgsl
|
|
||||||
|
|
||||||
// shift_expression
|
// shift_expression
|
||||||
// : additive_expression shift_expr
|
// : additive_expression shift_expr
|
||||||
|
@ -2390,33 +2397,35 @@ Maybe<ast::Expression*> ParserImpl::shift_expression() {
|
||||||
// | GREATER_THAN_EQUAL shift_expression relational_expr
|
// | GREATER_THAN_EQUAL shift_expression relational_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_relational_expr(
|
Expect<ast::Expression*> ParserImpl::expect_relational_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
ast::BinaryOp op = ast::BinaryOp::kNone;
|
auto t = peek();
|
||||||
if (t.IsLessThan())
|
ast::BinaryOp op = ast::BinaryOp::kNone;
|
||||||
op = ast::BinaryOp::kLessThan;
|
if (t.IsLessThan())
|
||||||
else if (t.IsGreaterThan())
|
op = ast::BinaryOp::kLessThan;
|
||||||
op = ast::BinaryOp::kGreaterThan;
|
else if (t.IsGreaterThan())
|
||||||
else if (t.IsLessThanEqual())
|
op = ast::BinaryOp::kGreaterThan;
|
||||||
op = ast::BinaryOp::kLessThanEqual;
|
else if (t.IsLessThanEqual())
|
||||||
else if (t.IsGreaterThanEqual())
|
op = ast::BinaryOp::kLessThanEqual;
|
||||||
op = ast::BinaryOp::kGreaterThanEqual;
|
else if (t.IsGreaterThanEqual())
|
||||||
else
|
op = ast::BinaryOp::kGreaterThanEqual;
|
||||||
return lhs;
|
else
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
auto name = t.to_name();
|
auto name = t.to_name();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = shift_expression();
|
auto rhs = shift_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched) {
|
if (!rhs.matched) {
|
||||||
return add_error(peek(),
|
return add_error(peek(),
|
||||||
"unable to parse right side of " + name + " expression");
|
"unable to parse right side of " + name + " expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
|
||||||
}
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
return expect_relational_expr(
|
|
||||||
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// relational_expression
|
// relational_expression
|
||||||
|
@ -2437,29 +2446,31 @@ Maybe<ast::Expression*> ParserImpl::relational_expression() {
|
||||||
// | NOT_EQUAL relational_expression equality_expr
|
// | NOT_EQUAL relational_expression equality_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_equality_expr(
|
Expect<ast::Expression*> ParserImpl::expect_equality_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
ast::BinaryOp op = ast::BinaryOp::kNone;
|
auto t = peek();
|
||||||
if (t.IsEqualEqual())
|
ast::BinaryOp op = ast::BinaryOp::kNone;
|
||||||
op = ast::BinaryOp::kEqual;
|
if (t.IsEqualEqual())
|
||||||
else if (t.IsNotEqual())
|
op = ast::BinaryOp::kEqual;
|
||||||
op = ast::BinaryOp::kNotEqual;
|
else if (t.IsNotEqual())
|
||||||
else
|
op = ast::BinaryOp::kNotEqual;
|
||||||
return lhs;
|
else
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
auto name = t.to_name();
|
auto name = t.to_name();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = relational_expression();
|
auto rhs = relational_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched) {
|
if (!rhs.matched) {
|
||||||
return add_error(peek(),
|
return add_error(peek(),
|
||||||
"unable to parse right side of " + name + " expression");
|
"unable to parse right side of " + name + " expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
|
||||||
}
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
return expect_equality_expr(
|
|
||||||
create<ast::BinaryExpression>(source, op, lhs, rhs.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// equality_expression
|
// equality_expression
|
||||||
|
@ -2478,21 +2489,24 @@ Maybe<ast::Expression*> ParserImpl::equality_expression() {
|
||||||
// :
|
// :
|
||||||
// | AND equality_expression and_expr
|
// | AND equality_expression and_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_and_expr(ast::Expression* lhs) {
|
Expect<ast::Expression*> ParserImpl::expect_and_expr(ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
if (!t.IsAnd())
|
auto t = peek();
|
||||||
return lhs;
|
if (!t.IsAnd())
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = equality_expression();
|
auto rhs = equality_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of & expression");
|
return add_error(peek(), "unable to parse right side of & expression");
|
||||||
|
|
||||||
return expect_and_expr(create<ast::BinaryExpression>(
|
lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs,
|
||||||
source, ast::BinaryOp::kAnd, lhs, rhs.value));
|
rhs.value);
|
||||||
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and_expression
|
// and_expression
|
||||||
|
@ -2512,18 +2526,21 @@ Maybe<ast::Expression*> ParserImpl::and_expression() {
|
||||||
// | XOR and_expression exclusive_or_expr
|
// | XOR and_expression exclusive_or_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_exclusive_or_expr(
|
Expect<ast::Expression*> ParserImpl::expect_exclusive_or_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
Source source;
|
while (synchronized_) {
|
||||||
if (!match(Token::Type::kXor, &source))
|
Source source;
|
||||||
return lhs;
|
if (!match(Token::Type::kXor, &source))
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto rhs = and_expression();
|
auto rhs = and_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of ^ expression");
|
return add_error(peek(), "unable to parse right side of ^ expression");
|
||||||
|
|
||||||
return expect_exclusive_or_expr(create<ast::BinaryExpression>(
|
lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kXor, lhs,
|
||||||
source, ast::BinaryOp::kXor, lhs, rhs.value));
|
rhs.value);
|
||||||
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclusive_or_expression
|
// exclusive_or_expression
|
||||||
|
@ -2543,18 +2560,21 @@ Maybe<ast::Expression*> ParserImpl::exclusive_or_expression() {
|
||||||
// | OR exclusive_or_expression inclusive_or_expr
|
// | OR exclusive_or_expression inclusive_or_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_inclusive_or_expr(
|
Expect<ast::Expression*> ParserImpl::expect_inclusive_or_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
Source source;
|
while (synchronized_) {
|
||||||
if (!match(Token::Type::kOr))
|
Source source;
|
||||||
return lhs;
|
if (!match(Token::Type::kOr))
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto rhs = exclusive_or_expression();
|
auto rhs = exclusive_or_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of | expression");
|
return add_error(peek(), "unable to parse right side of | expression");
|
||||||
|
|
||||||
return expect_inclusive_or_expr(create<ast::BinaryExpression>(
|
lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kOr, lhs,
|
||||||
source, ast::BinaryOp::kOr, lhs, rhs.value));
|
rhs.value);
|
||||||
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inclusive_or_expression
|
// inclusive_or_expression
|
||||||
|
@ -2574,21 +2594,24 @@ Maybe<ast::Expression*> ParserImpl::inclusive_or_expression() {
|
||||||
// | AND_AND inclusive_or_expression logical_and_expr
|
// | AND_AND inclusive_or_expression logical_and_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_logical_and_expr(
|
Expect<ast::Expression*> ParserImpl::expect_logical_and_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
auto t = peek();
|
while (synchronized_) {
|
||||||
if (!t.IsAndAnd())
|
auto t = peek();
|
||||||
return lhs;
|
if (!t.IsAndAnd())
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
auto rhs = inclusive_or_expression();
|
auto rhs = inclusive_or_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of && expression");
|
return add_error(peek(), "unable to parse right side of && expression");
|
||||||
|
|
||||||
return expect_logical_and_expr(create<ast::BinaryExpression>(
|
lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs,
|
||||||
source, ast::BinaryOp::kLogicalAnd, lhs, rhs.value));
|
rhs.value);
|
||||||
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// logical_and_expression
|
// logical_and_expression
|
||||||
|
@ -2608,18 +2631,21 @@ Maybe<ast::Expression*> ParserImpl::logical_and_expression() {
|
||||||
// | OR_OR logical_and_expression logical_or_expr
|
// | OR_OR logical_and_expression logical_or_expr
|
||||||
Expect<ast::Expression*> ParserImpl::expect_logical_or_expr(
|
Expect<ast::Expression*> ParserImpl::expect_logical_or_expr(
|
||||||
ast::Expression* lhs) {
|
ast::Expression* lhs) {
|
||||||
Source source;
|
while (synchronized_) {
|
||||||
if (!match(Token::Type::kOrOr))
|
Source source;
|
||||||
return lhs;
|
if (!match(Token::Type::kOrOr))
|
||||||
|
return lhs;
|
||||||
|
|
||||||
auto rhs = logical_and_expression();
|
auto rhs = logical_and_expression();
|
||||||
if (rhs.errored)
|
if (rhs.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
if (!rhs.matched)
|
if (!rhs.matched)
|
||||||
return add_error(peek(), "unable to parse right side of || expression");
|
return add_error(peek(), "unable to parse right side of || expression");
|
||||||
|
|
||||||
return expect_logical_or_expr(create<ast::BinaryExpression>(
|
lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalOr, lhs,
|
||||||
source, ast::BinaryOp::kLogicalOr, lhs, rhs.value));
|
rhs.value);
|
||||||
|
}
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// logical_or_expression
|
// logical_or_expression
|
||||||
|
|
Loading…
Reference in New Issue