AbstractOperations.cpp 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
  3. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  5. * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include <LibJS/Runtime/PropertyKey.h>
  10. #include <LibJS/Runtime/Temporal/AbstractOperations.h>
  11. namespace JS::Temporal {
  12. // 14.4.1.1 GetOptionsObject ( options ), https://tc39.es/proposal-temporal/#sec-getoptionsobject
  13. ThrowCompletionOr<Object*> get_options_object(VM& vm, Value options)
  14. {
  15. auto& realm = *vm.current_realm();
  16. // 1. If options is undefined, then
  17. if (options.is_undefined()) {
  18. // a. Return OrdinaryObjectCreate(null).
  19. return Object::create(realm, nullptr).ptr();
  20. }
  21. // 2. If options is an Object, then
  22. if (options.is_object()) {
  23. // a. Return options.
  24. return &options.as_object();
  25. }
  26. // 3. Throw a TypeError exception.
  27. return vm.throw_completion<TypeError>(ErrorType::NotAnObject, "Options");
  28. }
  29. // 14.4.1.2 GetOption ( options, property, type, values, default ), https://tc39.es/proposal-temporal/#sec-getoption
  30. ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan<StringView> values, OptionDefault const& default_)
  31. {
  32. VERIFY(property.is_string());
  33. // 1. Let value be ? Get(options, property).
  34. auto value = TRY(options.get(property));
  35. // 2. If value is undefined, then
  36. if (value.is_undefined()) {
  37. // a. If default is REQUIRED, throw a RangeError exception.
  38. if (default_.has<DefaultRequired>())
  39. return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, "undefined"sv, property.as_string());
  40. // b. Return default.
  41. return default_.visit(
  42. [](DefaultRequired) -> Value { VERIFY_NOT_REACHED(); },
  43. [](Empty) -> Value { return js_undefined(); },
  44. [](bool default_) -> Value { return Value { default_ }; },
  45. [](double default_) -> Value { return Value { default_ }; },
  46. [&](StringView default_) -> Value { return PrimitiveString::create(vm, default_); });
  47. }
  48. // 3. If type is BOOLEAN, then
  49. if (type == OptionType::Boolean) {
  50. // a. Set value to ToBoolean(value).
  51. value = Value { value.to_boolean() };
  52. }
  53. // 4. Else,
  54. else {
  55. // a. Assert: type is STRING.
  56. VERIFY(type == OptionType::String);
  57. // b. Set value to ? ToString(value).
  58. value = TRY(value.to_primitive_string(vm));
  59. }
  60. // 5. If values is not EMPTY and values does not contain value, throw a RangeError exception.
  61. if (!values.is_empty()) {
  62. // NOTE: Every location in the spec that invokes GetOption with type=boolean also has values=undefined.
  63. VERIFY(value.is_string());
  64. if (auto value_string = value.as_string().utf8_string(); !values.contains_slow(value_string))
  65. return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, value_string, property.as_string());
  66. }
  67. // 6. Return value.
  68. return value;
  69. }
  70. }