mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 20:45:14 +00:00
IDLGenerators: Handle restricted/unrestricted floating point types
This commit is contained in:
parent
2bd8093449
commit
3e221fbb2d
Notes:
sideshowbarker
2024-07-17 07:09:53 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/3e221fbb2d Pull-request: https://github.com/SerenityOS/serenity/pull/24474
8 changed files with 108 additions and 15 deletions
|
@ -165,10 +165,10 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
|
|||
if (type.is_string())
|
||||
return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector };
|
||||
|
||||
if (type.name() == "double" && !type.is_nullable())
|
||||
if ((type.name() == "double" || type.name() == "unrestricted double") && !type.is_nullable())
|
||||
return { .name = "double", .sequence_storage_type = SequenceStorageType::Vector };
|
||||
|
||||
if (type.name() == "float" && !type.is_nullable())
|
||||
if ((type.name() == "float" || type.name() == "unrestricted float") && !type.is_nullable())
|
||||
return { .name = "float", .sequence_storage_type = SequenceStorageType::Vector };
|
||||
|
||||
if (type.name() == "boolean" && !type.is_nullable())
|
||||
|
@ -462,6 +462,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
|
||||
scoped_generator.set("string_type", string_to_fly_string ? "FlyString" : "String");
|
||||
scoped_generator.set("parameter.type.name", parameter.type->name());
|
||||
scoped_generator.set("parameter.name", parameter.name);
|
||||
|
||||
if (explicit_null) {
|
||||
if (!IDL::is_platform_object(*parameter.type)) {
|
||||
|
@ -559,7 +560,14 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
)~~~");
|
||||
}
|
||||
}
|
||||
} else if (parameter.type->name() == "double" || parameter.type->name() == "float") {
|
||||
} else if (parameter.type->is_floating_point()) {
|
||||
if (parameter.type->name() == "unrestricted float") {
|
||||
scoped_generator.set("parameter.type.name", "float");
|
||||
} else if (parameter.type->name() == "unrestricted double") {
|
||||
scoped_generator.set("parameter.type.name", "double");
|
||||
}
|
||||
|
||||
bool is_wrapped_in_optional_type = false;
|
||||
if (!optional) {
|
||||
scoped_generator.append(R"~~~(
|
||||
@parameter.type.name@ @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
|
||||
|
@ -570,6 +578,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
@parameter.type.name@ @cpp_name@;
|
||||
)~~~");
|
||||
} else {
|
||||
is_wrapped_in_optional_type = true;
|
||||
scoped_generator.append(R"~~~(
|
||||
Optional<@parameter.type.name@> @cpp_name@;
|
||||
)~~~");
|
||||
|
@ -588,6 +597,22 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
if (parameter.type->is_restricted_floating_point()) {
|
||||
if (is_wrapped_in_optional_type) {
|
||||
scoped_generator.append(R"~~~(
|
||||
if (@cpp_name@.has_value() && (isinf(*@cpp_name@) || isnan(*@cpp_name@))) {
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidRestrictedFloatingPointParameter, "@parameter.name@");
|
||||
}
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
if (isinf(@cpp_name@) || isnan(@cpp_name@)) {
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidRestrictedFloatingPointParameter, "@parameter.name@");
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
} else if (parameter.type->name() == "Promise") {
|
||||
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
|
||||
// Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
|
||||
|
@ -1702,7 +1727,7 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const
|
|||
|
||||
@result_expression@ new_array@recursion_depth@;
|
||||
)~~~");
|
||||
} else if (type.name() == "boolean" || type.name() == "double" || type.name() == "float") {
|
||||
} else if (type.name() == "boolean" || type.is_floating_point()) {
|
||||
if (type.is_nullable()) {
|
||||
scoped_generator.append(R"~~~(
|
||||
@result_expression@ JS::Value(@value@.release_value());
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
KeyframeEffect with NaN options value: threw an exception
|
||||
KeyframeEffect with infinite delay value: threw an exception
|
||||
KeyframeEffect with NaN delay value: threw an exception
|
||||
KeyframeEffect with infinite endDelay value: threw an exception
|
||||
KeyframeEffect with NaN endDelay value: threw an exception
|
||||
KeyframeEffect with NaN iterations: threw an exception
|
||||
KeyframeEffect with infinite options value: did not throw an exception
|
||||
KeyframeEffect with finite options value: did not throw an exception
|
||||
KeyframeEffect with infinite iterations: did not throw an exception
|
||||
KeyframeEffect with infinite duration: did not throw an exception
|
|
@ -3,16 +3,24 @@ Testing DOMRect:
|
|||
2. {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10}
|
||||
3. {"x":-10,"y":-20,"width":30,"height":40,"top":-20,"right":20,"bottom":20,"left":-10}
|
||||
4. {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10}
|
||||
5. {"x":null,"y":20,"width":30,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
||||
6. {"x":10,"y":null,"width":30,"height":40,"top":null,"right":40,"bottom":null,"left":10}
|
||||
7. {"x":10,"y":20,"width":null,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
||||
8. {"x":10,"y":20,"width":30,"height":null,"top":null,"right":40,"bottom":null,"left":10}
|
||||
5. Exception: TypeError
|
||||
6. Exception: TypeError
|
||||
7. Exception: TypeError
|
||||
8. Exception: TypeError
|
||||
9. Exception: TypeError
|
||||
10. Exception: TypeError
|
||||
11. Exception: TypeError
|
||||
12. Exception: TypeError
|
||||
Testing DOMRectReadOnly:
|
||||
1. {"x":0,"y":0,"width":0,"height":0,"top":0,"right":0,"bottom":0,"left":0}
|
||||
2. {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10}
|
||||
3. {"x":-10,"y":-20,"width":30,"height":40,"top":-20,"right":20,"bottom":20,"left":-10}
|
||||
4. {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10}
|
||||
5. {"x":null,"y":20,"width":30,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
||||
6. {"x":10,"y":null,"width":30,"height":40,"top":null,"right":40,"bottom":null,"left":10}
|
||||
7. {"x":10,"y":20,"width":null,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
||||
8. {"x":10,"y":20,"width":30,"height":null,"top":null,"right":40,"bottom":null,"left":10}
|
||||
5. Exception: TypeError
|
||||
6. Exception: TypeError
|
||||
7. Exception: TypeError
|
||||
8. Exception: TypeError
|
||||
9. Exception: TypeError
|
||||
10. Exception: TypeError
|
||||
11. Exception: TypeError
|
||||
12. Exception: TypeError
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
function checkException(name, cb) {
|
||||
try {
|
||||
cb();
|
||||
println(`${name}: did not throw an exception`);
|
||||
} catch (e) {
|
||||
println(`${name}: threw an exception`);
|
||||
}
|
||||
}
|
||||
|
||||
// Test invalid values
|
||||
checkException('KeyframeEffect with NaN options value', () => new KeyframeEffect(null, null, NaN));
|
||||
checkException('KeyframeEffect with infinite delay value', () => new KeyframeEffect(null, null, { delay: -Infinity }));;
|
||||
checkException('KeyframeEffect with NaN delay value', () => new KeyframeEffect(null, null, { delay: NaN }));
|
||||
checkException('KeyframeEffect with infinite endDelay value', () => new KeyframeEffect(null, null, { endDelay: Infinity }));
|
||||
checkException('KeyframeEffect with NaN endDelay value', () => new KeyframeEffect(null, null, { endDelay: NaN }));
|
||||
checkException('KeyframeEffect with NaN iterations', () => new KeyframeEffect(null, null, { iterations: NaN }));
|
||||
|
||||
// Test valid values
|
||||
checkException('KeyframeEffect with infinite options value', () => new KeyframeEffect(null, null, Infinity));
|
||||
checkException('KeyframeEffect with finite options value', () => new KeyframeEffect(null, null, 1234.5));
|
||||
checkException('KeyframeEffect with infinite iterations', () => new KeyframeEffect(null, null, { iterations: Infinity }));
|
||||
checkException('KeyframeEffect with infinite duration', () => new KeyframeEffect(null, null, { duration: Infinity }));
|
||||
});
|
||||
</script>
|
|
@ -38,6 +38,18 @@
|
|||
// 8. Creating a DOMRect with NaN height value
|
||||
testPart(() => new Rect(10, 20, 30, NaN));
|
||||
|
||||
// 5. Creating a DOMRect with Infinity x value
|
||||
testPart(() => new Rect(Infinity, 20, 30, 40));
|
||||
|
||||
// 6. Creating a DOMRect with Infinity y value
|
||||
testPart(() => new Rect(10, Infinity, 30, 40));
|
||||
|
||||
// 7. Creating a DOMRect with Infinity width value
|
||||
testPart(() => new Rect(10, 20, Infinity, 40));
|
||||
|
||||
// 8. Creating a DOMRect with Infinity height value
|
||||
testPart(() => new Rect(10, 20, 30, Infinity));
|
||||
|
||||
testCounter = 1;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -225,10 +225,12 @@ NonnullRefPtr<Type const> Parser::parse_type()
|
|||
if (unsigned_)
|
||||
consume_whitespace();
|
||||
|
||||
// FIXME: Actually treat "unrestricted" and normal floats/doubles differently.
|
||||
if (lexer.consume_specific("unrestricted"sv))
|
||||
bool unrestricted = lexer.consume_specific("unrestricted"sv);
|
||||
if (unrestricted)
|
||||
consume_whitespace();
|
||||
|
||||
VERIFY(!(unsigned_ && unrestricted));
|
||||
|
||||
auto name = lexer.consume_until([](auto ch) { return !is_ascii_alphanumeric(ch) && ch != '_'; });
|
||||
|
||||
if (name.equals_ignoring_ascii_case("long"sv)) {
|
||||
|
@ -252,6 +254,9 @@ NonnullRefPtr<Type const> Parser::parse_type()
|
|||
StringBuilder builder;
|
||||
if (unsigned_)
|
||||
builder.append("unsigned "sv);
|
||||
if (unrestricted)
|
||||
builder.append("unrestricted "sv);
|
||||
|
||||
builder.append(name);
|
||||
|
||||
if (nullable) {
|
||||
|
|
|
@ -125,7 +125,7 @@ public:
|
|||
bool is_integer() const { return is_plain() && m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-numeric-type
|
||||
bool is_numeric() const { return is_plain() && (is_integer() || m_name.is_one_of("float", "unrestricted float", "double", "unrestricted double")); }
|
||||
bool is_numeric() const { return is_plain() && (is_integer() || is_floating_point()); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-primitive-type
|
||||
bool is_primitive() const { return is_plain() && (is_numeric() || is_boolean() || m_name == "bigint"); }
|
||||
|
@ -138,6 +138,10 @@ public:
|
|||
|
||||
bool is_json(Interface const&) const;
|
||||
|
||||
bool is_restricted_floating_point() const { return m_name.is_one_of("float", "double"); }
|
||||
bool is_unrestricted_floating_point() const { return m_name.is_one_of("unrestricted float", "unrestricted double"); }
|
||||
bool is_floating_point() const { return is_restricted_floating_point() || is_unrestricted_floating_point(); }
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
ByteString m_name;
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
M(InvalidLength, "Invalid {} length") \
|
||||
M(InvalidOrAmbiguousExportEntry, "Invalid or ambiguous export entry '{}'") \
|
||||
M(InvalidPrecision, "Precision must be an integer no less than 1, and no greater than 100") \
|
||||
M(InvalidRestrictedFloatingPointParameter, "Expected {} to be a finite floating-point number") \
|
||||
M(InvalidTimeValue, "Invalid time value") \
|
||||
M(InvalidRadix, "Radix must be an integer no less than 2, and no greater than 36") \
|
||||
M(IsNotA, "{} is not a {}") \
|
||||
|
|
Loading…
Add table
Reference in a new issue