diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a8a27..14c5c57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,3 +91,6 @@ set_property(TEST unresolved_field.frank PROPERTY WILL_FAIL true) set_property(TEST unresolved_global.frank PROPERTY WILL_FAIL true) set_property(TEST unresolved_name.frank PROPERTY WILL_FAIL true) set_property(TEST func_no_return.frank PROPERTY WILL_FAIL true) +set_property(TEST assert_lrc_bad_1.frank PROPERTY WILL_FAIL true) +set_property(TEST assert_lrc_bad_2.frank PROPERTY WILL_FAIL true) +set_property(TEST assert_lrc_bad_3.frank PROPERTY WILL_FAIL true) diff --git a/src/rt/core/builtin.cc b/src/rt/core/builtin.cc index fb28da2..fc7fb7f 100644 --- a/src/rt/core/builtin.cc +++ b/src/rt/core/builtin.cc @@ -390,11 +390,91 @@ namespace rt::core }); } + void assert_rc__function_impl( + verona::interpreter::FrameObj* frame, size_t args, bool assert_lrc) + { + std::string option; + if (assert_lrc) + { + option = "lrc"; + } + else + { + option = "sbrc"; + } + + + if (args != 2) + { + std::stringstream ss; + ss << "assert_" << option << " expected 2 arguments"; + ui::error(ss.str()); + } + + auto count_str = frame->stack_pop("count_str"); + auto bridge = frame->stack_pop("bridge"); + // Make sure we're comparing the correct LRC value + rt::remove_reference(frame->object(), bridge); + if (count_str->get_prototype() != stringPrototypeObject()) + { + ui::error("given count is not a string", count_str); + } + auto region = objects::get_region(bridge); + if (region->bridge != bridge) + { + std::stringstream ss; + ss << bridge << " is not the bridge object of the region"; + ui::error(ss.str(), bridge); + } + // Remove string object whitespace + auto s = count_str->get_name(); + if (s[0] == '\"') + { + s.erase(0, 1); + s.erase(s.size() - 1); + } + auto count = std::stoi(s); + size_t actual; + if (assert_lrc) + { + actual = rt::objects::get_region(bridge)->local_reference_count; + } + else + { + actual = rt::objects::get_region(bridge)->sub_region_reference_count; + } + if (actual != count) + { + std::stringstream ss; + ss << "count: " << count << " did not match " << option << ": " << actual; + auto msg = ss.str(); + ui::error(msg, bridge); + } + + rt::remove_reference(frame->object(), count_str); + }; + + void test_builtins() + { + // Onus is on caller to provide a string object representing an actual integer + // Fixme: + // Refactor once integers are implemented + add_builtin("assert_lrc", [](auto frame, auto args) { + assert_rc__function_impl(frame, args, true); + return std::nullopt; + }); + add_builtin("assert_sbrc", [](auto frame, auto args) { + assert_rc__function_impl(frame, args, false); + return std::nullopt; + }); + } + void init_builtins(ui::UI* ui) { mermaid_builtins(ui); ctor_builtins(); action_builtins(); pragma_builtins(); + test_builtins(); } } diff --git a/tests/builtin_test/assert_lrc_1.frank b/tests/builtin_test/assert_lrc_1.frank new file mode 100644 index 0000000..97b45f8 --- /dev/null +++ b/tests/builtin_test/assert_lrc_1.frank @@ -0,0 +1,11 @@ +# Feels incorrect to utilize frank-tests for builtins +# that are meant to be utilized for frank-tests... +r1 = Region() +# Give r1 a LRC of 2 +a = {} +r1.a = a +# Using string object +expected = "2" +assert_lrc(r1, expected) +# Using string directly +assert_lrc(r1, "2") \ No newline at end of file diff --git a/tests/builtin_test/assert_lrc_bad_1.frank b/tests/builtin_test/assert_lrc_bad_1.frank new file mode 100644 index 0000000..a822e81 --- /dev/null +++ b/tests/builtin_test/assert_lrc_bad_1.frank @@ -0,0 +1,3 @@ +# Not a bridge +a = {} +assert_lrc(a, "2") \ No newline at end of file diff --git a/tests/builtin_test/assert_lrc_bad_2.frank b/tests/builtin_test/assert_lrc_bad_2.frank new file mode 100644 index 0000000..fa163a4 --- /dev/null +++ b/tests/builtin_test/assert_lrc_bad_2.frank @@ -0,0 +1,3 @@ +# Not a string +a = {} +assert_lrc(a, a) \ No newline at end of file diff --git a/tests/builtin_test/assert_lrc_bad_3.frank b/tests/builtin_test/assert_lrc_bad_3.frank new file mode 100644 index 0000000..0ec49f2 --- /dev/null +++ b/tests/builtin_test/assert_lrc_bad_3.frank @@ -0,0 +1,4 @@ +r1 = Region() +expected = "2" +# LRC is only 1 +assert_lrc(r1, expected) \ No newline at end of file diff --git a/tests/regions/merge5.frank b/tests/regions/merge5.frank new file mode 100644 index 0000000..d6c29de --- /dev/null +++ b/tests/regions/merge5.frank @@ -0,0 +1,15 @@ + +r1 = Region() +r2 = Region() +r1.r2 = r2 + +assert_sbrc(r1, "1") +r2 = None +assert_sbrc(r1, "0") +assert_lrc(r1.r2, "0") + +# Edge case where r2 does not contribute to sbrc of r1 +# Assure that lrc is unchanged +assert_lrc(r1, "1") +merge(r1.r2, r1) +assert_lrc(r1, "1") \ No newline at end of file