1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:37:35 +00:00

JSSpecCompiler: Parse arbitrarily large rational numbers in xspec mode

This commit is contained in:
Dan Klishch 2024-01-20 21:18:05 -05:00 committed by Andrew Kaster
parent 2a2e31f2ed
commit 86d54a8684
9 changed files with 64 additions and 8 deletions

View file

@ -10,6 +10,7 @@
#include <AK/RefCounted.h> #include <AK/RefCounted.h>
#include <AK/RefPtr.h> #include <AK/RefPtr.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCrypto/BigFraction/BigFraction.h>
#include "Forward.h" #include "Forward.h"
@ -208,16 +209,16 @@ protected:
class MathematicalConstant : public Expression { class MathematicalConstant : public Expression {
public: public:
MathematicalConstant(i64 number) MathematicalConstant(Crypto::BigFraction number)
: m_number(number) : m_number(number)
{ {
} }
// TODO: This should be able to hold arbitrary number
i64 m_number;
protected: protected:
void dump_tree(StringBuilder& builder) override; void dump_tree(StringBuilder& builder) override;
private:
Crypto::BigFraction m_number;
}; };
class StringLiteral : public Expression { class StringLiteral : public Expression {

View file

@ -62,7 +62,12 @@ void ControlFlowBranch::dump_tree(StringBuilder& builder)
void MathematicalConstant::dump_tree(StringBuilder& builder) void MathematicalConstant::dump_tree(StringBuilder& builder)
{ {
dump_node(builder, "MathematicalConstant {}", m_number); String representation;
if (Crypto::UnsignedBigInteger { 1000 }.divided_by(m_number.denominator()).remainder == 0)
representation = MUST(String::from_byte_string(m_number.to_byte_string(3)));
else
representation = MUST(String::formatted("{}/{}", MUST(m_number.numerator().to_base(10)), MUST(m_number.denominator().to_base(10))));
dump_node(builder, "MathematicalConstant {}", representation);
} }
void StringLiteral::dump_tree(StringBuilder& builder) void StringLiteral::dump_tree(StringBuilder& builder)

View file

@ -21,6 +21,6 @@ set(SOURCES
main.cpp main.cpp
) )
lagom_tool(JSSpecCompiler LIBS LibCpp LibMain LibXML) lagom_tool(JSSpecCompiler LIBS LibCpp LibMain LibXML LibCrypto)
target_include_directories(JSSpecCompiler PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(JSSpecCompiler PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(JSSpecCompiler PRIVATE -Wno-missing-field-initializers) target_compile_options(JSSpecCompiler PRIVATE -Wno-missing-field-initializers)

View file

@ -126,7 +126,8 @@ template<>
NullableTree CppASTConverter::convert_node(Cpp::NumericLiteral const& literal) NullableTree CppASTConverter::convert_node(Cpp::NumericLiteral const& literal)
{ {
// TODO: Numerical literals are not limited to i64. // TODO: Numerical literals are not limited to i64.
return make_ref_counted<MathematicalConstant>(literal.value().to_number<i64>().value()); VERIFY(literal.value().to_number<i64>().has_value());
return make_ref_counted<MathematicalConstant>(MUST(Crypto::BigFraction::from_string(literal.value())));
} }
template<> template<>

View file

@ -299,7 +299,7 @@ TextParseErrorOr<Tree> TextParser::parse_expression()
if (token.type == TokenType::Identifier) { if (token.type == TokenType::Identifier) {
expression = make_ref_counted<UnresolvedReference>(token.data); expression = make_ref_counted<UnresolvedReference>(token.data);
} else if (token.type == TokenType::Number) { } else if (token.type == TokenType::Number) {
expression = make_ref_counted<MathematicalConstant>(token.data.to_number<i64>().value()); expression = make_ref_counted<MathematicalConstant>(MUST(Crypto::BigFraction::from_string(token.data)));
} else if (token.type == TokenType::String) { } else if (token.type == TokenType::String) {
expression = make_ref_counted<StringLiteral>(token.data); expression = make_ref_counted<StringLiteral>(token.data);
} else { } else {

View file

@ -0,0 +1,16 @@
<!DOCTYPE inline_dtd[<!ENTITY nbsp " ">]>
<specification>
<emu-clause id="1" aoid="ArbitrarilyLargeNumbers">
<h1><span class="secnum">1</span> ArbitrarilyLargeNumbers ( <var>a</var> )</h1>
<emu-alg>
<ol>
<li>Let <var>a</var> be 1.</li>
<li>Let <var>b</var> be 3.6.</li>
<li>Let <var>c</var> be -3.6.</li>
<li>Let <var>d</var> be -1000000000000000000000.</li>
<li>Let <var>e</var> be 1.0000001.</li>
<li>Return <var>a</var>+<var>b</var>+<var>c</var>+<var>d</var>+<var>e</var>.</li>
</ol>
</emu-alg>
</emu-clause>
</specification>

View file

@ -0,0 +1,29 @@
===== AST after reference-resolving =====
ArbitrarilyLargeNumbers(a):
TreeList
BinaryOperation Assignment
Var a
MathematicalConstant 1
BinaryOperation Assignment
Var b
MathematicalConstant 3.6
BinaryOperation Assignment
Var c
MathematicalConstant -3.6
BinaryOperation Assignment
Var d
MathematicalConstant -1000000000000000000000
BinaryOperation Assignment
Var e
MathematicalConstant 10000001/10000000
ReturnNode
BinaryOperation Plus
Var a
BinaryOperation Plus
Var b
BinaryOperation Plus
Var c
BinaryOperation Plus
Var d
Var e

View file

@ -50,6 +50,7 @@ const Array regression_tests = {
TestDescription { TestDescription {
.sources = { .sources = {
"spec-no-new-line-after-dot.xml"sv, "spec-no-new-line-after-dot.xml"sv,
"spec-parsing.xml"sv,
"spec-single-function-simple.xml"sv, "spec-single-function-simple.xml"sv,
}, },
.flags = { dump_after_frontend }, .flags = { dump_after_frontend },

View file

@ -58,6 +58,9 @@ public:
ByteString to_byte_string(unsigned rounding_threshold) const; ByteString to_byte_string(unsigned rounding_threshold) const;
double to_double() const; double to_double() const;
Crypto::SignedBigInteger const& numerator() const& { return m_numerator; }
Crypto::UnsignedBigInteger const& denominator() const& { return m_denominator; }
private: private:
void reduce(); void reduce();