From 47e3d2de1988b39008d08d3f7307d13a1d6aa8a5 Mon Sep 17 00:00:00 2001 From: Jianling Zhong Date: Sun, 10 Nov 2024 16:26:17 -0800 Subject: [PATCH] Add native repeat object --- compiler+runtime/CMakeLists.txt | 1 + .../include/cpp/jank/runtime/erasure.hpp | 11 ++ .../include/cpp/jank/runtime/obj/repeat.hpp | 57 ++++++++ .../include/cpp/jank/runtime/object.hpp | 1 + .../src/cpp/jank/runtime/obj/repeat.cpp | 138 ++++++++++++++++++ compiler+runtime/src/jank/clojure/core.jank | 11 +- compiler+runtime/test/cpp/jank/read/parse.cpp | 12 +- 7 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp create mode 100644 compiler+runtime/src/cpp/jank/runtime/obj/repeat.cpp diff --git a/compiler+runtime/CMakeLists.txt b/compiler+runtime/CMakeLists.txt index 49285427..22608bf3 100644 --- a/compiler+runtime/CMakeLists.txt +++ b/compiler+runtime/CMakeLists.txt @@ -196,6 +196,7 @@ add_library( src/cpp/jank/runtime/obj/persistent_string_sequence.cpp src/cpp/jank/runtime/obj/cons.cpp src/cpp/jank/runtime/obj/range.cpp + src/cpp/jank/runtime/obj/repeat.cpp src/cpp/jank/runtime/obj/iterator.cpp src/cpp/jank/runtime/obj/lazy_sequence.cpp src/cpp/jank/runtime/obj/chunk_buffer.cpp diff --git a/compiler+runtime/include/cpp/jank/runtime/erasure.hpp b/compiler+runtime/include/cpp/jank/runtime/erasure.hpp index 3cababc3..83f61555 100644 --- a/compiler+runtime/include/cpp/jank/runtime/erasure.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/erasure.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -286,6 +287,11 @@ namespace jank::runtime return fn(expect_object(erased), std::forward(args)...); } break; + case object_type::repeat: + { + return fn(expect_object(erased), std::forward(args)...); + } + break; case object_type::native_array_sequence: { return fn(expect_object(erased), std::forward(args)...); @@ -522,6 +528,11 @@ namespace jank::runtime return fn(expect_object(erased), std::forward(args)...); } break; + case object_type::repeat: + { + return fn(expect_object(erased), std::forward(args)...); + } + break; case object_type::native_array_sequence: { return fn(expect_object(erased), std::forward(args)...); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp new file mode 100644 index 00000000..2b904fa2 --- /dev/null +++ b/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include + +namespace jank::runtime +{ + template <> + struct static_object : gc + { + static constexpr native_bool pointer_free{ false }; + using bounds_check_t = native_bool (*)(object_ptr); + + static_object() = default; + static_object(object_ptr value); + static_object(object_ptr count, object_ptr value); + + static object_ptr create(object_ptr value); + static object_ptr create(object_ptr count, object_ptr value); + + /* behavior::object_like */ + native_bool equal(object const &) const; + native_persistent_string to_string(); + void to_string(fmt::memory_buffer &buff); + native_persistent_string to_code_string(); + native_hash to_hash() const; + + /* behavior::seqable */ + native_box seq(); + native_box fresh_seq() const; + + /* behavior::sequenceable */ + object_ptr first() const; + native_box next() const; + + /* behavior::sequenceable_in_place */ + native_box next_in_place(); + + /* behavior::conjable */ + obj::cons_ptr conj(object_ptr head) const; + + /* behavior::metadatable */ + native_box with_meta(object_ptr m) const; + + object base{ object_type::repeat }; + object_ptr value{}; + native_integer count_int; + object_ptr count{}; + option meta{}; + bounds_check_t bounds_check{}; + }; + + namespace obj + { + using repeat = static_object; + using repeat_ptr = native_box; + } +} diff --git a/compiler+runtime/include/cpp/jank/runtime/object.hpp b/compiler+runtime/include/cpp/jank/runtime/object.hpp index ba66e84b..56968d61 100644 --- a/compiler+runtime/include/cpp/jank/runtime/object.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/object.hpp @@ -52,6 +52,7 @@ namespace jank::runtime cons, lazy_sequence, range, + repeat, iterator, native_array_sequence, native_vector_sequence, diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/repeat.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/repeat.cpp new file mode 100644 index 00000000..87e72c83 --- /dev/null +++ b/compiler+runtime/src/cpp/jank/runtime/obj/repeat.cpp @@ -0,0 +1,138 @@ +#include + +namespace jank::runtime +{ + static native_bool positive_count_check(object_ptr const count) + { + return lt(make_box(0), count); + } + + obj::repeat::static_object(object_ptr const value) + : value{ value } + { + } + + obj::repeat::static_object(object_ptr const count, object_ptr const value) + : value{ value } + , count{ count } + , bounds_check{ positive_count_check } + { + count_int + = visit_number_like([](auto const typed_count) -> native_bool { return typed_count->data; }, + count); + } + + object_ptr obj::repeat::create(object_ptr const value) + { + return make_box(value); + } + + object_ptr obj::repeat::create(object_ptr const count, object_ptr const value) + { + return make_box(count, value); + } + + obj::repeat_ptr obj::repeat::seq() + { + return this; + } + + obj::repeat_ptr obj::repeat::fresh_seq() const + { + return make_box(count, value); + } + + object_ptr obj::repeat::first() const + { + return value; + } + + obj::repeat_ptr obj::repeat::next() const + { + if(count_int < 0) + { + return this; + } + if(count_int < 1) + { + return nullptr; + } + return make_box(make_box(count_int - 1), value); + } + + obj::repeat_ptr obj::repeat::next_in_place() + { + if(count_int < 0) + { + return this; + } + if(count_int < 1) + { + return nullptr; + } + count = make_box(count_int - 1); + count_int -= 1; + return this; + } + + obj::cons_ptr obj::repeat::conj(object_ptr const head) const + { + return make_box(head, this); + } + + native_bool obj::repeat::equal(object const &o) const + { + return visit_object( + [this](auto const typed_o) { + using T = typename decltype(typed_o)::value_type; + + if constexpr(!behavior::seqable) + { + return false; + } + else + { + auto seq(typed_o->fresh_seq()); + /* TODO: This is common code; can it be shared? */ + for(auto it(fresh_seq()); it != nullptr; + it = runtime::next_in_place(it), seq = runtime::next_in_place(seq)) + { + if(seq == nullptr || !runtime::equal(it, seq->first())) + { + return false; + } + } + return true; + } + }, + &o); + } + + void obj::repeat::to_string(fmt::memory_buffer &buff) + { + runtime::to_string(seq(), buff); + } + + native_persistent_string obj::repeat::to_string() + { + return runtime::to_string(seq()); + } + + native_persistent_string obj::repeat::to_code_string() + { + return runtime::to_code_string(seq()); + } + + native_hash obj::repeat::to_hash() const + { + return hash::ordered(&base); + } + + obj::repeat_ptr obj::repeat::with_meta(object_ptr const m) const + { + auto const meta(behavior::detail::validate_meta(m)); + auto ret(fresh_seq()); + ret->meta = meta; + return ret; + } +} diff --git a/compiler+runtime/src/jank/clojure/core.jank b/compiler+runtime/src/jank/clojure/core.jank index ac78de54..f7847ba3 100644 --- a/compiler+runtime/src/jank/clojure/core.jank +++ b/compiler+runtime/src/jank/clojure/core.jank @@ -2236,13 +2236,12 @@ ; TODO: Custom cycle object (lazy-seq (concat coll (cycle coll)))) -; Returns a lazy (infinite!, or length n if supplied) sequence of xs. +; Returns a lazy (infinite!, or length n if supplied) sequence of val. (defn repeat - ; TODO: Custom repeat object - ([x] - (lazy-seq (cons x (repeat x)))) - ([n x] - (take n (repeat x)))) + ([val] + (native/raw "__value = obj::repeat::create(~{ val });")) + ([count val] + (native/raw "__value = obj::repeat::create(~{ count }, ~{ val });"))) ; Returns a vector of [(take n coll) (drop n coll)] (defn split-at [n coll] diff --git a/compiler+runtime/test/cpp/jank/read/parse.cpp b/compiler+runtime/test/cpp/jank/read/parse.cpp index ac7d675e..3cdfa9db 100644 --- a/compiler+runtime/test/cpp/jank/read/parse.cpp +++ b/compiler+runtime/test/cpp/jank/read/parse.cpp @@ -206,9 +206,9 @@ namespace jank::read::parse { "\\u1234", "\\u5678", "\\u90ab", "\\ucdef", "\\uABCD", "\\uEFa0" }) { auto const r(p.next()); - CHECK(equal(r.expect_ok().unwrap().ptr, - make_box( - parse_character_in_base(ch.substr(2), 16).expect_ok()))); + CHECK(equal( + r.expect_ok().unwrap().ptr, + make_box(parse_character_in_base(ch.substr(2), 16).expect_ok()))); auto const len(ch.size()); CHECK(r.expect_ok().unwrap().start @@ -256,9 +256,9 @@ namespace jank::read::parse for(native_persistent_string const &ch : { "\\o012", "\\o345", "\\o670" }) { auto const r(p.next()); - CHECK(equal(r.expect_ok().unwrap().ptr, - make_box( - parse_character_in_base(ch.substr(2), 8).expect_ok()))); + CHECK(equal( + r.expect_ok().unwrap().ptr, + make_box(parse_character_in_base(ch.substr(2), 8).expect_ok()))); auto const len(ch.size()); CHECK(r.expect_ok().unwrap().start