diff --git a/common/goos/Object.cpp b/common/goos/Object.cpp index 646b665488..d8bcc9446b 100644 --- a/common/goos/Object.cpp +++ b/common/goos/Object.cpp @@ -12,7 +12,7 @@ * Object::make_ * * To convert an Object into a more specific object, use the as_ method of Object. - * It will throw an exception is you get the type wrong. + * It will throw an exception if you get the type wrong. * * These are all the types: * @@ -90,12 +90,42 @@ std::string fixed_to_string(FloatType x) { s64 rounded = x; bool exact_int = ((float)rounded) == x; + // it's an integer number, so let's just get this over with asap if (exact_int) { - sprintf(buff, "%.1f", x); + sprintf(buff, "%lld.0", rounded); return {buff}; } else { - sprintf(buff, "%.6f", x); - return {buff}; + // not an integer - see how many decimal cases we need + // i'm not sure what happens if x is a NaN/inf... + + // buffer for format string + char fmt_buf[256]; + + // we are going to try our hardest to make sure the output is re-parseable + // for what it's worth, the lowest representable 32-bit floating point number has almost 50 + // decimal cases, although: + // - by that point we should just be using scientific notation instead? + // - the PS2 DOES NOT DENORMALIZE FLOATS, or handle NaNs/infs! so the representation wouldn't + // be accurate anyway + // - we might not ever encounter numbers like that. the pretty printer has a "banned" floats + // list just in case + + // 99 might seem high, but we are gonna get the result in under 10 or so most of the time, so + // it's fine. + // maybe there's some math principles or other tricks to optimize this? + for (int i = 1; i <= 99; ++i) { + // generate the format string + sprintf(fmt_buf, "%%.%df", i); + sprintf(buff, fmt_buf, x); + + auto float_from_string = float(std::stod(buff)); + float value_as_float = float(x); + bool are_they_equal = float_from_string == value_as_float; + + if (are_they_equal) + return {buff}; + } + throw std::runtime_error("a float could not be represented accurately"); } } diff --git a/common/goos/Object.h b/common/goos/Object.h index 3aba2221e4..7527dfdbd3 100644 --- a/common/goos/Object.h +++ b/common/goos/Object.h @@ -14,7 +14,7 @@ * Object::make_ * * To convert an Object into a more specific object, use the as_ method of Object. - * It will throw an exception is you get the type wrong. + * It will throw an exception if you get the type wrong. * * These are all the types: * diff --git a/common/goos/PrettyPrinter.cpp b/common/goos/PrettyPrinter.cpp index 445ab046a4..7b7e915c7a 100644 --- a/common/goos/PrettyPrinter.cpp +++ b/common/goos/PrettyPrinter.cpp @@ -15,30 +15,19 @@ namespace pretty_print { namespace { -const std::unordered_set allowed_floats = { - 0.0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.625, - 0.6875, 0.75, 0.8125, 0.875, 0.9375, -0.0625, -0.125, -0.1875, -0.25, -0.3125, -0.375, - -0.4375, -0.5, -0.5625, -0.625, -0.6875, -0.75, -0.8125, -0.875, -0.9375}; -} +// the integer representation is used here instead, wouldn't want really long numbers +const std::unordered_set banned_floats = {}; +} // namespace /*! * Print a float in a nice representation if possibly, or an exact 32-bit integer constant to * be reinterpreted. */ goos::Object float_representation(float value) { - s64 rounded = value; - bool exact_int = ((float)rounded) == value; - if (exact_int || allowed_floats.find(value) != allowed_floats.end()) { - auto result = goos::Object::make_float(value); - - // this is probably very slow for huge numbers of floats, but worth checking. - auto float_as_string = result.print(); - auto as_float_again = float(std::stod(float_as_string)); - assert(as_float_again == value); - - return result; + u32 int_value; + memcpy(&int_value, &value, 4); + if (banned_floats.find(int_value) == banned_floats.end()) { + return goos::Object::make_float(value); } else { - u32 int_value; - memcpy(&int_value, &value, 4); return pretty_print::build_list("the-as", "float", fmt::format("#x{:x}", int_value)); } } @@ -632,4 +621,4 @@ goos::Object build_list(const std::vector& symbols) { } return build_list(f.data(), f.size()); } -} // namespace pretty_print \ No newline at end of file +} // namespace pretty_print diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 1dc1b13845..5621baa8aa 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -32624,7 +32624,33 @@ - +(define-extern *level-load-list* pair) +(define-extern training level-load-info) +(define-extern village1 level-load-info) +(define-extern beach level-load-info) +(define-extern jungle level-load-info) +(define-extern jungleb level-load-info) +(define-extern misty level-load-info) +(define-extern firecanyon level-load-info) +(define-extern village2 level-load-info) +(define-extern sunken level-load-info) +(define-extern sunkenb level-load-info) +(define-extern swamp level-load-info) +(define-extern rolling level-load-info) +(define-extern ogre level-load-info) +(define-extern village3 level-load-info) +(define-extern snow level-load-info) +(define-extern maincave level-load-info) +(define-extern darkcave level-load-info) +(define-extern robocave level-load-info) +(define-extern lavatube level-load-info) +(define-extern citadel level-load-info) +(define-extern finalboss level-load-info) +(define-extern intro level-load-info) +(define-extern demo level-load-info) +(define-extern title level-load-info) +(define-extern halfpipe level-load-info) +(define-extern default-level level-load-info) ;;(define-extern error object) ;; unknown type ;;(define-extern details object) ;; unknown type @@ -33671,7 +33697,6 @@ (define-extern ramdisk-sync function) ;;(define-extern ramdisk-rpc-fill object) ;; unknown type (define-extern swap-sound-buffers function) -;;(define-extern misty object) ;; unknown type (define-extern sound-group-stop function) (define-extern sound-set-ear-trans function) (define-extern sound-pause function) @@ -33687,7 +33712,6 @@ ;;(define-extern *flava-table* object) ;; unknown type (define-extern sound-basic-cb function) ;;(define-extern sound-iop-info object) ;; unknown type -;;(define-extern beach object) ;; unknown type ;;(define-extern flava-table object) ;; unknown type ;;(define-extern empty2 object) ;; unknown type (define-extern sound-bank-unload function) @@ -33695,31 +33719,20 @@ (define-extern get-sound-buffer-entry function) (define-extern current-str-pos function) (define-extern sound-play-by-name function) -;;(define-extern jungleb object) ;; unknown type -;;(define-extern snow object) ;; unknown type -;;(define-extern rolling object) ;; unknown type (define-extern sound-set-falloff-curve function) -;;(define-extern jungle object) ;; unknown type (define-extern sound-name= function) (define-extern new-sound-id function) (define-extern sound-set-reverb function) (define-extern list-sounds function) (define-extern show-iop-info function) (define-extern sound-music-load function) -;;(define-extern finalboss object) ;; unknown type (define-extern sound-trans-convert function) (define-extern sound-set-sound-falloff function) ;;(define-extern flava-table-row object) ;; unknown type -;;(define-extern swamp object) ;; unknown type -;;(define-extern village1 object) ;; unknown type (define-extern sound-group-continue function) -;;(define-extern village2 object) ;; unknown type (define-extern sound-continue function) ;;(define-extern empty1 object) ;; unknown type -;;(define-extern village3 object) ;; unknown type ;;(define-extern *sound-player-enable* object) ;; unknown type -;;(define-extern firecanyon object) ;; unknown type -;;(define-extern citadel object) ;; unknown type (define-extern show-iop-memory function) (define-extern sound-set-volume function) (define-extern sound-command->string function) @@ -33729,11 +33742,8 @@ ;;(define-extern *ambient-spec* object) ;; unknown type (define-extern sound-angle-convert function) (define-extern ear-trans function) -;;(define-extern ogre object) ;; unknown type -;;(define-extern maincave object) ;; unknown type ;;(define-extern credits object) ;; unknown type (define-extern sound-bank-load function) -;;(define-extern lavatube object) ;; unknown type (define-extern sound-group-pause function) (define-extern current-str-id function) (define-extern sound-set-flava function) @@ -34332,7 +34342,6 @@ (define-extern touch-tracker-init function) (define-extern position-in-front-of-camera! function) ;;(define-extern reset object) ;; unknown type -;;(define-extern *level-load-list* object) ;; unknown type ;;(define-extern life object) ;; unknown type ;;(define-extern *spawn-actors* object) ;; unknown type ;;(define-extern eco-pill object) ;; unknown type @@ -34369,7 +34378,6 @@ (define-extern progress-allowed? function) ;;(define-extern *level-task-data* object) ;; unknown type ;;(define-extern format-card object) ;; unknown type -;;(define-extern training object) ;; unknown type ;;(define-extern mc-format object) ;; unknown type (define-extern get-task-status function) ;;(define-extern create-file object) ;; unknown type @@ -34613,7 +34621,6 @@ (define-extern update-sky-tng-data function) ;;(define-extern sky-base-polygons object) ;; unknown type (define-extern make-sky-textures function) -;;(define-extern sunken object) ;; unknown type (define-extern sky-set-orbit function) (define-extern sky-set-sun-colors-sun function) (define-extern sky-set-sun-colors-halo function) @@ -34749,23 +34756,15 @@ ;;(define-extern vi2 object) ;; unknown type ;;(define-extern rol object) ;; unknown type ;;(define-extern cit object) ;; unknown type -;;(define-extern darkcave object) ;; unknown type ;;(define-extern bea object) ;; unknown type ;;(define-extern vi3 object) ;; unknown type ;;(define-extern fin object) ;; unknown type ;;(define-extern display-no-wait object) ;; unknown type -;;(define-extern sunkenb object) ;; unknown type ;;(define-extern jun object) ;; unknown type ;;(define-extern special-vis object) ;; unknown type -;;(define-extern robocave object) ;; unknown type ;;(define-extern mai object) ;; unknown type ;;(define-extern lav object) ;; unknown type ;;(define-extern sun object) ;; unknown type -;;(define-extern title object) ;; unknown type -;;(define-extern demo object) ;; unknown type -;;(define-extern default-level object) ;; unknown type -;;(define-extern intro object) ;; unknown type -;;(define-extern halfpipe object) ;; unknown type ;;(define-extern none object) ;; unknown type ;;(define-extern robocave-vis object) ;; unknown type ;;(define-extern tra object) ;; unknown type diff --git a/test-goal-typecoherency.bat b/test-goal-typecoherency.bat deleted file mode 100644 index b16e293584..0000000000 --- a/test-goal-typecoherency.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -out\build\Release\bin\goalc-test --gtest_filter="*TypeConsistency*" -pause \ No newline at end of file diff --git a/test.bat b/test.bat new file mode 100644 index 0000000000..fb960d0b1e --- /dev/null +++ b/test.bat @@ -0,0 +1,3 @@ +@echo off +out\build\Release\bin\goalc-test +pause \ No newline at end of file diff --git a/test/decompiler/test_DataParser.cpp b/test/decompiler/test_DataParser.cpp index bbc1d4deab..14c1519748 100644 --- a/test/decompiler/test_DataParser.cpp +++ b/test/decompiler/test_DataParser.cpp @@ -289,31 +289,31 @@ TEST_F(DataDecompTest, ContinuePoint) { " :name \"finalboss-start\"\n" " :level 'finalboss\n" " :trans (new 'static 'vector\n" - " :x 11548456.000000\n" - " :y 2215872.000000\n" - " :z -19409498.000000\n" - " :w 1.000000\n" + " :x 11548456.0\n" + " :y 2215872.0\n" + " :z -19409498.0\n" + " :w 1.0\n" " )\n" " :quat (new 'static 'vector\n" - " :y (the-as float #x3f3b851f)\n" - " :w (the-as float #x3f2e425b)\n" + " :y 0.7325\n" + " :w 0.6807\n" " )\n" " :camera-trans (new 'static 'vector\n" - " :x 11513311.000000\n" - " :y (the-as float #x4a0869de)\n" - " :z -19435708.000000\n" - " :w 1.000000\n" + " :x 11513311.0\n" + " :y 2234999.5\n" + " :z -19435708.0\n" + " :w 1.0\n" " )\n" " :camera-rot (new 'static 'array 'float 9\n" - " (the-as float #x3f169ad4)\n" - " 0.000000\n" - " (the-as float #xbf4ef9db)\n" - " (the-as float #x3ddbf488)\n" - " (the-as float #x3f7db8bb)\n" - " (the-as float #x3d9ff2e5)\n" - " (the-as float #x3f4d288d)\n" - " (the-as float #xbe07fcb9)\n" - " (the-as float #x3f15460b)\n" + " 0.5883\n" + " 0.0\n" + " -0.8085\n" + " 0.1074\n" + " 0.9911\n" + " 0.0781\n" + " 0.8014\n" + " -0.1328\n" + " 0.5831\n" " )\n" " :load-commands (('special \"citb-exit-plat-4\" #t))\n" " :vis-nick 'fin\n" @@ -341,4 +341,4 @@ TEST_F(DataDecompTest, FloatArray) { check_forms_equal(decomp.print(), "(new 'static 'array 'float 7\n" "1.0 0.0 1.0 0.0 1.0 0.0 1.0)"); -} \ No newline at end of file +} diff --git a/test/test_goos.cpp b/test/test_goos.cpp index c5fb8415fc..029ae0e962 100644 --- a/test/test_goos.cpp +++ b/test/test_goos.cpp @@ -155,11 +155,11 @@ TEST(GoosBuiltins, Addition) { // two element adding EXPECT_EQ(e(i, "(+ 1 2)"), "3"); - EXPECT_EQ(e(i, "(+ 1.1 2.2)"), "3.300000"); + EXPECT_EQ(e(i, "(+ 1.1 2.2)"), "3.3"); // mixed EXPECT_EQ(e(i, "(+ 1 1.1)"), "2"); - EXPECT_EQ(e(i, "(+ 1.1 1)"), "2.100000"); + EXPECT_EQ(e(i, "(+ 1.1 1)"), "2.1"); // many, and check rounding happens at the right time EXPECT_EQ(e(i, "(+ 1 1.4 1.4 1.4 1.4)"), "5"); @@ -178,11 +178,11 @@ TEST(GoosBuiltins, Multiplication) { // two element adding EXPECT_EQ(e(i, "(* 3 2)"), "6"); - EXPECT_EQ(e(i, "(* 1.1 2.2)"), "2.420000"); + EXPECT_EQ(e(i, "(* 1.1 2.2)"), "2.42"); // mixed EXPECT_EQ(e(i, "(* 1 1.1)"), "1"); - EXPECT_EQ(e(i, "(* 1.1 1)"), "1.100000"); + EXPECT_EQ(e(i, "(* 1.1 1)"), "1.1"); // many, and check rounding happens at the right time EXPECT_EQ(e(i, "(* 3 1.4 1.4 1.4 1.4)"), "3"); @@ -201,11 +201,11 @@ TEST(GoosBuiltins, Subtraction) { // two element adding EXPECT_EQ(e(i, "(- 3 2)"), "1"); - EXPECT_EQ(e(i, "(- 1.1 2.2)"), "-1.100000"); + EXPECT_EQ(e(i, "(- 1.1 2.2)"), "-1.1"); // mixed EXPECT_EQ(e(i, "(- 1 1.1)"), "0"); - EXPECT_EQ(e(i, "(- 1.1 1)"), "0.100000"); + EXPECT_EQ(e(i, "(- 1.1 1)"), "0.1"); // many, and check rounding happens at the right time EXPECT_EQ(e(i, "(- 3 1.4 1.4 1.4 1.4)"), "-1"); @@ -221,11 +221,11 @@ TEST(GoosBuiltins, Division) { // two element adding EXPECT_EQ(e(i, "(/ 16 2)"), "8"); - EXPECT_EQ(e(i, "(/ 9. 2.)"), "4.500000"); + EXPECT_EQ(e(i, "(/ 9. 2.)"), "4.5"); // mixed EXPECT_EQ(e(i, "(/ 3 2.)"), "1"); - EXPECT_EQ(e(i, "(/ 3. 2)"), "1.500000"); + EXPECT_EQ(e(i, "(/ 3. 2)"), "1.5"); i.disable_printfs(); for (auto x : {"(/ 1)", "(/ 1.0)", "(/)", "(/ 'a)", "(/ #\\a)", "(/ 1 :test 2)", @@ -494,7 +494,7 @@ TEST(GoosEval, EvalSelfEvaluating) { EXPECT_EQ(e(i, "010"), "10"); EXPECT_EQ(e(i, "-010"), "-10"); EXPECT_EQ(e(i, "\"test\""), "\"test\""); - EXPECT_EQ(e(i, "1.2"), "1.200000"); // this depends on how we decide to print floats + EXPECT_EQ(e(i, "1.2"), "1.2"); // this depends on how we decide to print floats EXPECT_EQ(e(i, "#\\a"), "#\\a"); EXPECT_EQ(e(i, "#\\\\n"), "#\\\\n"); @@ -502,6 +502,16 @@ TEST(GoosEval, EvalSelfEvaluating) { EXPECT_ANY_THROW(e(i, "#\\\\a")); } +TEST(GoosEval, FloatEvalAndPrinting) { + Interpreter i; + EXPECT_EQ(e(i, "0.9999979734420776"), "0.999998"); + EXPECT_EQ(e(i, "0.999998"), e(i, "0.9999979734420776")); + EXPECT_EQ(e(i, "1."), "1.0"); + EXPECT_EQ(e(i, ".03"), "0.03"); + EXPECT_EQ(e(i, "0.02999999932944774627685546875"), e(i, "0.03")); + EXPECT_EQ(e(i, "0.5883"), e(i, "0.5882999897")); +} + /*! * Check named "keyword" arguments */ @@ -1020,8 +1030,8 @@ TEST(GoosObject, Float) { EXPECT_TRUE(different == same); // check print and inspect - EXPECT_EQ(different.print(), "-12.340000"); - EXPECT_EQ(different.inspect(), "[float] -12.340000\n"); + EXPECT_EQ(different.print(), "-12.34"); + EXPECT_EQ(different.inspect(), "[float] -12.34\n"); } /*! @@ -1300,4 +1310,4 @@ TEST(GoosBuiltins, Format) { TEST(GoosBuiltins, Error) { Interpreter i; EXPECT_ANY_THROW(e(i, "(error \"hi\")")); -} \ No newline at end of file +}