Skip to content

Commit

Permalink
WIP: Remove UnparsedCalculationNode
Browse files Browse the repository at this point in the history
The tricky bit remaining is figuring out how to convert the temporary
types into actual CalculationNodes. I think I'm going to need a
recursive free function that takes a Node and produces a
CalculationNode. That means moving a few types to top level. Maybe I
should move calc parsing into its own cpp file? IDK.
  • Loading branch information
AtkinsSJ committed Dec 13, 2024
1 parent e318316 commit 3fdec55
Showing 1 changed file with 36 additions and 43 deletions.
79 changes: 36 additions & 43 deletions Libraries/LibWeb/CSS/Parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8679,8 +8679,24 @@ OwnPtr<CalculationNode> Parser::parse_a_calculation(Vector<ComponentValue> const
struct Operator {
char delim;
};
using Value = Variant<NonnullOwnPtr<CalculationNode>, Operator>;
Vector<Value> values;
struct ProductNode;
struct SumNode;
struct InvertNode;
struct NegateNode;
using Node = Variant<Operator, Number, Dimension, CalculationNode::ConstantType, NonnullOwnPtr<ProductNode>, NonnullOwnPtr<SumNode>, NonnullOwnPtr<InvertNode>, NonnullOwnPtr<NegateNode>, NonnullRawPtr<ComponentValue const>>;
struct ProductNode {
Vector<Node> children;
};
struct SumNode {
Vector<Node> children;
};
struct InvertNode {
Node child;
};
struct NegateNode {
Node child;
};
Vector<Node> values;
for (auto const& value : original_values) {
if (value.is(Token::Type::Whitespace))
continue;
Expand All @@ -8698,41 +8714,28 @@ OwnPtr<CalculationNode> Parser::parse_a_calculation(Vector<ComponentValue> const
if (value.is(Token::Type::Ident)) {
auto maybe_constant = CalculationNode::constant_type_from_string(value.token().ident());
if (maybe_constant.has_value()) {
values.append({ ConstantCalculationNode::create(maybe_constant.value()) });
values.append(maybe_constant.value());
continue;
}
}

if (value.is(Token::Type::Number)) {
values.append({ NumericCalculationNode::create(value.token().number()) });
values.append(value.token().number());
continue;
}

if (auto dimension = parse_dimension(value); dimension.has_value()) {
if (dimension->is_angle())
values.append({ NumericCalculationNode::create(dimension->angle()) });
else if (dimension->is_frequency())
values.append({ NumericCalculationNode::create(dimension->frequency()) });
else if (dimension->is_length())
values.append({ NumericCalculationNode::create(dimension->length()) });
else if (dimension->is_percentage())
values.append({ NumericCalculationNode::create(dimension->percentage()) });
else if (dimension->is_resolution())
values.append({ NumericCalculationNode::create(dimension->resolution()) });
else if (dimension->is_time())
values.append({ NumericCalculationNode::create(dimension->time()) });
else if (dimension->is_flex()) {
if (dimension->is_flex()) {
// https://www.w3.org/TR/css3-grid-layout/#fr-unit
// NOTE: <flex> values are not <length>s (nor are they compatible with <length>s, like some <percentage> values),
// so they cannot be represented in or combined with other unit types in calc() expressions.
return nullptr;
} else {
VERIFY_NOT_REACHED();
}
values.append(dimension.release_value());
continue;
}

values.append({ UnparsedCalculationNode::create(value) });
values.append(NonnullRawPtr { value });
}

// If we have no values, the syntax is invalid.
Expand Down Expand Up @@ -8771,26 +8774,25 @@ OwnPtr<CalculationNode> Parser::parse_a_calculation(Vector<ComponentValue> const
}

// 1. For each "/" operator in the run, replace its right-hand value item rhs with an Invert node containing rhs as its child.
Vector<NonnullOwnPtr<CalculationNode>> run_values;
run_values.append(move(values[start_of_run].get<NonnullOwnPtr<CalculationNode>>()));
Vector<Node> run_values;
run_values.append(move(values[start_of_run]));
for (auto i = start_of_run + 1; i <= end_of_run; i += 2) {
auto& operator_ = values[i].get<Operator>().delim;
auto& rhs = values[i + 1];
if (operator_ == '/') {
run_values.append(InvertCalculationNode::create(move(rhs.get<NonnullOwnPtr<CalculationNode>>())));
run_values.append(make<InvertNode>(move(rhs)));
continue;
}
VERIFY(operator_ == '*');
run_values.append(move(rhs.get<NonnullOwnPtr<CalculationNode>>()));
run_values.append(move(rhs));
}
// 2. Replace the entire run with a Product node containing the value items of the run as its children.
auto product_node = ProductCalculationNode::create(move(run_values));
values.remove(start_of_run, end_of_run - start_of_run + 1);
values.insert(start_of_run, { move(product_node) });
values.insert(start_of_run, make<ProductNode>(move(run_values)));
}

// 4. Collect children into Sum and Negate nodes.
Optional<NonnullOwnPtr<CalculationNode>> single_value;
Optional<Node> single_value;
{
// 1. For each "-" operator item in values, replace its right-hand value item rhs with a Negate node containing rhs as its child.
for (auto i = 0u; i < values.size(); ++i) {
Expand All @@ -8801,35 +8803,26 @@ OwnPtr<CalculationNode> Parser::parse_a_calculation(Vector<ComponentValue> const
auto rhs_index = ++i;
auto& rhs = values[rhs_index];

NonnullOwnPtr<CalculationNode> negate_node = NegateCalculationNode::create(move(rhs.get<NonnullOwnPtr<CalculationNode>>()));
values.remove(rhs_index);
values.insert(rhs_index, move(negate_node));
values.insert(rhs_index, make<NegateNode>(move(rhs)));
}

// 2. If values has only one item, and it is a Product node or a parenthesized simple block, replace values with that item.
if (values.size() == 1) {
values.first().visit(
[&](ComponentValue& component_value) {
[&](ComponentValue const& component_value) {
if (component_value.is_block() && component_value.block().is_paren())
single_value = UnparsedCalculationNode::create(move(component_value));
single_value = NonnullRawPtr { component_value };
},
[&](NonnullOwnPtr<CalculationNode>& node) {
if (node->type() == CalculationNode::Type::Product)
single_value = move(node);
[&](NonnullOwnPtr<ProductNode>& node) {
single_value = move(node);
},
[](auto&) {});
}
// Otherwise, replace values with a Sum node containing the value items of values as its children.
if (!single_value.has_value()) {
values.remove_all_matching([](Value& value) { return value.has<Operator>(); });
Vector<NonnullOwnPtr<CalculationNode>> value_items;
value_items.ensure_capacity(values.size());
for (auto& value : values) {
if (value.has<Operator>())
continue;
value_items.unchecked_append(move(value.get<NonnullOwnPtr<CalculationNode>>()));
}
single_value = SumCalculationNode::create(move(value_items));
values.remove_all_matching([](Node& value) { return value.has<Operator>(); });
single_value = make<SumNode>(move(values));
}
}

Expand Down

0 comments on commit 3fdec55

Please sign in to comment.