LibWeb: Update math function argument parsing to use TokenStream

This brings us in line with the rest of the parsing methods
This commit is contained in:
Callum Law 2025-11-03 13:18:28 +13:00 committed by Sam Atkins
parent 1f7fe97ac3
commit 76108b1979
Notes: github-actions[bot] 2025-12-01 11:02:20 +00:00
3 changed files with 19 additions and 11 deletions

View file

@ -538,7 +538,7 @@ private:
RefPtr<StyleValue const> parse_will_change_value(TokenStream<ComponentValue>&);
RefPtr<CalculationNode const> convert_to_calculation_node(CalcParsing::Node const&, CalculationContext const&);
RefPtr<CalculationNode const> parse_a_calculation(Vector<ComponentValue> const&, CalculationContext const&);
RefPtr<CalculationNode const> parse_a_calculation(TokenStream<ComponentValue>&, CalculationContext const&);
ParseErrorOr<NonnullRefPtr<Selector>> parse_complex_selector(TokenStream<ComponentValue>&, SelectorType);
ParseErrorOr<Optional<Selector::CompoundSelector>> parse_compound_selector(TokenStream<ComponentValue>&);

View file

@ -4420,8 +4420,10 @@ RefPtr<CalculationNode const> Parser::parse_a_calc_function_node(Function const&
{
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
if (function.name.equals_ignoring_ascii_case("calc"sv))
return parse_a_calculation(function.value, context);
if (function.name.equals_ignoring_ascii_case("calc"sv)) {
TokenStream tokens { function.value };
return parse_a_calculation(tokens, context);
}
if (auto maybe_function = parse_math_function(function, context)) {
// NOTE: We have to simplify manually here, since parse_math_function() is a helper for calc() parsing
@ -4480,7 +4482,8 @@ RefPtr<CalculationNode const> Parser::convert_to_calculation_node(CalcParsing::N
// 1. If leaf is a parenthesized simple block, replace leaf with the result of parsing a calculation from leafs contents.
if (component_value->is_block() && component_value->block().is_paren()) {
auto leaf_calculation = parse_a_calculation(component_value->block().value, context);
TokenStream tokens { component_value->block().value };
auto leaf_calculation = parse_a_calculation(tokens, context);
if (!leaf_calculation)
return nullptr;
@ -4576,13 +4579,16 @@ RefPtr<CalculationNode const> Parser::convert_to_calculation_node(CalcParsing::N
}
// https://drafts.csswg.org/css-values-4/#parse-a-calculation
RefPtr<CalculationNode const> Parser::parse_a_calculation(Vector<ComponentValue> const& original_values, CalculationContext const& context)
RefPtr<CalculationNode const> Parser::parse_a_calculation(TokenStream<ComponentValue>& tokens, CalculationContext const& context)
{
auto transaction = tokens.begin_transaction();
// 1. Discard any <whitespace-token>s from values.
// 2. An item in values is an “operator” if its a <delim-token> with the value "+", "-", "*", or "/". Otherwise, its a “value”.
Vector<CalcParsing::Node> values;
for (auto const& value : original_values) {
while (tokens.has_next_token()) {
auto const& value = tokens.consume_a_token();
if (value.is(Token::Type::Whitespace))
continue;
if (value.is(Token::Type::Delim)) {
@ -4706,6 +4712,7 @@ RefPtr<CalculationNode const> Parser::parse_a_calculation(Vector<ComponentValue>
return nullptr;
// 6. Return the result of simplifying a calculation tree from values.
transaction.commit();
return simplify_a_calculation_tree(*calculation_tree, context, CalculationResolutionContext {});
}

View file

@ -125,9 +125,8 @@ Optional<MathFunction> math_function_from_string(StringView name)
namespace Web::CSS::Parser {
static Optional<RoundingStrategy> parse_rounding_strategy(Vector<ComponentValue> const& tokens)
static Optional<RoundingStrategy> parse_rounding_strategy(TokenStream<ComponentValue>& stream)
{
auto stream = TokenStream { tokens };
stream.discard_whitespace();
if (!stream.has_next_token())
return {};
@ -172,7 +171,8 @@ RefPtr<CalculationNode const> Parser::parse_math_function(Function const& functi
parsed_arguments.ensure_capacity(arguments.size());
for (auto& argument : arguments) {
auto calculation_node = parse_a_calculation(argument, context);
TokenStream<ComponentValue> tokens { argument };
auto calculation_node = parse_a_calculation(tokens, context);
if (!calculation_node) {
ErrorReporter::the().report(InvalidValueError {
.value_type = "@name:lowercase@()"_fly_string,
@ -287,7 +287,7 @@ RefPtr<CalculationNode const> Parser::parse_math_function(Function const& functi
if (parameter_type_string == "<rounding-strategy>") {
parameter_is_calculation = false;
parameter_generator.set("parameter_type", "RoundingStrategy"_string);
parameter_generator.set("parse_function", "parse_rounding_strategy(arguments[argument_index])"_string);
parameter_generator.set("parse_function", MUST(String::formatted("parse_rounding_strategy(tokens_{})", parameter_index)));
parameter_generator.set("check_function", ".has_value()"_string);
parameter_generator.set("release_function", ".release_value()"_string);
if (auto default_value = parameter.get_string("default"sv); default_value.has_value()) {
@ -299,7 +299,7 @@ RefPtr<CalculationNode const> Parser::parse_math_function(Function const& functi
// NOTE: This assumes everything not handled above is a calculation node of some kind.
parameter_is_calculation = true;
parameter_generator.set("parameter_type", "RefPtr<CalculationNode const>"_string);
parameter_generator.set("parse_function", "parse_a_calculation(arguments[argument_index], context)"_string);
parameter_generator.set("parse_function", MUST(String::formatted("parse_a_calculation(tokens_{}, context)", parameter_index)));
parameter_generator.set("check_function", " != nullptr"_string);
parameter_generator.set("release_function", ".release_nonnull()"_string);
@ -334,6 +334,7 @@ RefPtr<CalculationNode const> Parser::parse_math_function(Function const& functi
}
parameter_generator.append(R"~~~(
TokenStream tokens_@parameter_index@ { arguments[argument_index] };
auto maybe_parsed_argument_@parameter_index@ = @parse_function@;
if (maybe_parsed_argument_@parameter_index@@check_function@) {
parameter_@parameter_index@ = maybe_parsed_argument_@parameter_index@@release_function@;