diff --git a/.vs/launch.vs.json b/.vs/launch.vs.json index 9c074ac9ac..b5eeee033a 100644 --- a/.vs/launch.vs.json +++ b/.vs/launch.vs.json @@ -68,6 +68,18 @@ "jak2" ] }, + { + "type": "default", + "project": "CMakeLists.txt", + "projectTarget": "offline-test.exe (bin\\offline-test.exe)", + "name": "Tests - Offline Tests - Jak 3", + "args": [ + "--iso_data_path", + "${workspaceRoot}/iso_data/jak3", + "--game", + "jak3" + ] + }, { "type": "default", "project": "CMakeLists.txt", diff --git a/Taskfile.yml b/Taskfile.yml index 485457fb9e..62075cc64e 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -90,7 +90,7 @@ tasks: - cmd: python ./scripts/cpp/format-includes.py - cmd: python ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i - task: format-json - + # DECOMPILING decomp: cmds: @@ -165,9 +165,6 @@ tasks: ignore_error: true - python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}} - task: offline-test-file - type-test-jak1: - cmds: - - cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak1TypeConsistency*" --gtest_break_on_failure' type-test: cmds: - - cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak2TypeConsistency*" --gtest_break_on_failure' + - cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*{{.TYPE_CONSISTENCY_TEST_FILTER}}*" --gtest_break_on_failure' diff --git a/common/goos/Reader.cpp b/common/goos/Reader.cpp index 30a7cfd01c..cef965ea7b 100644 --- a/common/goos/Reader.cpp +++ b/common/goos/Reader.cpp @@ -238,9 +238,14 @@ Object Reader::read_from_string(const std::string& str, * Read a file */ Object Reader::read_from_file(const std::vector& file_path, bool check_encoding) { - std::string joined_path = fmt::format("{}", fmt::join(file_path, "/")); + std::string file_descriptor = fmt::format("{}", fmt::join(file_path, "/")); + const auto joined_file_path = file_util::get_file_path(file_path); - auto textFrag = std::make_shared(file_util::get_file_path(file_path), joined_path); + if (!fs::exists(joined_file_path)) { + throw std::runtime_error(fmt::format("Cannot read {}, file doesn't exist", joined_file_path)); + } + + auto textFrag = std::make_shared(joined_file_path, file_descriptor); db.insert(textFrag); auto result = internal_read(textFrag, check_encoding); diff --git a/common/goos/TextDB.cpp b/common/goos/TextDB.cpp index 054516abd0..90133d920f 100644 --- a/common/goos/TextDB.cpp +++ b/common/goos/TextDB.cpp @@ -85,9 +85,9 @@ std::pair SourceText::get_containing_line(int offset) { /*! * Read text from a file. */ -FileText::FileText(const std::string& filename, const std::string& description_name) - : m_filename(filename), m_desc_name(description_name) { - m_text = file_util::read_text_file(m_filename); +FileText::FileText(const std::string& file_path, const std::string& description_name) + : m_filepath(file_path), m_desc_name(description_name) { + m_text = file_util::read_text_file(m_filepath); build_offsets(); } diff --git a/common/goos/TextDB.h b/common/goos/TextDB.h index 70161dae05..57e7668b63 100644 --- a/common/goos/TextDB.h +++ b/common/goos/TextDB.h @@ -80,13 +80,13 @@ class ProgramString : public SourceText { */ class FileText : public SourceText { public: - FileText(const std::string& filename, const std::string& description_name); + FileText(const std::string& file_path, const std::string& description_name); std::string get_description() { return m_desc_name; } ~FileText() = default; private: - std::string m_filename; + std::string m_filepath; std::string m_desc_name; }; diff --git a/common/util/FileUtil.cpp b/common/util/FileUtil.cpp index ace9b47929..dc08cfed35 100644 --- a/common/util/FileUtil.cpp +++ b/common/util/FileUtil.cpp @@ -636,6 +636,9 @@ std::vector find_files_in_dir(const fs::path& dir, const std::regex& p std::vector find_files_recursively(const fs::path& base_dir, const std::regex& pattern) { std::vector files = {}; + if (!fs::exists(base_dir)) { + return files; + } for (auto& p : fs::recursive_directory_iterator(base_dir)) { if (p.is_regular_file()) { if (std::regex_match(p.path().filename().string(), pattern)) { diff --git a/decompiler/config/jak1/all-types.gc b/decompiler/config/jak1/all-types.gc index aee0f05485..398f361eb8 100644 --- a/decompiler/config/jak1/all-types.gc +++ b/decompiler/config/jak1/all-types.gc @@ -13,7 +13,7 @@ (z float :offset 64) (w float :offset 96)) :method-count-assert 9 - :size-assert #x10 + :size-assert #x10 :flag-assert #x900000010 ) diff --git a/decompiler/config/jak3/all-types.gc b/decompiler/config/jak3/all-types.gc index 0c86266928..107b822544 100644 --- a/decompiler/config/jak3/all-types.gc +++ b/decompiler/config/jak3/all-types.gc @@ -252,7 +252,7 @@ ;; (define-extern lognot function) ;; (function int int) ;; (define-extern false-func function) ;; (function symbol) ;; (define-extern true-func function) ;; (function symbol) -;; (define-extern format object) ;; (function _varargs_ object) +(define-extern format (function _varargs_ object)) ;; (define-extern basic-type? function) ;; (function basic type symbol) ;; (define-extern type-type? function) ;; (function type type symbol) ;; (define-extern type? function) ;; (function object type symbol) @@ -2826,12 +2826,11 @@ (basic-reserved-method-28 () none) ;; 28 ) ) -|# -;; (deftype part-id (uint32) -;; () -;; :flag-assert #x900000004 -;; ) +(deftype part-id (uint32) + () + :flag-assert #x900000004 + ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/scripts/tasks/.env.default b/scripts/tasks/.env.default index 0cd0388abd..7cac9a7c55 100644 --- a/scripts/tasks/.env.default +++ b/scripts/tasks/.env.default @@ -1,3 +1,4 @@ GAME=jak1 DECOMP_CONFIG=jak1/jak1_config.jsonc DECOMP_CONFIG_VERSION=ntsc_v1 +TYPE_CONSISTENCY_TEST_FILTER=Jak1TypeConsistency diff --git a/scripts/tasks/update-env.py b/scripts/tasks/update-env.py index d1b64a4999..5bf045f1f2 100644 --- a/scripts/tasks/update-env.py +++ b/scripts/tasks/update-env.py @@ -69,6 +69,12 @@ default_config_version_map = { "jak3": "ntsc_v1" } +type_consistency_filter_map = { + "jak1": "Jak1TypeConsistency", + "jak2": "Jak2TypeConsistency", + "jak3": "Jak3TypeConsistency" +} + if args.game: if args.game not in valid_games: print("Unsupported game '{}'".format(args.game)) @@ -78,12 +84,14 @@ if args.game: if (curr != file["GAME"]) or file["DECOMP_CONFIG_VERSION"] not in decomp_config_version_map[file["GAME"]]: file["DECOMP_CONFIG"] = decomp_config_map[file["GAME"]] file["DECOMP_CONFIG_VERSION"] = default_config_version_map[file["GAME"]] + file["TYPE_CONSISTENCY_TEST_FILTER"] = type_consistency_filter_map[file["GAME"]] if args.decomp_config: if args.decomp_config not in decomp_config_version_map[file["GAME"]]: print("Unsupported decomp config '{}' for game '{}'".format(args.decomp_config, file["GAME"])) sys.exit(1) file["DECOMP_CONFIG"] = decomp_config_map[file["GAME"]] file["DECOMP_CONFIG_VERSION"] = decomp_config_version_map[file["GAME"]][args.decomp_config] + file["TYPE_CONSISTENCY_TEST_FILTER"] = type_consistency_filter_map[file["GAME"]] with open(env_path, 'w') as env_file: for item in file.items(): diff --git a/test/decompiler/reference/jak3/decompiler-macros.gc b/test/decompiler/reference/jak3/decompiler-macros.gc new file mode 100644 index 0000000000..22c9d8ad03 --- /dev/null +++ b/test/decompiler/reference/jak3/decompiler-macros.gc @@ -0,0 +1 @@ +;; This file should contain an implementation for all macros that the decompiler uses in its output. diff --git a/test/goalc/test_type_consistency.cpp b/test/goalc/test_type_consistency.cpp index 93209761a2..21fb47d078 100644 --- a/test/goalc/test_type_consistency.cpp +++ b/test/goalc/test_type_consistency.cpp @@ -17,7 +17,8 @@ void add_jak2_expected_type_mismatches(Compiler& c) { c.add_ignored_type_definition("editable-plane"); } -// TODO - debatably delete these now that jak 1 is complete +void add_jak3_expected_type_mismatches(Compiler& c) {} + TEST(Jak1TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) { Compiler compiler(GameVersion::Jak1); compiler.enable_throw_on_redefines(); @@ -27,7 +28,24 @@ TEST(Jak1TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) { compiler.run_test_no_load("decompiler/config/jak1/all-types.gc"); } -// TODO - debatably delete these now that jak 1 is complete +TEST(Jak2TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) { + Compiler compiler(GameVersion::Jak2); + compiler.enable_throw_on_redefines(); + add_common_expected_type_mismatches(compiler); + add_jak2_expected_type_mismatches(compiler); + compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc"); + compiler.run_test_no_load("decompiler/config/jak2/all-types.gc"); +} + +TEST(Jak3TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) { + Compiler compiler(GameVersion::Jak3); + compiler.enable_throw_on_redefines(); + add_common_expected_type_mismatches(compiler); + add_jak3_expected_type_mismatches(compiler); + compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc"); + compiler.run_test_no_load("decompiler/config/jak3/all-types.gc"); +} + TEST(Jak1TypeConsistency, TypeConsistency) { Compiler compiler(GameVersion::Jak1); compiler.enable_throw_on_redefines(); @@ -46,11 +64,11 @@ TEST(Jak2TypeConsistency, TypeConsistency) { compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc"); } -TEST(Jak2TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) { - Compiler compiler(GameVersion::Jak2); +TEST(Jak3TypeConsistency, TypeConsistency) { + Compiler compiler(GameVersion::Jak3); compiler.enable_throw_on_redefines(); add_common_expected_type_mismatches(compiler); - add_jak2_expected_type_mismatches(compiler); + add_jak3_expected_type_mismatches(compiler); + compiler.run_test_no_load("decompiler/config/jak3/all-types.gc"); compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc"); - compiler.run_test_no_load("decompiler/config/jak2/all-types.gc"); } diff --git a/test/offline/config/jak3/config.jsonc b/test/offline/config/jak3/config.jsonc new file mode 100644 index 0000000000..1b27d02994 --- /dev/null +++ b/test/offline/config/jak3/config.jsonc @@ -0,0 +1,11 @@ +{ + "dgos": [ + "CGO/GAME.CGO" + ], + + "skip_compile_files": [], + + "skip_compile_functions": [], + + "skip_compile_states": {} +} diff --git a/test/offline/framework/execution.cpp b/test/offline/framework/execution.cpp index 8d302fbabc..0baf67201c 100644 --- a/test/offline/framework/execution.cpp +++ b/test/offline/framework/execution.cpp @@ -9,9 +9,10 @@ // TODO - i think these should be partitioned by game name instead of it being in the filename // (and the names not being consistent) -std::unordered_map game_name_to_all_types1 = { +std::unordered_map game_name_to_all_types = { {"jak1", "jak1/all-types.gc"}, - {"jak2", "jak2/all-types.gc"}}; + {"jak2", "jak2/all-types.gc"}, + {"jak3", "jak3/all-types.gc"}}; void disassemble(OfflineTestDecompiler& dc) { dc.db->process_link_data(*dc.config); @@ -105,13 +106,15 @@ OfflineTestCompileResult compile(OfflineTestDecompiler& dc, Compiler compiler(game_name_to_version(config.game_name)); compiler.run_front_end_on_file( - {"decompiler", "config", game_name_to_all_types1[config.game_name]}); + {"decompiler", "config", game_name_to_all_types[config.game_name]}); compiler.run_front_end_on_file( {"test", "decompiler", "reference", config.game_name, "decompiler-macros.gc"}); if (config.game_name == "jak2") { compiler.run_front_end_on_file({"goal_src", "jak2", "engine", "data", "art-elts.gc"}); } else if (config.game_name == "jak1") { compiler.run_front_end_on_file({"goal_src", "jak1", "engine", "data", "art-elts.gc"}); + } else if (config.game_name == "jak3") { + compiler.run_front_end_on_file({"goal_src", "jak3", "engine", "data", "art-elts.gc"}); } int total_lines = 0;