From 86d54a8684eabf7ae476d802ba7b14ea1f6872fa Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Sat, 20 Jan 2024 21:18:05 -0500 Subject: [PATCH] JSSpecCompiler: Parse arbitrarily large rational numbers in xspec mode --- .../CodeGenerators/JSSpecCompiler/AST/AST.h | 9 +++--- .../JSSpecCompiler/AST/ASTPrinting.cpp | 7 ++++- .../JSSpecCompiler/CMakeLists.txt | 2 +- .../JSSpecCompiler/Parser/CppASTConverter.cpp | 3 +- .../JSSpecCompiler/Parser/TextParser.cpp | 2 +- .../JSSpecCompiler/Tests/spec-parsing.xml | 16 ++++++++++ .../Tests/spec-parsing.xml.expectation | 29 +++++++++++++++++++ Tests/JSSpecCompiler/test-runner.cpp | 1 + .../LibCrypto/BigFraction/BigFraction.h | 3 ++ 9 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml create mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h index 9937c96083..93d9f79fb1 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "Forward.h" @@ -208,16 +209,16 @@ protected: class MathematicalConstant : public Expression { public: - MathematicalConstant(i64 number) + MathematicalConstant(Crypto::BigFraction number) : m_number(number) { } - // TODO: This should be able to hold arbitrary number - i64 m_number; - protected: void dump_tree(StringBuilder& builder) override; + +private: + Crypto::BigFraction m_number; }; class StringLiteral : public Expression { diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp index 771b4b1cad..ec5f4108a2 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp @@ -62,7 +62,12 @@ void ControlFlowBranch::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) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt index 18f7850404..a442a0bb5e 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/CMakeLists.txt @@ -21,6 +21,6 @@ set(SOURCES 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_compile_options(JSSpecCompiler PRIVATE -Wno-missing-field-initializers) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp index b83a26c58f..5a46c8db65 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/CppASTConverter.cpp @@ -126,7 +126,8 @@ template<> NullableTree CppASTConverter::convert_node(Cpp::NumericLiteral const& literal) { // TODO: Numerical literals are not limited to i64. - return make_ref_counted(literal.value().to_number().value()); + VERIFY(literal.value().to_number().has_value()); + return make_ref_counted(MUST(Crypto::BigFraction::from_string(literal.value()))); } template<> diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp index cc52684f4f..173d1322de 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp @@ -299,7 +299,7 @@ TextParseErrorOr TextParser::parse_expression() if (token.type == TokenType::Identifier) { expression = make_ref_counted(token.data); } else if (token.type == TokenType::Number) { - expression = make_ref_counted(token.data.to_number().value()); + expression = make_ref_counted(MUST(Crypto::BigFraction::from_string(token.data))); } else if (token.type == TokenType::String) { expression = make_ref_counted(token.data); } else { diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml new file mode 100644 index 0000000000..6a75ee8bf7 --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml @@ -0,0 +1,16 @@ +]> + + +

1 ArbitrarilyLargeNumbers ( a )

+ +
    +
  1. Let a be 1.
  2. +
  3. Let b be 3.6.
  4. +
  5. Let c be -3.6.
  6. +
  7. Let d be -1000000000000000000000.
  8. +
  9. Let e be 1.0000001.
  10. +
  11. Return a+b+c+d+e.
  12. +
+
+
+
diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation new file mode 100644 index 0000000000..cba8728620 --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Tests/spec-parsing.xml.expectation @@ -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 + diff --git a/Tests/JSSpecCompiler/test-runner.cpp b/Tests/JSSpecCompiler/test-runner.cpp index 27df47276c..43b0d7d22d 100644 --- a/Tests/JSSpecCompiler/test-runner.cpp +++ b/Tests/JSSpecCompiler/test-runner.cpp @@ -50,6 +50,7 @@ const Array regression_tests = { TestDescription { .sources = { "spec-no-new-line-after-dot.xml"sv, + "spec-parsing.xml"sv, "spec-single-function-simple.xml"sv, }, .flags = { dump_after_frontend }, diff --git a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h index aaa18a85c2..6fdf647bb0 100644 --- a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h +++ b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h @@ -58,6 +58,9 @@ public: ByteString to_byte_string(unsigned rounding_threshold) const; double to_double() const; + Crypto::SignedBigInteger const& numerator() const& { return m_numerator; } + Crypto::UnsignedBigInteger const& denominator() const& { return m_denominator; } + private: void reduce();