mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 04:13:11 +00:00
IDLGenerators: Handle restricted/unrestricted floating point types
This commit is contained in:
parent
2bd8093449
commit
3e221fbb2d
|
@ -165,10 +165,10 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
|
||||||
if (type.is_string())
|
if (type.is_string())
|
||||||
return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector };
|
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 };
|
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 };
|
return { .name = "float", .sequence_storage_type = SequenceStorageType::Vector };
|
||||||
|
|
||||||
if (type.name() == "boolean" && !type.is_nullable())
|
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("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("string_type", string_to_fly_string ? "FlyString" : "String");
|
||||||
scoped_generator.set("parameter.type.name", parameter.type->name());
|
scoped_generator.set("parameter.type.name", parameter.type->name());
|
||||||
|
scoped_generator.set("parameter.name", parameter.name);
|
||||||
|
|
||||||
if (explicit_null) {
|
if (explicit_null) {
|
||||||
if (!IDL::is_platform_object(*parameter.type)) {
|
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) {
|
if (!optional) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
@parameter.type.name@ @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
|
@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@;
|
@parameter.type.name@ @cpp_name@;
|
||||||
)~~~");
|
)~~~");
|
||||||
} else {
|
} else {
|
||||||
|
is_wrapped_in_optional_type = true;
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
Optional<@parameter.type.name@> @cpp_name@;
|
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") {
|
} else if (parameter.type->name() == "Promise") {
|
||||||
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
|
// 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
|
// 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@;
|
@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()) {
|
if (type.is_nullable()) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
@result_expression@ JS::Value(@value@.release_value());
|
@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}
|
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}
|
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}
|
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}
|
5. Exception: TypeError
|
||||||
6. {"x":10,"y":null,"width":30,"height":40,"top":null,"right":40,"bottom":null,"left":10}
|
6. Exception: TypeError
|
||||||
7. {"x":10,"y":20,"width":null,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
7. Exception: TypeError
|
||||||
8. {"x":10,"y":20,"width":30,"height":null,"top":null,"right":40,"bottom":null,"left":10}
|
8. Exception: TypeError
|
||||||
|
9. Exception: TypeError
|
||||||
|
10. Exception: TypeError
|
||||||
|
11. Exception: TypeError
|
||||||
|
12. Exception: TypeError
|
||||||
Testing DOMRectReadOnly:
|
Testing DOMRectReadOnly:
|
||||||
1. {"x":0,"y":0,"width":0,"height":0,"top":0,"right":0,"bottom":0,"left":0}
|
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}
|
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}
|
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}
|
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}
|
5. Exception: TypeError
|
||||||
6. {"x":10,"y":null,"width":30,"height":40,"top":null,"right":40,"bottom":null,"left":10}
|
6. Exception: TypeError
|
||||||
7. {"x":10,"y":20,"width":null,"height":40,"top":20,"right":null,"bottom":60,"left":null}
|
7. Exception: TypeError
|
||||||
8. {"x":10,"y":20,"width":30,"height":null,"top":null,"right":40,"bottom":null,"left":10}
|
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
|
// 8. Creating a DOMRect with NaN height value
|
||||||
testPart(() => new Rect(10, 20, 30, NaN));
|
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;
|
testCounter = 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -225,10 +225,12 @@ NonnullRefPtr<Type const> Parser::parse_type()
|
||||||
if (unsigned_)
|
if (unsigned_)
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
// FIXME: Actually treat "unrestricted" and normal floats/doubles differently.
|
bool unrestricted = lexer.consume_specific("unrestricted"sv);
|
||||||
if (lexer.consume_specific("unrestricted"sv))
|
if (unrestricted)
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
|
VERIFY(!(unsigned_ && unrestricted));
|
||||||
|
|
||||||
auto name = lexer.consume_until([](auto ch) { return !is_ascii_alphanumeric(ch) && ch != '_'; });
|
auto name = lexer.consume_until([](auto ch) { return !is_ascii_alphanumeric(ch) && ch != '_'; });
|
||||||
|
|
||||||
if (name.equals_ignoring_ascii_case("long"sv)) {
|
if (name.equals_ignoring_ascii_case("long"sv)) {
|
||||||
|
@ -252,6 +254,9 @@ NonnullRefPtr<Type const> Parser::parse_type()
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
if (unsigned_)
|
if (unsigned_)
|
||||||
builder.append("unsigned "sv);
|
builder.append("unsigned "sv);
|
||||||
|
if (unrestricted)
|
||||||
|
builder.append("unrestricted "sv);
|
||||||
|
|
||||||
builder.append(name);
|
builder.append(name);
|
||||||
|
|
||||||
if (nullable) {
|
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"); }
|
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
|
// 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
|
// https://webidl.spec.whatwg.org/#dfn-primitive-type
|
||||||
bool is_primitive() const { return is_plain() && (is_numeric() || is_boolean() || m_name == "bigint"); }
|
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_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:
|
private:
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
ByteString m_name;
|
ByteString m_name;
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
M(InvalidLength, "Invalid {} length") \
|
M(InvalidLength, "Invalid {} length") \
|
||||||
M(InvalidOrAmbiguousExportEntry, "Invalid or ambiguous export entry '{}'") \
|
M(InvalidOrAmbiguousExportEntry, "Invalid or ambiguous export entry '{}'") \
|
||||||
M(InvalidPrecision, "Precision must be an integer no less than 1, and no greater than 100") \
|
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(InvalidTimeValue, "Invalid time value") \
|
||||||
M(InvalidRadix, "Radix must be an integer no less than 2, and no greater than 36") \
|
M(InvalidRadix, "Radix must be an integer no less than 2, and no greater than 36") \
|
||||||
M(IsNotA, "{} is not a {}") \
|
M(IsNotA, "{} is not a {}") \
|
||||||
|
|
Loading…
Reference in a new issue