Commit e0bcd910 authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Fix operator precedence in SizesCalcParser

Pop all operators with greater/equal precedence rather than just the
top-most.

Bug: 803824
Change-Id: I5f106a0e82ed98ba2510c86ed157bf4b133cb5b8
Reviewed-on: https://chromium-review.googlesource.com/888919
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarYoav Weiss <yoav@yoav.ws>
Cr-Commit-Position: refs/heads/master@{#532100}
parent 5837fa97
...@@ -32,25 +32,31 @@ static bool OperatorPriority(UChar cc, bool& high_priority) { ...@@ -32,25 +32,31 @@ static bool OperatorPriority(UChar cc, bool& high_priority) {
bool SizesCalcParser::HandleOperator(Vector<CSSParserToken>& stack, bool SizesCalcParser::HandleOperator(Vector<CSSParserToken>& stack,
const CSSParserToken& token) { const CSSParserToken& token) {
// If the token is an operator, o1, then: // If the token is not an operator, then return. Else determine the
// while there is an operator token, o2, at the top of the stack, and // precedence of the new operator (op1).
// either o1 is left-associative and its precedence is equal to that of o2,
// or o1 has precedence less than that of o2,
// pop o2 off the stack, onto the output queue;
// push o1 onto the stack.
bool stack_operator_priority;
bool incoming_operator_priority; bool incoming_operator_priority;
if (!OperatorPriority(token.Delimiter(), incoming_operator_priority)) if (!OperatorPriority(token.Delimiter(), incoming_operator_priority))
return false; return false;
if (!stack.IsEmpty() && stack.back().GetType() == kDelimiterToken) {
if (!OperatorPriority(stack.back().Delimiter(), stack_operator_priority)) while (!stack.IsEmpty()) {
// While there is an operator (op2) at the top of the stack,
// determine its precedence, and...
const CSSParserToken& top_of_stack = stack.back();
if (top_of_stack.GetType() != kDelimiterToken)
break;
bool stack_operator_priority;
if (!OperatorPriority(top_of_stack.Delimiter(), stack_operator_priority))
return false; return false;
if (!incoming_operator_priority || stack_operator_priority) { // ...if op1 is left-associative (all currently supported
AppendOperator(stack.back()); // operators are) and its precedence is equal to that of op2, or
stack.pop_back(); // op1 has precedence less than that of op2, ...
} if (incoming_operator_priority && !stack_operator_priority)
break;
// ...pop op2 off the stack and add it to the output queue.
AppendOperator(top_of_stack);
stack.pop_back();
} }
// Push op1 onto the stack.
stack.push_back(token); stack.push_back(token);
return true; return true;
} }
......
...@@ -97,6 +97,14 @@ TEST(SizesCalcParserTest, Basic) { ...@@ -97,6 +97,14 @@ TEST(SizesCalcParserTest, Basic) {
{"calc(100px @ 2)", 0, false, false}, {"calc(100px @ 2)", 0, false, false},
{"calc(1 flim 2)", 0, false, false}, {"calc(1 flim 2)", 0, false, false},
{"calc(1 flim (2))", 0, false, false}, {"calc(1 flim (2))", 0, false, false},
{"calc((100vw - 2 * 40px - 2 * 30px) / 3)", 120, true, false},
{"calc((100vw - 40px - 60px - 40px) / 3)", 120, true, false},
{"calc((50vw + 40px + 30px + 40px) / 3)", 120, true, false},
{"calc((100vw - 2 / 2 * 40px - 2 * 30px) / 4)", 100, true, false},
{"calc((100vw - 2 * 2 / 2 * 40px - 2 * 30px) / 3)", 120, true, false},
{"calc((100vw - 2 * 2 / 2 * 40px - 2 * 30px) / 3)", 120, true, false},
{"calc((100vw - 2 * 2 * 20px - 2 * 30px) / 3)", 120, true, false},
{"calc((100vw - 320px / 2 / 2 - 2 * 30px) / 3)", 120, true, false},
{nullptr, 0, true, false} // Do not remove the terminator line. {nullptr, 0, true, false} // Do not remove the terminator line.
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment