Numbers.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. * Copyright (c) 2023, Jonatan Klemets <jonatan.r.klemets@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/GenericLexer.h>
  7. #include <LibWeb/HTML/Numbers.h>
  8. #include <LibWeb/Infra/CharacterTypes.h>
  9. namespace Web::HTML {
  10. // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
  11. Optional<i32> parse_integer(StringView string)
  12. {
  13. // 1. Let input be the string being parsed.
  14. // 2. Let position be a pointer into input, initially pointing at the start of the string.
  15. GenericLexer lexer { string };
  16. // 3. Let sign have the value "positive".
  17. // NOTE: Skipped, see comment on step 6.
  18. // 4. Skip ASCII whitespace within input given position.
  19. lexer.ignore_while(Web::Infra::is_ascii_whitespace);
  20. // 5. If position is past the end of input, return an error.
  21. if (lexer.is_eof()) {
  22. return {};
  23. }
  24. // 6. If the character indicated by position (the first character) is a U+002D HYPHEN-MINUS character (-):
  25. //
  26. // If we parse a signed integer, then we include the sign character (if present) in the collect step
  27. // (step 8) and lean on `AK::StringUtils::convert_to_int` to handle it for us.
  28. size_t start_index = lexer.tell();
  29. if (lexer.peek() == '-' || lexer.peek() == '+') {
  30. lexer.consume();
  31. }
  32. // 7. If the character indicated by position is not an ASCII digit, then return an error.
  33. if (!lexer.next_is(is_ascii_digit)) {
  34. return {};
  35. }
  36. // 8. Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Let value be that integer.
  37. lexer.consume_while(is_ascii_digit);
  38. size_t end_index = lexer.tell();
  39. auto digits = lexer.input().substring_view(start_index, end_index - start_index);
  40. auto optional_value = AK::StringUtils::convert_to_int<i32>(digits);
  41. // 9. If sign is "positive", return value, otherwise return the result of subtracting value from zero.
  42. // NOTE: Skipped, see comment on step 6.
  43. return optional_value;
  44. }
  45. // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
  46. Optional<u32> parse_non_negative_integer(StringView string)
  47. {
  48. // 1. Let input be the string being parsed.
  49. // 2. Let value be the result of parsing input using the rules for parsing integers.
  50. //
  51. // NOTE: Because we call `parse_integer`, we parse all integers as signed. If we need the extra
  52. // size that an unsigned integer offers, then this would need to be improved. That said,
  53. // I don't think we need to support such large integers at the moment.
  54. auto optional_value = parse_integer(string);
  55. // 3. If value is an error, return an error.
  56. if (!optional_value.has_value()) {
  57. return {};
  58. }
  59. // 4. If value is less than zero, return an error.
  60. if (optional_value.value() < 0) {
  61. return {};
  62. }
  63. // 5. Return value.
  64. return static_cast<u32>(optional_value.value());
  65. }
  66. }