diff --git a/.clang-tidy b/.clang-tidy index 4838578fd..0da0af222 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -47,6 +47,8 @@ misc-definitions-in-headers,\ -bugprone-macro-parentheses,\ -bugprone-throwing-static-initialization,\ -readability-redundant-member-init,\ +-readability-redundant-typename,\ +-readability-redundant-casting,\ -readability-implicit-bool-conversion,\ -readability-magic-numbers,\ -readability-identifier-length,\ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e87c092ac..d282052a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -97,10 +97,11 @@ jobs: analyze: on ## Debug + sanitization - - name: Ubuntu - address sanitizer - os: ubuntu-24.04 - build_type: Debug - sanitize: address + # TODO: Fix this. GC issue: https://github.com/bdwgc/bdwgc/issues/772 + #- name: Ubuntu - address sanitizer + # os: ubuntu-24.04 + # build_type: Debug + # sanitize: address - name: Ubuntu - undefined behavior sanitizer os: ubuntu-24.04 @@ -203,6 +204,12 @@ jobs: path: | ${{ github.workspace }}/compiler+runtime/.ctcache key: ctcache-${{ env.JANK_MATRIX_ID }}-${{ github.ref_name }} + - uses: thejerrybao/setup-swap-space@466d59798fb9263b9c2331c83cf71f9b7bfd0c78 + if: runner.os == 'Linux' + with: + swap-space-path: /swapfile + swap-size-gb: 8 + remove-existing-swap-files: true - name: Build and test jank id: jank-build-step run: | @@ -272,26 +279,37 @@ jobs: run: | scp -i ~/.ssh/jank_id_ed25519 -o StrictHostKeyChecking=no ~/*.tar.gz root@cache.jank-lang.org:/var/www/cache.jank-lang.org/html/ - build-nix: - name: "Nix - release" - runs-on: ubuntu-latest - steps: - - name: "Set up nix" - uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - - name: "Set up cachix" - uses: cachix/cachix-action@v16 - with: - name: jank-lang - # If you chose API tokens for write access OR if you have a private cache - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - # Only push to cache on main branch, not PRs - skipPush: "${{ github.ref != 'refs/heads/main' }}" - - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - name: "Build jank" - run: nix build .?submodules=1 -L - - name: "Check health" - run: nix run .?submodules=1 check-health + # TODO: Fix Nix in CI! + # We're currently running out of memory in CI, due to Clang's memory usage for + # JIT compiled C++ code. Nix, unsurprisingly, uses more RAM than others, so it's + # blocked while others are merely hindered. We should be able to fix this by + # optimizing Clang's memory usage for JIT compiled code. See this gist for + # much more details: https://gist.github.com/jeaye/9adaaa56aee50d5912207907a48d1006 + # + # It's also possible that we can just use IR gen for Nix. That would require + # some additional CMake support, but is definitely doable. For the alpha, since + # we don't have a finished Nix package anyway, I'm not too concerned about this. + # + #build-nix: + # name: "Nix - release" + # runs-on: ubuntu-latest + # steps: + # - name: "Set up nix" + # uses: cachix/install-nix-action@v31 + # with: + # nix_path: nixpkgs=channel:nixos-unstable + # - name: "Set up cachix" + # uses: cachix/cachix-action@v16 + # with: + # name: jank-lang + # # If you chose API tokens for write access OR if you have a private cache + # authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + # # Only push to cache on main branch, not PRs + # skipPush: "${{ github.ref != 'refs/heads/main' }}" + # - uses: actions/checkout@v4 + # with: + # submodules: 'recursive' + # - name: "Build jank" + # run: nix build .?submodules=1 -L + # - name: "Check health" + # run: nix run .?submodules=1 check-health diff --git a/.gitignore b/.gitignore index 66bce157b..454712591 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ a.out .jank-repl-history .envrc .direnv -/notes # Vim files /.ycm_extra_conf.py* diff --git a/.gitmodules b/.gitmodules index f4d195697..087e2f87d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,9 @@ [submodule "compiler+runtime/third-party/folly"] path = compiler+runtime/third-party/folly url = https://github.com/jank-lang/folly.git -[submodule "compiler+runtime/third-party/bpptree"] - path = compiler+runtime/third-party/bpptree - url = https://github.com/jank-lang/BppTree.git [submodule "compiler+runtime/third-party/immer"] path = compiler+runtime/third-party/immer url = https://github.com/jank-lang/immer.git -[submodule "compiler+runtime/third-party/cli11"] - path = compiler+runtime/third-party/cli11 - url = https://github.com/jank-lang/CLI11.git [submodule "compiler+runtime/third-party/boost-preprocessor"] path = compiler+runtime/third-party/boost-preprocessor url = https://github.com/jank-lang/boost-preprocessor.git diff --git a/compiler+runtime/CMakeLists.txt b/compiler+runtime/CMakeLists.txt index d07be2b0d..1f7959436 100644 --- a/compiler+runtime/CMakeLists.txt +++ b/compiler+runtime/CMakeLists.txt @@ -42,12 +42,14 @@ option(jank_coverage "Enable code coverage measurement" OFF) option(jank_analyze "Enable static analysis" OFF) option(jank_test "Enable jank's test suite" OFF) option(jank_unity_build "Optimize translation unit compilation for the number of cores" OFF) +option(jank_debug_gc "Enable GC debug assertions" OFF) +option(jank_profile_gc "Enable GC profiling (via massif or heaptrack)" OFF) +option(jank_force_phase_2 "Force the linking of core libs into the jank binary" OFF) set(jank_sanitize "none" CACHE STRING "The type of Clang sanitization to use (or none)") set(jank_resource_dir "../lib/jank/${CMAKE_PROJECT_VERSION}" CACHE STRING "Where jank's runtime files are installed. Relative paths are based on the runtime jank binary path") -set(jank_clojure_core_o "${CMAKE_BINARY_DIR}/core-libs/clojure/core.o") find_package(Git REQUIRED) execute_process( @@ -81,7 +83,7 @@ set( jank_aot_compiler_flags -Wall -Wextra -Wpedantic -Wfloat-equal -Wuninitialized -Wswitch-enum -Wnon-virtual-dtor - -Wold-style-cast -Wno-gnu-case-range -Wno-c99-designator + -Wold-style-cast -Wno-gnu-case-range -Wno-c99-designator -Wno-c2y-extensions -Wno-gnu-conditional-omitted-operand -Wno-implicit-fallthrough -Wno-covered-switch-default @@ -99,6 +101,8 @@ set( set( jank_common_compiler_flags -std=gnu++20 + # https://groups.google.com/g/llvm-dev/c/W-OweiAjDcU?pli=1 + -femulated-tls -DIMMER_HAS_LIBGC=1 -DIMMER_TAGGED_NODE=0 -DHAVE_CXX14=1 -DCPPINTEROP_USE_REPL -DFOLLY_HAVE_JEMALLOC=0 -DFOLLY_HAVE_TCMALLOC=0 -DFOLLY_ASSUME_NO_JEMALLOC=1 -DFOLLY_ASSUME_NO_TCMALLOC=1 @@ -132,8 +136,18 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") list(APPEND jank_common_compiler_flags -Og -g -DNDEBUG) endif() -if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") +if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR jank_force_phase_2) set(jank_enable_phase_2 ON) +else() + set(jank_enable_phase_2 OFF) +endif() + +if(jank_enable_phase_2) + set(jank_clojure_core_output "${CMAKE_BINARY_DIR}/core-libs/clojure/core.cpp") + set(jank_clojure_core_output_artifact "${CMAKE_BINARY_DIR}/CMakeFiles/jank_exe_phase_2.dir/core-libs/clojure/core.cpp.o") +else() + set(jank_clojure_core_output "${CMAKE_BINARY_DIR}/core-libs/clojure/core.o") + set(jank_clojure_core_output_artifact "${jank_clojure_core_output}") endif() if(jank_test) @@ -349,6 +363,17 @@ set(jank_lib_standalone_deps folly_lib clangCppInterOp ) + +# jank compiles in two phases. The first phase builds the compiler+runtime into a binary +# called jank-phase-1. We then we this compiler to build the core libs (like clojure.core) +# into cpp files. We then compile those and link them into a new binary which is just +# called jank. This bakes in the core libraries so they're very fast to load, but of +# course it means that updating a core library means updating the whole jank binary. +# +# For debug builds, we don't bother building the second phase and we just create a symlink +# called jank which points at jank-phase-1. This makes iteration a little faster, at the +# cost of jank's startup being a little slower, since it's loading the core libs via their +# object files, rather than having them baked in. add_custom_command( DEPENDS ${jank_lib_standalone_deps} OUTPUT ${CMAKE_BINARY_DIR}/libjank-standalone-phase-1.a @@ -363,8 +388,7 @@ add_custom_target( ) add_custom_command( - DEPENDS ${jank_lib_standalone_deps} - jank_core_libraries + DEPENDS ${jank_lib_standalone_deps} jank_exe_phase_2 OUTPUT ${CMAKE_BINARY_DIR}/libjank-standalone.a COMMAND_EXPAND_LISTS VERBATIM @@ -569,10 +593,8 @@ target_include_directories( PUBLIC "$" "$" - "$" "$" "$" - "$" "$" "$" "$" @@ -753,11 +775,16 @@ if(jank_enable_phase_2) add_executable( jank_exe_phase_2 "$" + ${jank_clojure_core_output} ) add_executable(jank::exe ALIAS jank_exe_phase_2) - set_property(TARGET jank_exe_phase_2 PROPERTY OUTPUT_NAME jank) + # Our generated code is not as precisely written as hand-written C++, so we ignore various + # warnings and skip linting. + set_source_files_properties(${jank_clojure_core_output} PROPERTIES COMPILE_FLAGS "-w -Wno-c++11-narrowing") + set_source_files_properties(${jank_clojure_core_output} PROPERTIES SKIP_LINTING ON) + # Symbol exporting for JIT. set_target_properties(jank_exe_phase_2 PROPERTIES ENABLE_EXPORTS 1) @@ -770,17 +797,16 @@ if(jank_enable_phase_2) target_link_libraries( jank_exe_phase_2 PUBLIC "$" - ${jank_clojure_core_o} ) jank_hook_llvm(jank_exe_phase_2) - add_dependencies(jank_exe_phase_2 jank_lib_standalone_phase_2 jank_core_libraries) + add_dependencies(jank_exe_phase_2 jank_core_libraries) #set_target_properties(jank_exe_phase_2 PROPERTIES LINK_FLAGS_RELEASE "-s") else() add_custom_command( - DEPENDS ${CMAKE_BINARY_DIR}/jank-phase-1 ${jank_clojure_core_o} ${jank_incremental_pch_flag} + DEPENDS ${CMAKE_BINARY_DIR}/jank-phase-1 ${jank_clojure_core_output} ${jank_incremental_pch_flag} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT ${CMAKE_BINARY_DIR}/jank COMMAND ln -sf jank-phase-1 jank @@ -825,6 +851,11 @@ if(jank_test) add_executable(jank::test_exe ALIAS jank_test_exe) add_dependencies(jank_test_exe jank_exe_phase_1 jank_core_libraries) + if(jank_enable_phase_2) + target_sources(jank_test_exe PUBLIC ${jank_clojure_core_output}) + target_compile_options(jank_test_exe PUBLIC -DJANK_PHASE_2) + endif() + set_property(TARGET jank_test_exe PROPERTY OUTPUT_NAME jank-test) target_compile_features(jank_test_exe PRIVATE ${jank_cxx_standard}) @@ -904,8 +935,8 @@ set(jank_core_libraries_flag "${CMAKE_BINARY_DIR}/classes/core-libraries") add_custom_command( DEPENDS ${CMAKE_BINARY_DIR}/jank-phase-1 ${CMAKE_SOURCE_DIR}/src/jank/clojure/core.jank ${jank_incremental_pch_flag} OUTPUT ${jank_core_libraries_flag} - BYPRODUCTS ${jank_clojure_core_o} - COMMAND ${CMAKE_BINARY_DIR}/jank-phase-1 compile-module -o ${jank_clojure_core_o} clojure.core + BYPRODUCTS ${jank_clojure_core_output} + COMMAND ${CMAKE_BINARY_DIR}/jank-phase-1 -O3 compile-module -o ${jank_clojure_core_output} clojure.core COMMAND touch ${jank_core_libraries_flag} ) add_custom_target( diff --git a/compiler+runtime/bin/ar-merge b/compiler+runtime/bin/ar-merge index c25a434f1..335e4180f 100755 --- a/compiler+runtime/bin/ar-merge +++ b/compiler+runtime/bin/ar-merge @@ -32,7 +32,7 @@ case "${command}" in # This follows merge, but also bundles in the Clojure core library object files, following # jank's phase 2 building. merge-phase-2) - object_files="$(cat "${cache_dir}"/*) ${cmake_binary_dir}/core-libs/clojure/core.o" + object_files="$(cat "${cache_dir}"/*) @jank_clojure_core_output_artifact@" merge_output="${cmake_binary_dir}/libjank-standalone.a" rm -f "${merge_output}" # shellcheck disable=SC2086 diff --git a/compiler+runtime/bin/build-clang b/compiler+runtime/bin/build-clang index b2cb2054c..c583c763d 100755 --- a/compiler+runtime/bin/build-clang +++ b/compiler+runtime/bin/build-clang @@ -52,6 +52,7 @@ srcdir="${PWD}" llvm_url="https://github.com/jank-lang/llvm-project.git" llvm_version=22 llvm_branch="jank-snapshot/llvm${llvm_version}" +# 4e5928689f23..a8f19259e708 jank-snapshot/llvm22 -> jank-snapshot/llvm22 function prepare() { diff --git a/compiler+runtime/bin/clean b/compiler+runtime/bin/clean index d2d1022e0..1b1b0831b 100755 --- a/compiler+runtime/bin/clean +++ b/compiler+runtime/bin/clean @@ -13,4 +13,5 @@ pushd "${here}/../build" make clean fi rm -rf ar-cache + rm -rf core-libs popd diff --git a/compiler+runtime/bin/jank/compiler+runtime/build+test.clj b/compiler+runtime/bin/jank/compiler+runtime/build+test.clj index 4c0de5131..6c4ced121 100755 --- a/compiler+runtime/bin/jank/compiler+runtime/build+test.clj +++ b/compiler+runtime/bin/jank/compiler+runtime/build+test.clj @@ -31,7 +31,10 @@ (str "-DCMAKE_BUILD_TYPE=" build-type) (str "-Djank_analyze=" analyze) (str "-Djank_sanitize=" sanitize) - (str "-Djank_coverage=" coverage)] + (str "-Djank_coverage=" coverage) + ; We force phase 2 building to use less memory in CI by + ; compiling to cpp files instead of object files. + "-Djank_force_phase_2=on"] configure-flags (cond-> configure-flags (not= "on" analyze) (conj "-DCMAKE_C_COMPILER_LAUNCHER=ccache" @@ -55,7 +58,16 @@ (util/with-elapsed-time duration (util/quiet-shell {:dir compiler+runtime-dir :extra-env exports} - "./bin/compile -v") + "./bin/clean") + (util/log-info-with-time duration "Cleaned")) + + (util/with-elapsed-time duration + (util/quiet-shell {:dir compiler+runtime-dir + :extra-env exports} + (str "./bin/compile -v" + ; This uses more memory in CI, so we limit parallelism. + (when (= "Release" build-type) + " -j1"))) (util/log-info-with-time duration "Compiled")) (util/quiet-shell {:dir compiler+runtime-dir diff --git a/compiler+runtime/cmake/dependency/bdwgc.cmake b/compiler+runtime/cmake/dependency/bdwgc.cmake index fff5b9cba..c814c07e7 100644 --- a/compiler+runtime/cmake/dependency/bdwgc.cmake +++ b/compiler+runtime/cmake/dependency/bdwgc.cmake @@ -4,18 +4,50 @@ set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS}) set(CMAKE_CXX_CLANG_TIDY_OLD ${CMAKE_CXX_CLANG_TIDY}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") - set(BUILD_SHARED_LIBS OFF) + set(CMAKE_CXX_CLANG_TIDY "") + set(GC_BUILD_SHARED_LIBS OFF) + + # Malloc redirection is causing crashes on macOS. However, without it, we get + # premature collections. Because of this, collection is disabled on macOS entirely. + # + # https://github.com/bdwgc/bdwgc/issues/829 + if(NOT APPLE) + set(enable_redirect_malloc ON CACHE BOOL "Redirect malloc and friends to collector routines") + set(enable_uncollectable_redirection ON CACHE BOOL "Redirect to uncollectible malloc instead of garbage-collected one") + endif() + set(enable_cplusplus ON CACHE BOOL "Enable C++") set(build_cord OFF CACHE BOOL "Build cord") set(enable_docs OFF CACHE BOOL "Enable docs") + set(enable_threads ON CACHE BOOL "Enable multi-threading support") set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set") set(enable_throw_bad_alloc_library ON CACHE BOOL "Enable C++ gctba library build") + set(enable_gc_debug OFF CACHE BOOL "Support for pointer back-tracing") + + if(jank_profile_gc) + set(enable_valgrind_tracking ON CACHE BOOL "Support tracking GC_malloc and friends for heap profiling tools") + endif() + + if(jank_debug_gc) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGC_ASSERTIONS") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGC_ASSERTIONS") + set(enable_gc_debug ON CACHE BOOL "Support for pointer back-tracing") + endif() + add_subdirectory(third-party/bdwgc EXCLUDE_FROM_ALL) + unset(GC_BUILD_SHARED_LIBS) + unset(enable_redirect_malloc) + unset(enable_uncollectable_redirection) unset(enable_cplusplus) unset(build_cord) unset(enable_docs) + unset(enable_threads) + unset(enable_large_config) + unset(enable_throw_bad_alloc_library) + unset(enable_valgrind_tracking) + unset(enable_gc_debug) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_OLD}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD}) diff --git a/compiler+runtime/cmake/install.cmake b/compiler+runtime/cmake/install.cmake index 9c7f7553c..d13504262 100644 --- a/compiler+runtime/cmake/install.cmake +++ b/compiler+runtime/cmake/install.cmake @@ -61,33 +61,17 @@ jank_glob_install_without_prefix( PATTERN "${CMAKE_SOURCE_DIR}/third-party/folly/folly/*.h" ) -jank_glob_install_without_prefix( - INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/bpptree/" - PATTERN "${CMAKE_SOURCE_DIR}/third-party/bpptree/include/*" -) - jank_glob_install_without_prefix( INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/immer/" OUTPUT_PREFIX "include/" PATTERN "${CMAKE_SOURCE_DIR}/third-party/immer/immer/*" ) -jank_glob_install_without_prefix( - INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/cli11/" - PATTERN "${CMAKE_SOURCE_DIR}/third-party/cli11/include/*" -) - jank_glob_install_without_prefix( INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/ftxui/" PATTERN "${CMAKE_SOURCE_DIR}/third-party/ftxui/include/*" ) -jank_glob_install_without_prefix( - INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/libzippp/src/" - OUTPUT_PREFIX "include/" - PATTERN "${CMAKE_SOURCE_DIR}/third-party/libzippp/src/*" -) - jank_glob_install_without_prefix( INPUT_PREFIX "${CMAKE_SOURCE_DIR}/third-party/cpptrace/" PATTERN "${CMAKE_SOURCE_DIR}/third-party/cpptrace/include/*" diff --git a/compiler+runtime/cmake/summary.cmake b/compiler+runtime/cmake/summary.cmake index d5000b845..d24e430d5 100644 --- a/compiler+runtime/cmake/summary.cmake +++ b/compiler+runtime/cmake/summary.cmake @@ -3,15 +3,18 @@ function(jank_message msg) endfunction() jank_message("┌─ jank options ─────────────────────") -jank_message("│ jank build type : ${CMAKE_BUILD_TYPE}") -jank_message("│ jank version : ${jank_version}") -jank_message("│ jank tests : ${jank_test}") -jank_message("│ jank coverage : ${jank_coverage}") -jank_message("│ jank analyze : ${jank_analyze}") -jank_message("│ jank sanitize : ${jank_sanitize}") -jank_message("│ jank unity build : ${jank_unity_build}") -jank_message("│ jank resource dir : ${jank_resource_dir}") -jank_message("│ clang version : ${LLVM_PACKAGE_VERSION}") -jank_message("│ clang prefix : ${CLANG_INSTALL_PREFIX}") -jank_message("│ clang resource dir : ${clang_resource_dir}") +jank_message("│ jank build type : ${CMAKE_BUILD_TYPE}") +jank_message("│ jank version : ${jank_version}") +jank_message("│ jank phase 2 : ${jank_enable_phase_2}") +jank_message("│ jank tests : ${jank_test}") +jank_message("│ jank coverage : ${jank_coverage}") +jank_message("│ jank analyze : ${jank_analyze}") +jank_message("│ jank sanitize : ${jank_sanitize}") +jank_message("│ jank unity build : ${jank_unity_build}") +jank_message("│ jank resource dir : ${jank_resource_dir}") +jank_message("│ jank debug gc : ${jank_debug_gc}") +jank_message("│ jank profile gc : ${jank_profile_gc}") +jank_message("│ clang version : ${LLVM_PACKAGE_VERSION}") +jank_message("│ clang prefix : ${CLANG_INSTALL_PREFIX}") +jank_message("│ clang resource dir : ${clang_resource_dir}") jank_message("└─────────────────────────────────────") diff --git a/compiler+runtime/doc/install.md b/compiler+runtime/doc/install.md index adbd5b46e..b26c3a439 100644 --- a/compiler+runtime/doc/install.md +++ b/compiler+runtime/doc/install.md @@ -1,6 +1,6 @@ # Installing jank If you're on any of the below systems, you can install jank using your system's -package manager. +package manager. If not, you can still [build jank yourself](https://github.com/jank-lang/jank/blob/main/compiler+runtime/doc/build.md). ## Homebrew (macOS or Linux) ### Install diff --git a/compiler+runtime/include/cpp/clojure/core_native.hpp b/compiler+runtime/include/cpp/clojure/core_native.hpp index df25efae8..bd9b23a46 100644 --- a/compiler+runtime/include/cpp/clojure/core_native.hpp +++ b/compiler+runtime/include/cpp/clojure/core_native.hpp @@ -3,62 +3,67 @@ #include #include -extern "C" jank_object_ref jank_load_clojure_core_native(); +extern "C" void jank_load_clojure_core_native(); namespace clojure::core_native { using namespace jank::runtime; - object_ref is_var(object_ref o); - object_ref var_get(object_ref o); - object_ref alter_var_root(object_ref o, object_ref fn, object_ref args); - object_ref is_var_bound(object_ref o); - object_ref is_var_thread_bound(object_ref o); - object_ref var_bind_root(object_ref v, object_ref o); - object_ref var_get_root(object_ref o); - object_ref intern_var(object_ref sym); + object_ref is_var(object_ref const o); + object_ref var_get(object_ref const o); + object_ref alter_var_root(object_ref const o, object_ref const fn, object_ref const args); + object_ref is_var_bound(object_ref const o); + object_ref is_var_thread_bound(object_ref const o); + object_ref var_bind_root(object_ref const v, object_ref const o); + object_ref var_get_root(object_ref const o); + object_ref intern_var(object_ref const sym); - object_ref ns_unalias(object_ref current_ns, object_ref alias); - object_ref ns_unmap(object_ref current_ns, object_ref sym); - object_ref in_ns(object_ref sym); - object_ref intern_ns(object_ref sym); - object_ref find_ns(object_ref sym); - object_ref find_var(object_ref sym); - object_ref remove_ns(object_ref sym); - object_ref is_ns(object_ref ns_or_sym); - object_ref ns_name(object_ref ns); - object_ref ns_map(object_ref ns); - object_ref var_ns(object_ref v); - object_ref ns_resolve(object_ref ns, object_ref sym); - object_ref alias(object_ref current_ns, object_ref remote_ns, object_ref alias); - object_ref refer(object_ref current_ns, object_ref sym, object_ref var); - object_ref load_module(object_ref path); - object_ref compile(object_ref path); + object_ref ns_unalias(object_ref const current_ns, object_ref const alias); + object_ref ns_unmap(object_ref const current_ns, object_ref const sym); + object_ref in_ns(object_ref const sym); + object_ref intern_ns(object_ref const sym); + object_ref find_ns(object_ref const sym); + object_ref find_var(object_ref const sym); + object_ref remove_ns(object_ref const sym); + object_ref is_ns(object_ref const ns_or_sym); + object_ref ns_name(object_ref const ns); + object_ref ns_map(object_ref const ns); + object_ref var_ns(object_ref const v); + object_ref ns_resolve(object_ref const ns, object_ref const sym); + object_ref alias(object_ref const current_ns, object_ref const remote_ns, object_ref const alias); + object_ref refer(object_ref const current_ns, object_ref const sym, object_ref const var); + object_ref load_module(object_ref const path); + object_ref compile(object_ref const path); - object_ref not_(object_ref o); + object_ref not_(object_ref const o); - object_ref is_fn(object_ref o); - object_ref is_multi_fn(object_ref o); + object_ref is_fn(object_ref const o); + object_ref is_multi_fn(object_ref const o); + object_ref multi_fn(object_ref const name, + object_ref const dispatch_fn, + object_ref const default_, + object_ref const hierarchy); object_ref - multi_fn(object_ref name, object_ref dispatch_fn, object_ref default_, object_ref hierarchy); - object_ref defmethod(object_ref multifn, object_ref dispatch_val, object_ref fn); - object_ref remove_all_methods(object_ref multifn); - object_ref remove_method(object_ref multifn, object_ref dispatch_val); - object_ref prefer_method(object_ref multifn, object_ref dispatch_val_x, object_ref ispatch_val_y); - object_ref methods(object_ref multifn); - object_ref get_method(object_ref multifn, object_ref dispatch_val); - object_ref prefers(object_ref multifn); + defmethod(object_ref const multifn, object_ref const dispatch_val, object_ref const fn); + object_ref remove_all_methods(object_ref const multifn); + object_ref remove_method(object_ref const multifn, object_ref const dispatch_val); + object_ref prefer_method(object_ref const multifn, + object_ref const dispatch_val_x, + object_ref const ispatch_val_y); + object_ref methods(object_ref const multifn); + object_ref get_method(object_ref const multifn, object_ref const dispatch_val); + object_ref prefers(object_ref const multifn); - object_ref sleep(object_ref ms); + object_ref sleep(object_ref const ms); object_ref current_time(); - object_ref eval(object_ref expr); - object_ref read_string(object_ref /* opts */, object_ref str); + object_ref eval(object_ref const expr); + object_ref read_string(object_ref const /* opts */, object_ref const str); - object_ref lazy_seq(object_ref o); + object_ref lazy_seq(object_ref const o); - object_ref hash_unordered(object_ref coll); + object_ref hash_unordered(object_ref const coll); object_ref jank_version(); - object_ref delay(object_ref fn); + object_ref delay(object_ref const fn); } diff --git a/compiler+runtime/include/cpp/clojure/string_native.hpp b/compiler+runtime/include/cpp/clojure/string_native.hpp index 3554516ab..4412d6c5e 100644 --- a/compiler+runtime/include/cpp/clojure/string_native.hpp +++ b/compiler+runtime/include/cpp/clojure/string_native.hpp @@ -7,23 +7,24 @@ namespace clojure::string_native using namespace jank; using namespace jank::runtime; - object_ref blank(object_ref s); - object_ref reverse(object_ref s); - object_ref lower_case(object_ref s); - object_ref starts_with(object_ref s, object_ref substr); - object_ref ends_with(object_ref s, object_ref substr); - object_ref includes(object_ref s, object_ref substr); - object_ref upper_case(object_ref s); - object_ref replace_first(object_ref s, object_ref match, object_ref replacement); + object_ref blank(object_ref const s); + object_ref reverse(object_ref const s); + object_ref lower_case(object_ref const s); + object_ref starts_with(object_ref const s, object_ref const substr); + object_ref ends_with(object_ref const s, object_ref const substr); + object_ref includes(object_ref const s, object_ref const substr); + object_ref upper_case(object_ref const s); + object_ref + replace_first(object_ref const s, object_ref const match, object_ref const replacement); - i64 index_of(object_ref s, object_ref value, object_ref from_index); - i64 last_index_of(object_ref s, object_ref value, object_ref from_index); + i64 index_of(object_ref const s, object_ref const value, object_ref const from_index); + i64 last_index_of(object_ref const s, object_ref const value, object_ref const from_index); - object_ref triml(object_ref s); - object_ref trimr(object_ref s); - object_ref trim(object_ref s); - object_ref trim_newline(object_ref s); + object_ref triml(object_ref const s); + object_ref trimr(object_ref const s); + object_ref trim(object_ref const s); + object_ref trim_newline(object_ref const s); - object_ref split(object_ref s, object_ref re); - object_ref split(object_ref s, object_ref re, object_ref limit); + object_ref split(object_ref const s, object_ref const re); + object_ref split(object_ref const s, object_ref const re, object_ref const limit); } diff --git a/compiler+runtime/include/cpp/jank/analyze/cpp_util.hpp b/compiler+runtime/include/cpp/jank/analyze/cpp_util.hpp index 8cd03e655..9d8ec82ac 100644 --- a/compiler+runtime/include/cpp/jank/analyze/cpp_util.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/cpp_util.hpp @@ -28,6 +28,7 @@ namespace jank::analyze::cpp_util native_vector> find_adl_scopes(native_vector> const &starters); jtl::immutable_string get_qualified_name(jtl::ptr scope); + jtl::immutable_string get_qualified_type_name(jtl::ptr type); void register_rtti(jtl::ptr type); jtl::ptr expression_type(expression_ref expr); diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/call.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/call.hpp index cea812555..00ba72d51 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/call.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/call.hpp @@ -20,7 +20,7 @@ namespace jank::analyze::expr bool needs_box, expression_ref source, native_vector &&arg_exprs, - runtime::obj::persistent_list_ref form); + runtime::obj::persistent_list_ref const form); runtime::object_ref to_runtime_data() const override; void walk(std::function)> const &f) override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/cpp_type.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/cpp_type.hpp index 1f6ab7d5b..714ca9585 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/cpp_type.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/cpp_type.hpp @@ -18,7 +18,7 @@ namespace jank::analyze::expr cpp_type(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref sym, + runtime::obj::symbol_ref const sym, jtl::ptr type); void propagate_position(expression_position const pos) override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/cpp_value.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/cpp_value.hpp index 176394709..4d0ac8825 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/cpp_value.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/cpp_value.hpp @@ -32,7 +32,7 @@ namespace jank::analyze::expr cpp_value(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref sym, + runtime::obj::symbol_ref const sym, jtl::ptr type, jtl::ptr scope, value_kind val_kind); diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp index c82b0ab6d..251428d1d 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp @@ -20,7 +20,7 @@ namespace jank::analyze::expr def(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref name, + runtime::obj::symbol_ref const name, jtl::option const &value); runtime::object_ref to_runtime_data() const override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/function.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/function.hpp index 9dbe3087b..890de0a14 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/function.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/function.hpp @@ -1,14 +1,9 @@ #pragma once +#include +#include #include -namespace jank::runtime::obj -{ - using symbol_ref = oref; - using persistent_hash_map_ref = oref; - using persistent_hash_map_ref = oref; -} - namespace jank::analyze { using local_binding_ptr = jtl::ptr; @@ -18,7 +13,7 @@ namespace jank::analyze::expr { using function_ref = jtl::ref; - struct function_context : gc + struct function_context { static constexpr bool pointer_free{ false }; @@ -27,7 +22,11 @@ namespace jank::analyze::expr jtl::immutable_string unique_name; usize param_count{}; bool is_variadic{}; - bool is_tail_recursive{}; + /* Is recur used within this function? */ + bool is_recur_recursive{}; + /* Is there any named recrusion within this function (tail or otherwise)? + * This counts any named recursion reference, not just calls. */ + bool is_named_recursive{}; /* TODO: is_pure */ }; @@ -62,7 +61,7 @@ namespace jank::analyze::expr jtl::immutable_string const &name, jtl::immutable_string const &unique_name, native_vector &&arities, - runtime::obj::persistent_hash_map_ref meta); + runtime::obj::persistent_hash_map_ref const meta); /* Aggregates all `frame->captures` from each arity so that we can know the overall * captures for all arities of this fn. This is necessary for codegen to IR, since we diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/if.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/if.hpp index a97780514..a8636d3c8 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/if.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/if.hpp @@ -25,6 +25,7 @@ namespace jank::analyze::expr /* TODO: Rename to have _expr suffixes. */ expression_ref condition; + /* The then/else exprs are expected to have the same type. We handle this during analysis. */ expression_ref then; jtl::option else_; }; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/local_reference.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/local_reference.hpp index 1fe5ee797..b88faa7ab 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/local_reference.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/local_reference.hpp @@ -1,12 +1,8 @@ #pragma once +#include #include -namespace jank::runtime::obj -{ - using symbol_ref = oref; -} - namespace jank::analyze { using local_binding_ptr = jtl::ptr; @@ -23,7 +19,7 @@ namespace jank::analyze::expr local_reference(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref name, + runtime::obj::symbol_ref const name, local_binding_ptr binding); runtime::object_ref to_runtime_data() const override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/named_recursion.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/named_recursion.hpp index 744f6118e..90db262ae 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/named_recursion.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/named_recursion.hpp @@ -19,7 +19,7 @@ namespace jank::analyze::expr local_frame_ptr frame, bool needs_box, recursion_reference &&recursion_ref, - runtime::obj::persistent_list_ref args, + runtime::obj::persistent_list_ref const args, native_vector &&arg_exprs); runtime::object_ref to_runtime_data() const override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/primitive_literal.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/primitive_literal.hpp index 0814976e4..b850730c6 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/primitive_literal.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/primitive_literal.hpp @@ -13,7 +13,7 @@ namespace jank::analyze::expr primitive_literal(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::object_ref data); + runtime::object_ref const data); runtime::object_ref to_runtime_data() const override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/recur.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/recur.hpp index af3d1e195..1e1056754 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/recur.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/recur.hpp @@ -24,7 +24,7 @@ namespace jank::analyze::expr recur(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::persistent_list_ref args, + runtime::obj::persistent_list_ref const args, native_vector &&arg_exprs, jtl::option const &loop_target); diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/var_deref.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/var_deref.hpp index 739d2b05e..ae3656ad3 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/var_deref.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/var_deref.hpp @@ -23,8 +23,8 @@ namespace jank::analyze::expr var_deref(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref qualified_name, - runtime::var_ref var); + runtime::obj::symbol_ref const qualified_name, + runtime::var_ref const var); runtime::object_ref to_runtime_data() const override; diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/var_ref.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/var_ref.hpp index 272b71803..4ffcc2dce 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/var_ref.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/var_ref.hpp @@ -21,11 +21,17 @@ namespace jank::analyze::expr var_ref(expression_position position, local_frame_ptr frame, bool needs_box, - runtime::obj::symbol_ref qualified_name, - runtime::var_ref var); + runtime::obj::symbol_ref const qualified_name, + runtime::var_ref const var); runtime::object_ref to_runtime_data() const override; + /* Holds the fully qualified name for the originally resolved var. + * It will be useful to know that the var ref happened through a + * referred var, for static analysis and error reporting. + * + * For all the other purposes, `var` member should be used that points + * to the actual value of the var.. */ runtime::obj::symbol_ref qualified_name{}; runtime::var_ref var{}; }; diff --git a/compiler+runtime/include/cpp/jank/analyze/expression.hpp b/compiler+runtime/include/cpp/jank/analyze/expression.hpp index 8934ee3de..2c313e4bb 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expression.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expression.hpp @@ -150,7 +150,7 @@ namespace jank::analyze } /* Common base class for every expression. */ - struct expression : gc + struct expression { static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/analyze/local_frame.hpp b/compiler+runtime/include/cpp/jank/analyze/local_frame.hpp index 9b389951d..c8b16607c 100644 --- a/compiler+runtime/include/cpp/jank/analyze/local_frame.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/local_frame.hpp @@ -8,6 +8,7 @@ namespace jank::runtime { struct context; + using var_ref = oref; namespace obj { @@ -29,25 +30,6 @@ namespace jank::analyze using function_context_ref = jtl::ref; } - struct lifted_var - { - jtl::immutable_string native_name{}; - runtime::obj::symbol_ref var_name{}; - - runtime::object_ref to_runtime_data() const; - }; - - /* TODO: Track constant usages to figure out if boxing is needed at all, - * rather than just doing both. */ - struct lifted_constant - { - jtl::immutable_string native_name{}; - jtl::option unboxed_native_name{}; - runtime::object_ref data{}; - - runtime::object_ref to_runtime_data() const; - }; - struct local_binding { runtime::obj::symbol_ref name{}; @@ -66,7 +48,7 @@ namespace jank::analyze using local_binding_ptr = jtl::ptr; - struct local_frame : gc + struct local_frame { enum class frame_type : u8 { @@ -122,27 +104,20 @@ namespace jank::analyze /* This is used to find both captures and regular locals, since it's * impossible to know which one a sym is without finding it. */ - jtl::option find_local_or_capture(runtime::obj::symbol_ref sym); + jtl::option find_local_or_capture(runtime::obj::symbol_ref const sym); static void register_captures(binding_find_result const &result); static void register_captures(jtl::ptr frame, named_recursion_find_result const &result); /* This can be used when you have a capture, but you want to trace it back to the * originating local. */ - jtl::option find_originating_local(runtime::obj::symbol_ref sym); + jtl::option find_originating_local(runtime::obj::symbol_ref const sym); - jtl::option find_named_recursion(runtime::obj::symbol_ref sym); + jtl::option + find_named_recursion(runtime::obj::symbol_ref const sym); static bool within_same_fn(jtl::ptr, jtl::ptr); - runtime::obj::symbol_ref lift_var(runtime::obj::symbol_ref const &); - jtl::option> - find_lifted_var(runtime::obj::symbol_ref const &) const; - - void lift_constant(runtime::object_ref); - jtl::option> - find_lifted_constant(runtime::object_ref) const; - static local_frame const &find_closest_fn_frame(local_frame const &frame); static local_frame &find_closest_fn_frame(local_frame &frame); @@ -152,12 +127,6 @@ namespace jank::analyze jtl::option> parent; native_unordered_map locals; native_unordered_map captures; - native_unordered_map lifted_vars; - native_unordered_map, - runtime::very_equal_to> - lifted_constants; /* This is only set if the frame type is fn. */ jtl::ptr fn_ctx; }; diff --git a/compiler+runtime/include/cpp/jank/analyze/processor.hpp b/compiler+runtime/include/cpp/jank/analyze/processor.hpp index eb8916de2..44049dcba 100644 --- a/compiler+runtime/include/cpp/jank/analyze/processor.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/processor.hpp @@ -49,8 +49,8 @@ namespace jank::analyze expression_result analyze(read::parse::processor::iterator, read::parse::processor::iterator const &); - expression_result analyze(runtime::object_ref, expression_position); - expression_result analyze(runtime::object_ref, + expression_result analyze(runtime::object_ref const, expression_position); + expression_result analyze(runtime::object_ref const, local_frame_ptr, expression_position, jtl::option const &, @@ -134,7 +134,7 @@ namespace jank::analyze expression_position, jtl::option const &, bool needs_box); - expression_result analyze_primitive_literal(runtime::object_ref, + expression_result analyze_primitive_literal(runtime::object_ref const, local_frame_ptr, expression_position, jtl::option const &, @@ -225,7 +225,7 @@ namespace jank::analyze bool needs_box); /* Returns whether the form is a special symbol. */ - bool is_special(runtime::object_ref form); + bool is_special(runtime::object_ref const form); using special_function_type = expression_result (processor::*)(runtime::obj::persistent_list_ref const, diff --git a/compiler+runtime/include/cpp/jank/analyze/recursive_visitor.hpp b/compiler+runtime/include/cpp/jank/analyze/recursive_visitor.hpp index 1c281afc9..713bbc1c8 100644 --- a/compiler+runtime/include/cpp/jank/analyze/recursive_visitor.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/recursive_visitor.hpp @@ -62,7 +62,7 @@ namespace jank::analyze virtual result_type visit(expr::def const &expr); virtual result_type visit(expr::var_deref const &expr); - virtual result_type visit(expr::var_ref const &expr); + virtual result_type visit(expr::var_ref const expr); virtual result_type visit(expr::call const &expr); virtual result_type visit(expr::primitive_literal const &expr); virtual result_type visit(expr::list const &expr); diff --git a/compiler+runtime/include/cpp/jank/aot/processor.hpp b/compiler+runtime/include/cpp/jank/aot/processor.hpp index 637e18a68..178b1d3c7 100644 --- a/compiler+runtime/include/cpp/jank/aot/processor.hpp +++ b/compiler+runtime/include/cpp/jank/aot/processor.hpp @@ -8,6 +8,8 @@ namespace jank::aot { struct processor { - jtl::result compile(jtl::immutable_string const &module) const; + jtl::result build_executable(jtl::immutable_string const &module) const; + jtl::result compile_object(jtl::immutable_string const &module_name, + jtl::immutable_string const &cpp_source) const; }; } diff --git a/compiler+runtime/include/cpp/jank/c_api.h b/compiler+runtime/include/cpp/jank/c_api.h index a66d5b9b5..ee4d6ceee 100644 --- a/compiler+runtime/include/cpp/jank/c_api.h +++ b/compiler+runtime/include/cpp/jank/c_api.h @@ -49,6 +49,8 @@ extern "C" jank_object_ref jank_read_string(jank_object_ref s); jank_object_ref jank_read_string_c(char const * const s); + jank_object_ref jank_ns_intern(jank_object_ref sym); + jank_object_ref jank_ns_intern_c(char const * const sym); void jank_ns_set_symbol_counter(char const * const ns, jank_u64 const count); jank_object_ref jank_var_intern(jank_object_ref ns, jank_object_ref name); diff --git a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp index c5688b954..803918ac1 100644 --- a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp +++ b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp @@ -110,7 +110,7 @@ namespace jank::codegen compilation_target target); /* For this ctor, we're inheriting the context from another function, which means * we're building a nested function. */ - llvm_processor(analyze::expr::function_ref expr, std::unique_ptr ctx); + llvm_processor(analyze::expr::function_ref expr, jtl::ref ctx); llvm_processor(llvm_processor const &) = delete; llvm_processor(llvm_processor &&) noexcept = default; diff --git a/compiler+runtime/include/cpp/jank/codegen/processor.hpp b/compiler+runtime/include/cpp/jank/codegen/processor.hpp index 048215b59..972160695 100644 --- a/compiler+runtime/include/cpp/jank/codegen/processor.hpp +++ b/compiler+runtime/include/cpp/jank/codegen/processor.hpp @@ -92,116 +92,110 @@ namespace jank::codegen processor(processor const &) = delete; processor(processor &&) noexcept = delete; + jtl::option gen(analyze::expression_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::def_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expression_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::var_deref_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::def_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::var_ref_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::call_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::var_deref_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::primitive_literal_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::list_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::vector_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::map_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::set_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::var_ref_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::local_reference_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::call_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option gen(analyze::expr::primitive_literal_ref const, - analyze::expr::function_arity const &, - bool box_needed); + gen(analyze::expr::function_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::recur_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::vector_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::recursion_reference_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::map_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::named_recursion_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::let_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::letfn_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::do_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::if_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::throw_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::try_ref const, analyze::expr::function_arity const &); + jtl::option gen(analyze::expr::case_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::set_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option gen(analyze::expr::local_reference_ref const, - analyze::expr::function_arity const &, - bool box_needed); + gen(analyze::expr::cpp_raw_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::function_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_type_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::recur_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option gen(analyze::expr::recursion_reference_ref const, - analyze::expr::function_arity const &, - bool box_needed); - jtl::option gen(analyze::expr::named_recursion_ref const, - analyze::expr::function_arity const &, - bool box_needed); + gen(analyze::expr::cpp_value_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::let_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_cast_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::letfn_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_call_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::do_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_constructor_call_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::if_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_member_call_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::throw_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_member_access_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::try_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_builtin_operator_call_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::case_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_box_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::cpp_raw_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_unbox_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::cpp_type_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_new_ref const, analyze::expr::function_arity const &); jtl::option - gen(analyze::expr::cpp_value_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option - gen(analyze::expr::cpp_cast_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option - gen(analyze::expr::cpp_call_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option gen(analyze::expr::cpp_constructor_call_ref const, - analyze::expr::function_arity const &, - bool box_needed); - jtl::option gen(analyze::expr::cpp_member_call_ref const, - analyze::expr::function_arity const &, - bool box_needed); - jtl::option gen(analyze::expr::cpp_member_access_ref const, - analyze::expr::function_arity const &, - bool box_needed); - jtl::option gen(analyze::expr::cpp_builtin_operator_call_ref const, - analyze::expr::function_arity const &, - bool box_needed); - jtl::option - gen(analyze::expr::cpp_box_ref const, analyze::expr::function_arity const &, bool box_needed); - jtl::option - gen(analyze::expr::cpp_unbox_ref const, analyze::expr::function_arity const &, bool box_needed); + gen(analyze::expr::cpp_delete_ref const, analyze::expr::function_arity const &); jtl::immutable_string declaration_str(); void build_header(); void build_body(); void build_footer(); - jtl::immutable_string expression_str(bool box_needed); - - jtl::immutable_string module_init_str(jtl::immutable_string const &module); + jtl::immutable_string expression_str(); void format_elided_var(jtl::immutable_string const &start, jtl::immutable_string const &end, jtl::immutable_string const &ret_tmp, native_vector const &arg_exprs, analyze::expr::function_arity const &fn_arity, - bool arg_box_needed, bool ret_box_needed); - void format_direct_call(jtl::immutable_string const &source_tmp, - jtl::immutable_string const &ret_tmp, - native_vector const &arg_exprs, - analyze::expr::function_arity const &fn_arity, - bool arg_box_needed); void format_dynamic_call(jtl::immutable_string const &source_tmp, jtl::immutable_string const &ret_tmp, native_vector const &arg_exprs, - analyze::expr::function_arity const &fn_arity, - bool arg_box_needed); + analyze::expr::function_arity const &fn_arity); + void format_direct_call(jtl::immutable_string const &source_tmp, + jtl::immutable_string const &ret_tmp, + native_vector const &arg_exprs, + analyze::expr::function_arity const &fn_arity); analyze::expr::function_ref root_fn; jtl::immutable_string module; compilation_target target{}; - runtime::obj::symbol struct_name; + jtl::immutable_string struct_name; + jtl::string_builder cpp_raw_buffer; + jtl::string_builder module_header_buffer; + jtl::string_builder module_footer_buffer; jtl::string_builder deps_buffer; jtl::string_builder header_buffer; jtl::string_builder body_buffer; jtl::string_builder footer_buffer; jtl::string_builder expression_buffer; jtl::immutable_string expression_fn_name; + + struct lifted_var + { + jtl::immutable_string native_name; + bool owned{}; + }; + + native_unordered_map lifted_vars; + native_unordered_map, + runtime::very_equal_to> + lifted_constants; bool generated_declaration{}; bool generated_expression{}; }; diff --git a/compiler+runtime/include/cpp/jank/compiler_native.hpp b/compiler+runtime/include/cpp/jank/compiler_native.hpp index 079db5e25..5703e4ddc 100644 --- a/compiler+runtime/include/cpp/jank/compiler_native.hpp +++ b/compiler+runtime/include/cpp/jank/compiler_native.hpp @@ -1,5 +1,3 @@ #pragma once -#include - -extern "C" jank_object_ref jank_load_jank_compiler_native(); +extern "C" void jank_load_jank_compiler_native(); diff --git a/compiler+runtime/include/cpp/jank/error.hpp b/compiler+runtime/include/cpp/jank/error.hpp index 746dd0f40..949fb64e1 100644 --- a/compiler+runtime/include/cpp/jank/error.hpp +++ b/compiler+runtime/include/cpp/jank/error.hpp @@ -103,6 +103,7 @@ namespace jank::error analyze_invalid_cpp_member_access, analyze_invalid_cpp_capture, analyze_mismatched_if_types, + analyze_known_issue, internal_analyze_failure, internal_codegen_failure, @@ -301,6 +302,8 @@ namespace jank::error return "analyze/invalid-cpp-capture"; case kind::analyze_mismatched_if_types: return "analyze/mismatched-if-types"; + case kind::analyze_known_issue: + return "analyze/known-issue"; case kind::internal_analyze_failure: return "internal/analysis-failure"; @@ -376,8 +379,10 @@ namespace jank::error /* We need gc_cleanup to run the dtor for the unique_ptr. This * is because cpptrace doesn't use our GC allocator. */ - struct base : gc_cleanup + struct base { + static constexpr bool is_error{ true }; + base() = delete; base(base const &) = delete; base(base &&) noexcept = default; @@ -387,17 +392,17 @@ namespace jank::error base(kind k, jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); base(kind k, jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion, + runtime::object_ref const expansion, std::unique_ptr trace); base(kind k, jtl::immutable_string const &message, read::source const &source, jtl::immutable_string const ¬e_message, - runtime::object_ref expansion); + runtime::object_ref const expansion); base(kind k, read::source const &source, jtl::immutable_string const ¬e_message); base(kind k, jtl::immutable_string const &message, @@ -412,7 +417,7 @@ namespace jank::error jtl::immutable_string const &message, read::source const &source, note const ¬e, - runtime::object_ref expansion); + runtime::object_ref const expansion); base(kind k, jtl::immutable_string const &message, read::source const &source, @@ -420,12 +425,12 @@ namespace jank::error base(kind k, jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion, + runtime::object_ref const expansion, jtl::ref cause); base(kind k, jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion, + runtime::object_ref const expansion, jtl::ref cause, std::unique_ptr trace); @@ -457,4 +462,12 @@ namespace jank { return jtl::make_ref(jtl::forward(args)...); } + + namespace error + { + error_ref internal_failure(jtl::immutable_string const &message); + /* This can be used by jtl helpers which can't reach into jank but which fail. */ + [[noreturn]] + void throw_internal_failure(jtl::immutable_string const &message); + } } diff --git a/compiler+runtime/include/cpp/jank/error/analyze.hpp b/compiler+runtime/include/cpp/jank/error/analyze.hpp index 280d4312e..b67323af1 100644 --- a/compiler+runtime/include/cpp/jank/error/analyze.hpp +++ b/compiler+runtime/include/cpp/jank/error/analyze.hpp @@ -11,148 +11,151 @@ namespace jank::error { error_ref analyze_invalid_case(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_def(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_def(jtl::immutable_string const &message, read::source const &source, jtl::immutable_string const ¬e, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_fn(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_fn_parameters(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_fn_parameters(jtl::immutable_string const &message, read::source const &source, jtl::immutable_string const &error_note_message, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_recur_position(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_recur_from_try(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_recur_args(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_let(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_letfn(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_loop(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_if(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_if(jtl::immutable_string const &message, read::source const &source, jtl::immutable_string const &error_note_message, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_quote(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_var_reference(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_throw(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_try(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_try(jtl::immutable_string const &message, read::source const &source, note &&extra, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_unresolved_var(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_unresolved_symbol(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_macro_expansion_exception(std::exception const &e, cpptrace::stacktrace const &trace, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_macro_expansion_exception(runtime::object_ref const e, cpptrace::stacktrace const &trace, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_macro_expansion_exception(jtl::immutable_string const &e, cpptrace::stacktrace const &trace, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_macro_expansion_exception(error_ref e, cpptrace::stacktrace const &trace, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_conversion(jtl::immutable_string const &message); error_ref analyze_invalid_cpp_operator_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_constructor_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_member_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_capture(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_mismatched_if_types(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_function_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_conversion(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_symbol(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_unresolved_cpp_symbol(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_raw(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_type(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_value(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_cast(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_box(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_unbox(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_new(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_delete(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); error_ref analyze_invalid_cpp_member_access(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); - error_ref - internal_analyze_failure(jtl::immutable_string const &message, runtime::object_ref expansion); + runtime::object_ref const expansion); + error_ref analyze_known_issue(jtl::immutable_string const &message, + read::source const &source, + runtime::object_ref const expansion); + error_ref internal_analyze_failure(jtl::immutable_string const &message, + runtime::object_ref const expansion); error_ref internal_analyze_failure(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion); + runtime::object_ref const expansion); } diff --git a/compiler+runtime/include/cpp/jank/error/report.hpp b/compiler+runtime/include/cpp/jank/error/report.hpp index 04b38c62a..46418aa46 100644 --- a/compiler+runtime/include/cpp/jank/error/report.hpp +++ b/compiler+runtime/include/cpp/jank/error/report.hpp @@ -5,4 +5,5 @@ namespace jank::error { void report(error_ref e); + void warn(jtl::immutable_string const &); } diff --git a/compiler+runtime/include/cpp/jank/error/runtime.hpp b/compiler+runtime/include/cpp/jank/error/runtime.hpp index 1deab795f..706a2e5e0 100644 --- a/compiler+runtime/include/cpp/jank/error/runtime.hpp +++ b/compiler+runtime/include/cpp/jank/error/runtime.hpp @@ -9,6 +9,7 @@ namespace jank::error error_ref runtime_unable_to_open_file(jtl::immutable_string const &message); error_ref runtime_invalid_cpp_eval(); error_ref runtime_unable_to_load_module(jtl::immutable_string const &message); + error_ref runtime_unable_to_load_module(error_ref cause); error_ref internal_runtime_failure(jtl::immutable_string const &message); error_ref runtime_invalid_unbox(jtl::immutable_string const &message, read::source const &unbox_source); diff --git a/compiler+runtime/include/cpp/jank/jit/processor.hpp b/compiler+runtime/include/cpp/jank/jit/processor.hpp index ca870111a..b133f45f2 100644 --- a/compiler+runtime/include/cpp/jank/jit/processor.hpp +++ b/compiler+runtime/include/cpp/jank/jit/processor.hpp @@ -17,6 +17,11 @@ namespace llvm } } +namespace clang +{ + class Value; +} + namespace Cpp { class Interpreter; @@ -30,6 +35,7 @@ namespace jank::jit ~processor(); void eval_string(jtl::immutable_string const &s) const; + void eval_string(jtl::immutable_string const &s, clang::Value *) const; void load_object(jtl::immutable_string_view const &path) const; void load_dynamic_library(jtl::immutable_string const &path) const; void load_ir_module(llvm::orc::ThreadSafeModule &&m) const; diff --git a/compiler+runtime/include/cpp/jank/perf_native.hpp b/compiler+runtime/include/cpp/jank/perf_native.hpp index 6c25a70db..44d962eac 100644 --- a/compiler+runtime/include/cpp/jank/perf_native.hpp +++ b/compiler+runtime/include/cpp/jank/perf_native.hpp @@ -2,4 +2,4 @@ #include -jank_object_ref jank_load_jank_perf_native(); +extern "C" void jank_load_jank_perf_native(); diff --git a/compiler+runtime/include/cpp/jank/prelude.hpp b/compiler+runtime/include/cpp/jank/prelude.hpp index 64789c2df..2618f3e30 100644 --- a/compiler+runtime/include/cpp/jank/prelude.hpp +++ b/compiler+runtime/include/cpp/jank/prelude.hpp @@ -8,5 +8,7 @@ #include #include #include +#include #include #include +#include diff --git a/compiler+runtime/include/cpp/jank/read/parse.hpp b/compiler+runtime/include/cpp/jank/read/parse.hpp index 8de1c5e14..a3e27a54e 100644 --- a/compiler+runtime/include/cpp/jank/read/parse.hpp +++ b/compiler+runtime/include/cpp/jank/read/parse.hpp @@ -100,12 +100,14 @@ namespace jank::read::parse iterator end(); private: - jtl::result syntax_quote(runtime::object_ref form); - jtl::result syntax_quote_expand_seq(runtime::object_ref seq); - jtl::result syntax_quote_expand_set(runtime::object_ref seq); + jtl::result syntax_quote(runtime::object_ref const form); + jtl::result + syntax_quote_expand_seq(runtime::object_ref const seq); + jtl::result + syntax_quote_expand_set(runtime::object_ref const seq); static jtl::result - syntax_quote_flatten_map(runtime::object_ref seq); - static bool syntax_quote_is_unquote(runtime::object_ref form, bool splice); + syntax_quote_flatten_map(runtime::object_ref const seq); + static bool syntax_quote_is_unquote(runtime::object_ref const form, bool splice); public: lex::processor::iterator token_current, token_end; @@ -117,7 +119,7 @@ namespace jank::read::parse * token, we should check this list to see if there's already a form we should pull out. * This is needed because parse iteration works one form at a time and splicing potentially * turns one form into many. */ - std::list pending_forms; + native_list pending_forms; lex::token latest_token; jtl::option shorthand; /* Whether or not the next form is considered quoted. */ diff --git a/compiler+runtime/include/cpp/jank/read/reparse.hpp b/compiler+runtime/include/cpp/jank/read/reparse.hpp index 0b6e988cf..1a791d1cd 100644 --- a/compiler+runtime/include/cpp/jank/read/reparse.hpp +++ b/compiler+runtime/include/cpp/jank/read/reparse.hpp @@ -20,7 +20,7 @@ namespace jank::runtime::obj * to parse the nth form inside that list. That gives us the source for `:foo`. */ namespace jank::read::parse { - source reparse_nth(runtime::obj::persistent_list_ref o, usize n); - source reparse_nth(runtime::obj::persistent_vector_ref o, usize n); - source reparse_nth(runtime::object_ref o, usize n); + source reparse_nth(runtime::obj::persistent_list_ref const o, usize n); + source reparse_nth(runtime::obj::persistent_vector_ref const o, usize n); + source reparse_nth(runtime::object_ref const o, usize n); } diff --git a/compiler+runtime/include/cpp/jank/read/source.hpp b/compiler+runtime/include/cpp/jank/read/source.hpp index e51cb4879..c1db7d41a 100644 --- a/compiler+runtime/include/cpp/jank/read/source.hpp +++ b/compiler+runtime/include/cpp/jank/read/source.hpp @@ -9,7 +9,7 @@ namespace jank::read struct source_position { - static source_position const unknown; + static source_position unknown(); bool operator==(source_position const &rhs) const; bool operator!=(source_position const &rhs) const; @@ -23,7 +23,7 @@ namespace jank::read struct source { - static source const unknown; + static source unknown(); source() = delete; source(source const &) = default; @@ -38,7 +38,7 @@ namespace jank::read jtl::immutable_string const &module, source_position const &start, source_position const &end, - runtime::object_ref macro_expansion); + runtime::object_ref const macro_expansion); source &operator=(source const &rhs) = default; source &operator=(source &&rhs) = default; diff --git a/compiler+runtime/include/cpp/jank/runtime/behavior/callable.hpp b/compiler+runtime/include/cpp/jank/runtime/behavior/callable.hpp index 832d753ff..59bc2dbac 100644 --- a/compiler+runtime/include/cpp/jank/runtime/behavior/callable.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/behavior/callable.hpp @@ -22,71 +22,80 @@ namespace jank::runtime * dynamic code. We may not every know if the source is callable at all, so * codegen will use this suite of fns instead. */ object_ref dynamic_call(object_ref const source); - object_ref dynamic_call(object_ref const source, object_ref); - object_ref dynamic_call(object_ref const source, object_ref, object_ref); - object_ref dynamic_call(object_ref const source, object_ref, object_ref, object_ref); - object_ref dynamic_call(object_ref const source, object_ref, object_ref, object_ref, object_ref); + object_ref dynamic_call(object_ref const source, object_ref const); + object_ref dynamic_call(object_ref const source, object_ref const, object_ref const); object_ref - dynamic_call(object_ref const source, object_ref, object_ref, object_ref, object_ref, object_ref); + dynamic_call(object_ref const source, object_ref const, object_ref const, object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + object_ref const, + object_ref const, + object_ref const, + object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); object_ref dynamic_call(object_ref const source, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - obj::persistent_list_ref); - - object_ref apply_to(object_ref source, object_ref args); + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + object_ref dynamic_call(object_ref const source, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + object_ref dynamic_call(object_ref const source, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + obj::persistent_list_ref const); + + object_ref apply_to(object_ref const source, object_ref const args); namespace behavior { @@ -98,42 +107,56 @@ namespace jank::runtime virtual ~callable() = default; virtual object_ref call(); - virtual object_ref call(object_ref); - virtual object_ref call(object_ref, object_ref); - virtual object_ref call(object_ref, object_ref, object_ref); - virtual object_ref call(object_ref, object_ref, object_ref, object_ref); - virtual object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref); - virtual object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref); + virtual object_ref call(object_ref const); + virtual object_ref call(object_ref const, object_ref const); + virtual object_ref call(object_ref const, object_ref const, object_ref const); virtual object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref, object_ref); - virtual object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); - virtual object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); - virtual object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref); + call(object_ref const, object_ref const, object_ref const, object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); + virtual object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const); /* Callables need a way to get back to the root object so we can do helpful * error reporting on failed calls. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/context.hpp b/compiler+runtime/include/cpp/jank/runtime/context.hpp index 336cdc270..13b5fd1b5 100644 --- a/compiler+runtime/include/cpp/jank/runtime/context.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/context.hpp @@ -43,30 +43,31 @@ namespace jank::runtime context(); context(context const &) = delete; context(context &&) noexcept = delete; - ~context(); ns_ref intern_ns(jtl::immutable_string const &); - ns_ref intern_ns(obj::symbol_ref const &); - ns_ref remove_ns(obj::symbol_ref const &); + ns_ref intern_ns(obj::symbol_ref const); + ns_ref remove_ns(obj::symbol_ref const); /* Looks up a ns by its symbol. Does not resolve aliases. Does not intern. */ - ns_ref find_ns(obj::symbol_ref const &); + ns_ref find_ns(obj::symbol_ref const); /* Resolves a symbol which could be an alias to its ns, based on the aliases * in the current ns. Does not intern. */ - ns_ref resolve_ns(obj::symbol_ref const &); + ns_ref resolve_ns(obj::symbol_ref const); ns_ref current_ns() const; /* Adds the current ns to unqualified symbols and resolves the ns of qualified symbols. * Does not intern. */ - obj::symbol_ref qualify_symbol(obj::symbol_ref const &) const; - jtl::option find_local(obj::symbol_ref const &); + obj::symbol_ref qualify_symbol(obj::symbol_ref const) const; + jtl::option find_local(obj::symbol_ref const); - jtl::result intern_var(obj::symbol_ref const &); + jtl::result intern_var(obj::symbol_ref const qualified_name); + jtl::result intern_var(jtl::immutable_string const &); jtl::result intern_var(jtl::immutable_string const &ns, jtl::immutable_string const &name); - jtl::result intern_owned_var(obj::symbol_ref const &); + jtl::result intern_owned_var(obj::symbol_ref const); + jtl::result intern_owned_var(jtl::immutable_string const &); jtl::result intern_owned_var(jtl::immutable_string const &ns, jtl::immutable_string const &name); - var_ref find_var(obj::symbol_ref const &); + var_ref find_var(obj::symbol_ref const); var_ref find_var(jtl::immutable_string const &ns, jtl::immutable_string const &name); jtl::result @@ -76,15 +77,15 @@ namespace jank::runtime jtl::result intern_keyword(jtl::immutable_string const &s); - object_ref macroexpand1(object_ref o); - object_ref macroexpand(object_ref o); + object_ref macroexpand1(object_ref const o); + object_ref macroexpand(object_ref const o); jtl::option eval_file(jtl::immutable_string const &path); - jtl::option eval_string(jtl::immutable_string_view const &code); - jtl::result eval_cpp_string(jtl::immutable_string_view const &code) const; - object_ref read_string(jtl::immutable_string_view const &code); + jtl::option eval_string(jtl::immutable_string const &code); + jtl::result eval_cpp_string(jtl::immutable_string const &code) const; + object_ref read_string(jtl::immutable_string const &code); native_vector - analyze_string(jtl::immutable_string_view const &code, bool const eval = true); + analyze_string(jtl::immutable_string const &code, bool const eval = true); /* Finds the specified module on the module path and loads it. If * the module is already loaded, nothing is done. @@ -98,24 +99,26 @@ namespace jank::runtime * Module meow.cat refers to foo.bar$meow.cat */ jtl::result - load_module(jtl::immutable_string_view const &module, module::origin ori); + load_module(jtl::immutable_string const &module, module::origin ori); /* Does all the same work as load_module, but also writes compiled files to the file system. */ - jtl::result compile_module(jtl::immutable_string_view const &module); + jtl::result compile_module(jtl::immutable_string const &module); object_ref eval(object_ref const o); + jtl::immutable_string get_output_module_name(jtl::immutable_string const &module_name) const; jtl::string_result write_module(jtl::immutable_string const &module_name, + jtl::immutable_string const &cpp_code, jtl::ref const &module) const; /* Generates a unique name for use with anything from codgen structs, * lifted vars, to shadowed locals. Prefixes with current namespace. */ jtl::immutable_string unique_namespaced_string() const; - jtl::immutable_string unique_namespaced_string(jtl::immutable_string_view const &prefix) const; - jtl::immutable_string unique_munged_string() const; - jtl::immutable_string unique_munged_string(jtl::immutable_string_view const &prefix) const; - obj::symbol unique_symbol() const; - obj::symbol unique_symbol(jtl::immutable_string_view const &prefix) const; + jtl::immutable_string unique_namespaced_string(jtl::immutable_string const &prefix) const; + jtl::immutable_string unique_string() const; + jtl::immutable_string unique_string(jtl::immutable_string const &prefix) const; + obj::symbol_ref unique_symbol() const; + obj::symbol_ref unique_symbol(jtl::immutable_string const &prefix) const; folly::Synchronized> namespaces; folly::Synchronized> keywords; @@ -158,9 +161,7 @@ namespace jank::runtime var_ref no_recur_var; var_ref gensym_env_var; - /* TODO: Remove this map. Just use the list. */ - static thread_local native_unordered_map> - thread_binding_frames; + static thread_local native_list thread_binding_frames; /* This must go last, since it'll try to access other bits in the runtime context during * its initialization and we need them to be ready. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/convert/builtin.hpp b/compiler+runtime/include/cpp/jank/runtime/convert/builtin.hpp index eb8745bc8..991a2a1ce 100644 --- a/compiler+runtime/include/cpp/jank/runtime/convert/builtin.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/convert/builtin.hpp @@ -15,12 +15,12 @@ namespace jank::runtime template <> struct convert { - static constexpr object_ref into_object(object_ref const t) + static object_ref into_object(object_ref const t) { return t; } - static constexpr object_ref from_object(object_ref const t) + static object_ref from_object(object_ref const t) { return t; } @@ -30,15 +30,25 @@ namespace jank::runtime requires(jtl::is_any_same) struct convert { - static constexpr object *into_object(T t) + static object_ref into_object(T t) { return const_cast(t); } - static constexpr object *from_object(T t) + static object_ref into_object(object_ref const t) + { + return t.erase(); + } + + static object_ref from_object(T t) { return const_cast(t); } + + static object_ref from_object(object_ref const t) + { + return t.erase(); + } }; /* Any typed object can convert to/from itself easily. */ @@ -46,17 +56,17 @@ namespace jank::runtime requires typed_object_ref struct convert { - static constexpr T into_object(T const t) + static T into_object(T const &t) { return t; } - static constexpr T from_object(object_ref const t) + static T from_object(object_ref const t) { return try_object(t); } - static constexpr T from_object(T const t) + static T from_object(T const t) { return t; } @@ -67,12 +77,12 @@ namespace jank::runtime requires has_conversion_members struct convert { - static constexpr auto into_object(T const &t) + static auto into_object(T const &t) { return T::into_object(t); } - static constexpr T from_object(auto const o) + static T from_object(auto const o) { return T::from_object(o); } @@ -81,12 +91,12 @@ namespace jank::runtime template <> struct convert { - static constexpr obj::nil_ref into_object() + static obj::nil_ref into_object() { - return jank_nil; + return jank_nil(); } - static constexpr void from_object(object_ref) + static void from_object(object_ref const) { } }; @@ -94,12 +104,12 @@ namespace jank::runtime template <> struct convert { - static constexpr obj::nil_ref into_object(jtl::nullptr_t) + static obj::nil_ref into_object(jtl::nullptr_t) { - return jank_nil; + return jank_nil(); } - static constexpr jtl::nullptr_t from_object(object_ref) + static jtl::nullptr_t from_object(object_ref const) { return nullptr; } @@ -108,17 +118,17 @@ namespace jank::runtime template <> struct convert { - static constexpr obj::boolean_ref into_object(bool const o) + static obj::boolean_ref into_object(bool const o) { return make_box(o); } - static constexpr bool from_object(object_ref const o) + static bool from_object(object_ref const o) { return try_object(o)->data; } - static constexpr bool from_object(obj::boolean_ref const o) + static bool from_object(obj::boolean_ref const o) { return o->data; } @@ -127,17 +137,17 @@ namespace jank::runtime template <> struct convert { - static constexpr obj::character_ref into_object(char const o) + static obj::character_ref into_object(char const o) { return make_box(o); } - static constexpr char from_object(object_ref const o) + static char from_object(object_ref const o) { return try_object(o)->data[0]; } - static constexpr char from_object(obj::character_ref const o) + static char from_object(obj::character_ref const o) { return o->data[0]; } @@ -147,17 +157,17 @@ namespace jank::runtime requires std::is_enum_v struct convert { - static constexpr obj::integer_ref into_object(T const o) + static obj::integer_ref into_object(T const o) { return make_box(static_cast(o)); } - static constexpr T from_object(object_ref const o) + static T from_object(object_ref const o) { return try_object(o); } - static constexpr T from_object(obj::integer_ref const o) + static T from_object(obj::integer_ref const o) { return o->data; } @@ -169,17 +179,17 @@ namespace jank::runtime && !jtl::is_any_same) struct convert { - static constexpr obj::integer_ref into_object(T const o) + static obj::integer_ref into_object(T const o) { return make_box(static_cast(o)); } - static constexpr T from_object(object_ref const o) + static T from_object(object_ref const o) { return static_cast(try_object(o)->data); } - static constexpr T from_object(obj::integer_ref const o) + static T from_object(obj::integer_ref const o) { return static_cast(o->data); } @@ -189,7 +199,7 @@ namespace jank::runtime template <> struct convert { - static constexpr obj::big_integer_ref into_object(native_big_integer const &o) + static obj::big_integer_ref into_object(native_big_integer const &o) { return make_box(o); } @@ -210,17 +220,17 @@ namespace jank::runtime requires(std::is_floating_point_v) struct convert { - static constexpr obj::real_ref into_object(T const o) + static obj::real_ref into_object(T const o) { return make_box(static_cast(o)); } - static constexpr T from_object(object_ref const o) + static T from_object(object_ref const o) { return static_cast(try_object(o)->data); } - static constexpr T from_object(obj::real_ref const o) + static T from_object(obj::real_ref const o) { return static_cast(o->data); } @@ -231,21 +241,21 @@ namespace jank::runtime requires(jtl::is_any_same, char *, char const *>) struct convert { - static constexpr obj::persistent_string_ref into_object(char const * const o) + static obj::persistent_string_ref into_object(char const * const o) { if(o == nullptr) { - return jank_nil; + return jank_nil(); } return make_box(o); } - static constexpr char const *from_object(object_ref const o) + static char const *from_object(object_ref const o) { return try_object(o)->data.c_str(); } - static constexpr char const *from_object(obj::persistent_string_ref const o) + static char const *from_object(obj::persistent_string_ref const o) { return o->data.c_str(); } @@ -256,17 +266,17 @@ namespace jank::runtime requires(jtl::is_any_same) struct convert { - static constexpr obj::persistent_string_ref into_object(T const &o) + static obj::persistent_string_ref into_object(T const &o) { return make_box(o); } - static constexpr T from_object(object_ref const o) + static T from_object(object_ref const o) { return try_object(o)->data; } - static constexpr T from_object(obj::persistent_string_ref const o) + static T from_object(obj::persistent_string_ref const o) { return o->data; } @@ -288,15 +298,15 @@ namespace jank::runtime return make_box(trans); } - static constexpr V from_object(object_ref const o) + static V from_object(object_ref const o) { return from_object(try_object(o)); } - static constexpr V from_object(obj::persistent_vector_ref const o) + static V from_object(obj::persistent_vector_ref const o) { V ret; - for(auto const e : o->data) + for(auto const &e : o->data) { ret.push_back(e); } diff --git a/compiler+runtime/include/cpp/jank/runtime/convert/function.hpp b/compiler+runtime/include/cpp/jank/runtime/convert/function.hpp index d7500e4dc..948964063 100644 --- a/compiler+runtime/include/cpp/jank/runtime/convert/function.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/convert/function.hpp @@ -7,13 +7,14 @@ namespace jank::runtime template struct always_object_ref { - using type = object_ref; + using type = object_ref const; }; template auto convert_function(R (* const fn)(Args...)) { - if constexpr(std::conjunction_v, std::is_same...>) + if constexpr(std::conjunction_v, + std::is_same...>) { return fn; } @@ -23,13 +24,13 @@ namespace jank::runtime [fn](Args &&...args) -> object_ref { if constexpr(jtl::is_void) { - fn(convert::into_object(jtl::forward(args))...); + fn(convert>::into_object(jtl::forward(args))...); return convert::into_object(); } else { return convert::into_object( - fn(convert::into_object(jtl::forward(args))...)); + fn(convert>::into_object(jtl::forward(args))...)); } } }; diff --git a/compiler+runtime/include/cpp/jank/runtime/core.hpp b/compiler+runtime/include/cpp/jank/runtime/core.hpp index e760e2b30..f161dc872 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core.hpp @@ -12,94 +12,103 @@ namespace jank::runtime { - jtl::immutable_string type(object_ref o); - bool is_nil(object_ref o); - bool is_true(object_ref o); - bool is_false(object_ref o); - bool is_some(object_ref o); - bool is_string(object_ref o); - bool is_char(object_ref o); - - bool is_symbol(object_ref o); - bool is_simple_symbol(object_ref o); - bool is_qualified_symbol(object_ref o); - - object_ref to_unqualified_symbol(object_ref o); - object_ref to_qualified_symbol(object_ref ns, object_ref name); - - object_ref print(object_ref args); - object_ref println(object_ref args); - object_ref pr(object_ref args); - object_ref prn(object_ref args); - - obj::persistent_string_ref subs(object_ref s, object_ref start); - obj::persistent_string_ref subs(object_ref s, object_ref start, object_ref end); - i64 first_index_of(object_ref s, object_ref m); - i64 last_index_of(object_ref s, object_ref m); - - bool is_named(object_ref o); - jtl::immutable_string name(object_ref o); - object_ref namespace_(object_ref o); - - object_ref keyword(object_ref ns, object_ref name); - bool is_keyword(object_ref o); - bool is_simple_keyword(object_ref o); - bool is_qualified_keyword(object_ref o); - - bool is_callable(object_ref o); - - uhash to_hash(object_ref o); - - object_ref macroexpand1(object_ref o); - object_ref macroexpand(object_ref o); - - object_ref gensym(object_ref o); - - object_ref atom(object_ref o); - object_ref deref(object_ref o); - object_ref swap_atom(object_ref atom, object_ref fn); - object_ref swap_atom(object_ref atom, object_ref fn, object_ref a1); - object_ref swap_atom(object_ref atom, object_ref fn, object_ref a1, object_ref a2); + jtl::immutable_string type(object_ref const o); + bool is_nil(object_ref const o); + bool is_true(object_ref const o); + bool is_false(object_ref const o); + bool is_some(object_ref const o); + bool is_string(object_ref const o); + bool is_char(object_ref const o); + + bool is_symbol(object_ref const o); + bool is_simple_symbol(object_ref const o); + bool is_qualified_symbol(object_ref const o); + + object_ref to_unqualified_symbol(object_ref const o); + object_ref to_qualified_symbol(object_ref const ns, object_ref const name); + + object_ref print(object_ref const args); + object_ref println(object_ref const args); + object_ref pr(object_ref const args); + object_ref prn(object_ref const args); + + obj::persistent_string_ref subs(object_ref const s, object_ref const start); + obj::persistent_string_ref subs(object_ref const s, object_ref const start, object_ref const end); + i64 first_index_of(object_ref const s, object_ref const m); + i64 last_index_of(object_ref const s, object_ref const m); + + bool is_named(object_ref const o); + jtl::immutable_string name(object_ref const o); + object_ref namespace_(object_ref const o); + + object_ref keyword(object_ref const ns, object_ref const name); + bool is_keyword(object_ref const o); + bool is_simple_keyword(object_ref const o); + bool is_qualified_keyword(object_ref const o); + + bool is_callable(object_ref const o); + + uhash to_hash(object_ref const o); + + object_ref macroexpand1(object_ref const o); + object_ref macroexpand(object_ref const o); + + object_ref gensym(object_ref const o); + + object_ref atom(object_ref const o); + object_ref deref(object_ref const o); + object_ref swap_atom(object_ref const atom, object_ref const fn); + object_ref swap_atom(object_ref const atom, object_ref const fn, object_ref const a1); object_ref - swap_atom(object_ref atom, object_ref fn, object_ref a1, object_ref a2, object_ref rest); - object_ref swap_vals(object_ref atom, object_ref fn); - object_ref swap_vals(object_ref atom, object_ref fn, object_ref a1); - object_ref swap_vals(object_ref atom, object_ref fn, object_ref a1, object_ref a2); + swap_atom(object_ref const atom, object_ref const fn, object_ref const a1, object_ref const a2); + object_ref swap_atom(object_ref const atom, + object_ref const fn, + object_ref const a1, + object_ref const a2, + object_ref const rest); + object_ref swap_vals(object_ref const atom, object_ref const fn); + object_ref swap_vals(object_ref const atom, object_ref const fn, object_ref const a1); object_ref - swap_vals(object_ref atom, object_ref fn, object_ref a1, object_ref a2, object_ref rest); - object_ref compare_and_set(object_ref atom, object_ref old_val, object_ref new_val); - object_ref reset(object_ref atom, object_ref new_val); - object_ref reset_vals(object_ref atom, object_ref new_val); - - object_ref volatile_(object_ref o); - bool is_volatile(object_ref o); - object_ref vswap(object_ref v, object_ref fn); - object_ref vswap(object_ref v, object_ref fn, object_ref args); - object_ref vreset(object_ref v, object_ref new_val); - - void push_thread_bindings(object_ref o); + swap_vals(object_ref const atom, object_ref const fn, object_ref const a1, object_ref const a2); + object_ref swap_vals(object_ref const atom, + object_ref const fn, + object_ref const a1, + object_ref const a2, + object_ref const rest); + object_ref + compare_and_set(object_ref const atom, object_ref const old_val, object_ref const new_val); + object_ref reset(object_ref const atom, object_ref const new_val); + object_ref reset_vals(object_ref const atom, object_ref const new_val); + + object_ref volatile_(object_ref const o); + bool is_volatile(object_ref const o); + object_ref vswap(object_ref const v, object_ref const fn); + object_ref vswap(object_ref const v, object_ref const fn, object_ref const args); + object_ref vreset(object_ref const v, object_ref const new_val); + + void push_thread_bindings(object_ref const o); void pop_thread_bindings(); object_ref get_thread_bindings(); - object_ref force(object_ref o); + object_ref force(object_ref const o); - object_ref tagged_literal(object_ref tag, object_ref form); - bool is_tagged_literal(object_ref o); + object_ref tagged_literal(object_ref const tag, object_ref const form); + bool is_tagged_literal(object_ref const o); - object_ref parse_uuid(object_ref o); - bool is_uuid(object_ref o); + object_ref parse_uuid(object_ref const o); + bool is_uuid(object_ref const o); object_ref random_uuid(); - bool is_inst(object_ref o); - i64 inst_ms(object_ref o); + bool is_inst(object_ref const o); + i64 inst_ms(object_ref const o); - object_ref re_pattern(object_ref o); - object_ref re_matcher(object_ref re, object_ref s); - object_ref re_find(object_ref m); - object_ref re_groups(object_ref m); - object_ref re_matches(object_ref re, object_ref s); + object_ref re_pattern(object_ref const o); + object_ref re_matcher(object_ref const re, object_ref const s); + object_ref re_find(object_ref const m); + object_ref re_groups(object_ref const m); + object_ref re_matches(object_ref const re, object_ref const s); object_ref smatch_to_vector(std::smatch const &match_results); - object_ref add_watch(object_ref reference, object_ref key, object_ref fn); - object_ref remove_watch(object_ref reference, object_ref key); + object_ref add_watch(object_ref const reference, object_ref const key, object_ref const fn); + object_ref remove_watch(object_ref const reference, object_ref const key); } diff --git a/compiler+runtime/include/cpp/jank/runtime/core/equal.hpp b/compiler+runtime/include/cpp/jank/runtime/core/equal.hpp index 35a429ccd..f72ebce16 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/equal.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/equal.hpp @@ -4,8 +4,8 @@ namespace jank::runtime { - bool equal(char lhs, object_ref rhs); - bool equal(object_ref lhs, object_ref rhs); - i64 compare(object_ref, object_ref); - bool is_identical(object_ref lhs, object_ref rhs); + bool equal(char lhs, object_ref const rhs); + bool equal(object_ref const lhs, object_ref const rhs); + i64 compare(object_ref const, object_ref const); + bool is_identical(object_ref const lhs, object_ref const rhs); } diff --git a/compiler+runtime/include/cpp/jank/runtime/core/make_box.hpp b/compiler+runtime/include/cpp/jank/runtime/core/make_box.hpp index bdb09ab89..f15b2711a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/make_box.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/make_box.hpp @@ -16,7 +16,7 @@ namespace jank::runtime [[gnu::flatten, gnu::hot, gnu::visibility("default")]] inline auto make_box(std::nullptr_t const &) { - return jank_nil; + return jank_nil(); } [[gnu::flatten, gnu::hot, gnu::visibility("default")]] diff --git a/compiler+runtime/include/cpp/jank/runtime/core/math.hpp b/compiler+runtime/include/cpp/jank/runtime/core/math.hpp index a88c1a127..30117b7ea 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/math.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/math.hpp @@ -13,281 +13,281 @@ namespace jank::runtime using big_decimal_ref = oref; } - object_ref add(object_ref l, object_ref r); - object_ref add(obj::integer_ref l, object_ref r); - object_ref add(object_ref l, obj::integer_ref r); - object_ref add(object_ref l, obj::ratio_ref r); - object_ref add(obj::big_decimal_ref l, object_ref r); - object_ref add(object_ref l, obj::big_decimal_ref r); - i64 add(obj::integer_ref l, obj::integer_ref r); - f64 add(obj::real_ref l, obj::real_ref r); - object_ref add(obj::real_ref l, object_ref r); - object_ref add(object_ref l, obj::real_ref r); - f64 add(obj::real_ref l, obj::integer_ref r); - f64 add(obj::integer_ref l, obj::real_ref r); - - object_ref add(object_ref l, f64 r); - object_ref add(f64 l, object_ref r); + object_ref add(object_ref const l, object_ref const r); + object_ref add(obj::integer_ref const l, object_ref const r); + object_ref add(object_ref const l, obj::integer_ref const r); + object_ref add(object_ref const l, obj::ratio_ref const r); + object_ref add(obj::big_decimal_ref const l, object_ref const r); + object_ref add(object_ref const l, obj::big_decimal_ref const r); + i64 add(obj::integer_ref const l, obj::integer_ref const r); + f64 add(obj::real_ref const l, obj::real_ref const r); + object_ref add(obj::real_ref const l, object_ref const r); + object_ref add(object_ref const l, obj::real_ref const r); + f64 add(obj::real_ref const l, obj::integer_ref const r); + f64 add(obj::integer_ref const l, obj::real_ref const r); + + object_ref add(object_ref const l, f64 r); + object_ref add(f64 l, object_ref const r); f64 add(f64 l, f64 r); f64 add(i64 l, f64 r); f64 add(f64 l, i64 r); - object_ref add(object_ref l, i64 r); - object_ref add(i64 l, object_ref r); + object_ref add(object_ref const l, i64 r); + object_ref add(i64 l, object_ref const r); i64 add(i64 l, i64 r); - obj::ratio_ref add(obj::ratio_ref l, obj::ratio_ref r); - object_ref add(obj::ratio_ref l, obj::integer_ref r); - obj::ratio_ref add(obj::integer_ref l, obj::ratio_ref r); + obj::ratio_ref add(obj::ratio_ref const l, obj::ratio_ref const r); + object_ref add(obj::ratio_ref const l, obj::integer_ref const r); + obj::ratio_ref add(obj::integer_ref const l, obj::ratio_ref const r); object_ref promoting_add(object_ref const l, object_ref const r); - object_ref sub(object_ref l, object_ref r); - object_ref sub(obj::integer_ref l, object_ref r); - object_ref sub(object_ref l, obj::integer_ref r); - object_ref sub(obj::big_decimal_ref l, object_ref r); - object_ref sub(object_ref l, obj::big_decimal_ref r); - i64 sub(obj::integer_ref l, obj::integer_ref r); - f64 sub(obj::real_ref l, obj::real_ref r); - object_ref sub(obj::real_ref l, object_ref r); - object_ref sub(object_ref l, obj::real_ref r); - f64 sub(obj::real_ref l, obj::integer_ref r); - f64 sub(obj::integer_ref l, obj::real_ref r); - - object_ref sub(object_ref l, f64 r); - object_ref sub(f64 l, object_ref r); + object_ref sub(object_ref const l, object_ref const r); + object_ref sub(obj::integer_ref const l, object_ref const r); + object_ref sub(object_ref const l, obj::integer_ref const r); + object_ref sub(obj::big_decimal_ref const l, object_ref const r); + object_ref sub(object_ref const l, obj::big_decimal_ref const r); + i64 sub(obj::integer_ref const l, obj::integer_ref const r); + f64 sub(obj::real_ref const l, obj::real_ref const r); + object_ref sub(obj::real_ref const l, object_ref const r); + object_ref sub(object_ref const l, obj::real_ref const r); + f64 sub(obj::real_ref const l, obj::integer_ref const r); + f64 sub(obj::integer_ref const l, obj::real_ref const r); + + object_ref sub(object_ref const l, f64 r); + object_ref sub(f64 l, object_ref const r); f64 sub(f64 l, f64 r); f64 sub(i64 l, f64 r); f64 sub(f64 l, i64 r); - object_ref sub(object_ref l, i64 r); - object_ref sub(i64 l, object_ref r); + object_ref sub(object_ref const l, i64 r); + object_ref sub(i64 l, object_ref const r); i64 sub(i64 l, i64 r); object_ref promoting_sub(object_ref const l, object_ref const r); - object_ref div(object_ref l, object_ref r); - object_ref div(obj::integer_ref l, object_ref r); - object_ref div(object_ref l, obj::integer_ref r); - object_ref div(obj::big_decimal_ref l, object_ref r); - object_ref div(object_ref l, obj::big_decimal_ref r); - i64 div(obj::integer_ref l, obj::integer_ref r); - f64 div(obj::real_ref l, obj::real_ref r); - object_ref div(obj::real_ref l, object_ref r); - object_ref div(object_ref l, obj::real_ref r); - f64 div(obj::real_ref l, obj::integer_ref r); - f64 div(obj::integer_ref l, obj::real_ref r); - - object_ref div(object_ref l, f64 r); - object_ref div(f64 l, object_ref r); + object_ref div(object_ref const l, object_ref const r); + object_ref div(obj::integer_ref const l, object_ref const r); + object_ref div(object_ref const l, obj::integer_ref const r); + object_ref div(obj::big_decimal_ref const l, object_ref const r); + object_ref div(object_ref const l, obj::big_decimal_ref const r); + i64 div(obj::integer_ref const l, obj::integer_ref const r); + f64 div(obj::real_ref const l, obj::real_ref const r); + object_ref div(obj::real_ref const l, object_ref const r); + object_ref div(object_ref const l, obj::real_ref const r); + f64 div(obj::real_ref const l, obj::integer_ref const r); + f64 div(obj::integer_ref const l, obj::real_ref const r); + + object_ref div(object_ref const l, f64 r); + object_ref div(f64 l, object_ref const r); f64 div(f64 l, f64 r); f64 div(i64 l, f64 r); f64 div(f64 l, i64 r); - object_ref div(object_ref l, i64 r); - object_ref div(i64 l, object_ref r); + object_ref div(object_ref const l, i64 r); + object_ref div(i64 l, object_ref const r); i64 div(i64 l, i64 r); - object_ref mul(object_ref l, object_ref r); - object_ref mul(obj::integer_ref l, object_ref r); - object_ref mul(object_ref l, obj::integer_ref r); - object_ref mul(obj::big_decimal_ref l, object_ref r); - object_ref mul(object_ref l, obj::big_decimal_ref r); - i64 mul(obj::integer_ref l, obj::integer_ref r); - f64 mul(obj::real_ref l, obj::real_ref r); - object_ref mul(obj::real_ref l, object_ref r); - object_ref mul(object_ref l, obj::real_ref r); - f64 mul(obj::real_ref l, obj::integer_ref r); - f64 mul(obj::integer_ref l, obj::real_ref r); - - object_ref mul(object_ref l, f64 r); - object_ref mul(f64 l, object_ref r); + object_ref mul(object_ref const l, object_ref const r); + object_ref mul(obj::integer_ref const l, object_ref const r); + object_ref mul(object_ref const l, obj::integer_ref const r); + object_ref mul(obj::big_decimal_ref const l, object_ref const r); + object_ref mul(object_ref const l, obj::big_decimal_ref const r); + i64 mul(obj::integer_ref const l, obj::integer_ref const r); + f64 mul(obj::real_ref const l, obj::real_ref const r); + object_ref mul(obj::real_ref const l, object_ref const r); + object_ref mul(object_ref const l, obj::real_ref const r); + f64 mul(obj::real_ref const l, obj::integer_ref const r); + f64 mul(obj::integer_ref const l, obj::real_ref const r); + + object_ref mul(object_ref const l, f64 r); + object_ref mul(f64 l, object_ref const r); f64 mul(f64 l, f64 r); f64 mul(i64 l, f64 r); f64 mul(f64 l, i64 r); - object_ref mul(object_ref l, i64 r); - object_ref mul(i64 l, object_ref r); + object_ref mul(object_ref const l, i64 r); + object_ref mul(i64 l, object_ref const r); i64 mul(i64 l, i64 r); object_ref promoting_mul(object_ref const l, object_ref const r); - bool lt(object_ref l, object_ref r); - bool lt(obj::integer_ref l, object_ref r); - bool lt(object_ref l, obj::integer_ref r); + bool lt(object_ref const l, object_ref const r); + bool lt(obj::integer_ref const l, object_ref const r); + bool lt(object_ref const l, obj::integer_ref const r); bool lt(obj::integer_ref const l, obj::integer_ref const r); bool lt(obj::real_ref const l, obj::real_ref const r); - bool lt(obj::real_ref l, object_ref r); - bool lt(object_ref l, obj::real_ref r); - bool lt(obj::real_ref l, obj::integer_ref r); - bool lt(obj::integer_ref l, obj::real_ref r); + bool lt(obj::real_ref const l, object_ref const r); + bool lt(object_ref const l, obj::real_ref const r); + bool lt(obj::real_ref const l, obj::integer_ref const r); + bool lt(obj::integer_ref const l, obj::real_ref const r); - bool lt(object_ref l, f64 r); - bool lt(f64 l, object_ref r); + bool lt(object_ref const l, f64 r); + bool lt(f64 l, object_ref const r); bool lt(f64 l, f64 r); bool lt(i64 l, f64 r); bool lt(f64 l, i64 r); - bool lt(object_ref l, i64 r); - bool lt(i64 l, object_ref r); + bool lt(object_ref const l, i64 r); + bool lt(i64 l, object_ref const r); bool lt(i64 l, i64 r); - bool lte(object_ref l, object_ref r); - bool lte(obj::integer_ref l, object_ref r); - bool lte(object_ref l, obj::integer_ref r); + bool lte(object_ref const l, object_ref const r); + bool lte(obj::integer_ref const l, object_ref const r); + bool lte(object_ref const l, obj::integer_ref const r); bool lte(obj::integer_ref const l, obj::integer_ref const r); bool lte(obj::real_ref const l, obj::real_ref const r); - bool lte(obj::real_ref l, object_ref r); - bool lte(object_ref l, obj::real_ref r); - bool lte(obj::real_ref l, obj::integer_ref r); - bool lte(obj::integer_ref l, obj::real_ref r); + bool lte(obj::real_ref const l, object_ref const r); + bool lte(object_ref const l, obj::real_ref const r); + bool lte(obj::real_ref const l, obj::integer_ref const r); + bool lte(obj::integer_ref const l, obj::real_ref const r); - bool lte(object_ref l, f64 r); - bool lte(f64 l, object_ref r); + bool lte(object_ref const l, f64 r); + bool lte(f64 l, object_ref const r); bool lte(f64 l, f64 r); bool lte(i64 l, f64 r); bool lte(f64 l, i64 r); - bool lte(object_ref l, i64 r); - bool lte(i64 l, object_ref r); + bool lte(object_ref const l, i64 r); + bool lte(i64 l, object_ref const r); bool lte(i64 l, i64 r); - object_ref min(object_ref l, object_ref r); - object_ref min(obj::integer_ref l, object_ref r); - object_ref min(object_ref l, obj::integer_ref r); - i64 min(obj::integer_ref l, obj::integer_ref r); - f64 min(obj::real_ref l, obj::real_ref r); - f64 min(obj::real_ref l, object_ref r); - f64 min(object_ref l, obj::real_ref r); - f64 min(obj::real_ref l, obj::integer_ref r); - f64 min(obj::integer_ref l, obj::real_ref r); - - f64 min(object_ref l, f64 r); - f64 min(f64 l, object_ref r); + object_ref min(object_ref const l, object_ref const r); + object_ref min(obj::integer_ref const l, object_ref const r); + object_ref min(object_ref const l, obj::integer_ref const r); + i64 min(obj::integer_ref const l, obj::integer_ref const r); + f64 min(obj::real_ref const l, obj::real_ref const r); + f64 min(obj::real_ref const l, object_ref const r); + f64 min(object_ref const l, obj::real_ref const r); + f64 min(obj::real_ref const l, obj::integer_ref const r); + f64 min(obj::integer_ref const l, obj::real_ref const r); + + f64 min(object_ref const l, f64 r); + f64 min(f64 l, object_ref const r); f64 min(f64 l, f64 r); f64 min(i64 l, f64 r); f64 min(f64 l, i64 r); - object_ref min(object_ref l, i64 r); - object_ref min(i64 l, object_ref r); + object_ref min(object_ref const l, i64 r); + object_ref min(i64 l, object_ref const r); i64 min(i64 l, i64 r); - object_ref max(object_ref l, object_ref r); - object_ref max(obj::integer_ref l, object_ref r); - object_ref max(object_ref l, obj::integer_ref r); - i64 max(obj::integer_ref l, obj::integer_ref r); - f64 max(obj::real_ref l, obj::real_ref r); - f64 max(obj::real_ref l, object_ref r); - f64 max(object_ref l, obj::real_ref r); - f64 max(obj::real_ref l, obj::integer_ref r); - f64 max(obj::integer_ref l, obj::real_ref r); - - object_ref max(object_ref l, f64 r); - object_ref max(f64 l, object_ref r); + object_ref max(object_ref const l, object_ref const r); + object_ref max(obj::integer_ref const l, object_ref const r); + object_ref max(object_ref const l, obj::integer_ref const r); + i64 max(obj::integer_ref const l, obj::integer_ref const r); + f64 max(obj::real_ref const l, obj::real_ref const r); + f64 max(obj::real_ref const l, object_ref const r); + f64 max(object_ref const l, obj::real_ref const r); + f64 max(obj::real_ref const l, obj::integer_ref const r); + f64 max(obj::integer_ref const l, obj::real_ref const r); + + object_ref max(object_ref const l, f64 r); + object_ref max(f64 l, object_ref const r); f64 max(f64 l, f64 r); f64 max(i64 l, f64 r); f64 max(f64 l, i64 r); - object_ref max(object_ref l, i64 r); - object_ref max(i64 l, object_ref r); + object_ref max(object_ref const l, i64 r); + object_ref max(i64 l, object_ref const r); i64 max(i64 l, i64 r); - object_ref abs(object_ref l); - i64 abs(obj::integer_ref l); - f64 abs(obj::real_ref l); + object_ref abs(object_ref const l); + i64 abs(obj::integer_ref const l); + f64 abs(obj::real_ref const l); i64 abs(i64 l); f64 abs(f64 l); - f64 tan(object_ref l); + f64 tan(object_ref const l); - f64 sqrt(object_ref l); - f64 sqrt(obj::integer_ref l); - f64 sqrt(obj::real_ref l); + f64 sqrt(object_ref const l); + f64 sqrt(obj::integer_ref const l); + f64 sqrt(obj::real_ref const l); f64 sqrt(i64 l); f64 sqrt(f64 l); - f64 pow(object_ref l, object_ref r); - f64 pow(obj::integer_ref l, object_ref r); - f64 pow(object_ref l, obj::integer_ref r); - f64 pow(obj::integer_ref l, obj::integer_ref r); - f64 pow(obj::real_ref l, obj::real_ref r); - f64 pow(obj::real_ref l, object_ref r); - f64 pow(object_ref l, obj::real_ref r); - f64 pow(obj::real_ref l, obj::integer_ref r); - f64 pow(obj::integer_ref l, obj::real_ref r); - - object_ref pow(object_ref l, f64 r); - object_ref pow(f64 l, object_ref r); + f64 pow(object_ref const l, object_ref const r); + f64 pow(obj::integer_ref const l, object_ref const r); + f64 pow(object_ref const l, obj::integer_ref const r); + f64 pow(obj::integer_ref const l, obj::integer_ref const r); + f64 pow(obj::real_ref const l, obj::real_ref const r); + f64 pow(obj::real_ref const l, object_ref const r); + f64 pow(object_ref const l, obj::real_ref const r); + f64 pow(obj::real_ref const l, obj::integer_ref const r); + f64 pow(obj::integer_ref const l, obj::real_ref const r); + + object_ref pow(object_ref const l, f64 r); + object_ref pow(f64 l, object_ref const r); f64 pow(f64 l, f64 r); f64 pow(i64 l, f64 r); f64 pow(f64 l, i64 r); - f64 pow(object_ref l, i64 r); - f64 pow(i64 l, object_ref r); + f64 pow(object_ref const l, i64 r); + f64 pow(i64 l, object_ref const r); f64 pow(i64 l, i64 r); - object_ref rem(object_ref l, object_ref r); - object_ref quot(object_ref l, object_ref r); - object_ref inc(object_ref l); + object_ref rem(object_ref const l, object_ref const r); + object_ref quot(object_ref const l, object_ref const r); + object_ref inc(object_ref const l); object_ref promoting_inc(object_ref const l); - object_ref dec(object_ref l); + object_ref dec(object_ref const l); object_ref promoting_dec(object_ref const l); - bool is_zero(object_ref l); - bool is_pos(object_ref l); - bool is_neg(object_ref l); - bool is_even(object_ref l); - bool is_odd(object_ref l); - - bool is_equiv(object_ref l, object_ref r); - - i64 bit_not(object_ref l); - i64 bit_and(object_ref l, object_ref r); - i64 bit_or(object_ref l, object_ref r); - i64 bit_xor(object_ref l, object_ref r); - i64 bit_and_not(object_ref l, object_ref r); - i64 bit_clear(object_ref l, object_ref r); - i64 bit_set(object_ref l, object_ref r); - i64 bit_flip(object_ref l, object_ref r); - bool bit_test(object_ref l, object_ref r); - i64 bit_shift_left(object_ref l, object_ref r); - i64 bit_shift_right(object_ref l, object_ref r); - i64 bit_unsigned_shift_right(object_ref l, object_ref r); + bool is_zero(object_ref const l); + bool is_pos(object_ref const l); + bool is_neg(object_ref const l); + bool is_even(object_ref const l); + bool is_odd(object_ref const l); + + bool is_equiv(object_ref const l, object_ref const r); + + i64 bit_not(object_ref const l); + i64 bit_and(object_ref const l, object_ref const r); + i64 bit_or(object_ref const l, object_ref const r); + i64 bit_xor(object_ref const l, object_ref const r); + i64 bit_and_not(object_ref const l, object_ref const r); + i64 bit_clear(object_ref const l, object_ref const r); + i64 bit_set(object_ref const l, object_ref const r); + i64 bit_flip(object_ref const l, object_ref const r); + bool bit_test(object_ref const l, object_ref const r); + i64 bit_shift_left(object_ref const l, object_ref const r); + i64 bit_shift_right(object_ref const l, object_ref const r); + i64 bit_unsigned_shift_right(object_ref const l, object_ref const r); f64 rand(); - native_big_integer numerator(object_ref o); - native_big_integer denominator(object_ref o); + native_big_integer numerator(object_ref const o); + native_big_integer denominator(object_ref const o); - i64 to_int(object_ref l); - i64 to_int(obj::integer_ref l); - i64 to_int(obj::real_ref l); + i64 to_int(object_ref const l); + i64 to_int(obj::integer_ref const l); + i64 to_int(obj::real_ref const l); i64 to_int(i64 l); i64 to_int(f64 l); - f64 to_real(object_ref o); + f64 to_real(object_ref const o); - bool is_number(object_ref o); + bool is_number(object_ref const o); object_ref number(object_ref const o); - bool is_integer(object_ref o); - bool is_real(object_ref o); - bool is_ratio(object_ref o); - bool is_boolean(object_ref o); - bool is_nan(object_ref o); - bool is_infinite(object_ref o); + bool is_integer(object_ref const o); + bool is_real(object_ref const o); + bool is_ratio(object_ref const o); + bool is_boolean(object_ref const o); + bool is_nan(object_ref const o); + bool is_infinite(object_ref const o); - i64 parse_long(object_ref o); - f64 parse_double(object_ref o); + i64 parse_long(object_ref const o); + f64 parse_double(object_ref const o); bool is_big_integer(object_ref const o); obj::big_integer_ref to_big_integer(object_ref const o); diff --git a/compiler+runtime/include/cpp/jank/runtime/core/meta.hpp b/compiler+runtime/include/cpp/jank/runtime/core/meta.hpp index 971ab226d..1481eaf8d 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/meta.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/meta.hpp @@ -12,16 +12,16 @@ namespace jank::runtime using persistent_hash_map_ref = oref; } - object_ref meta(object_ref m); - object_ref with_meta(object_ref o, object_ref m); - object_ref with_meta_graceful(object_ref o, object_ref m); - object_ref reset_meta(object_ref o, object_ref m); + object_ref meta(object_ref const m); + object_ref with_meta(object_ref const o, object_ref const m); + object_ref with_meta_graceful(object_ref const o, object_ref const m); + object_ref reset_meta(object_ref const o, object_ref const m); read::source meta_source(jtl::option const &o); read::source object_source(object_ref const o); obj::persistent_hash_map_ref source_to_meta(read::source const &source); obj::persistent_hash_map_ref source_to_meta(read::source_position const &start, read::source_position const &end); - object_ref strip_source_from_meta(object_ref meta); + object_ref strip_source_from_meta(object_ref const meta); jtl::option strip_source_from_meta_opt(jtl::option const &meta); } diff --git a/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp b/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp index 38e04cbd9..6f6177e18 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp @@ -8,6 +8,6 @@ namespace jank::runtime jtl::immutable_string munge_and_replace(jtl::immutable_string const &o, jtl::immutable_string const &search, char const * const replace); - object_ref munge(object_ref o); + object_ref munge(object_ref const o); jtl::immutable_string demunge(jtl::immutable_string const &o); } diff --git a/compiler+runtime/include/cpp/jank/runtime/core/seq.hpp b/compiler+runtime/include/cpp/jank/runtime/core/seq.hpp index 4622c1945..a3bb3a50f 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/seq.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/seq.hpp @@ -14,157 +14,157 @@ namespace jank::runtime template requires behavior::seqable - auto seq(jtl::ref const s) + auto seq(oref const &s) { return s->seq(); } - object_ref seq(object_ref s); + object_ref seq(object_ref const s); template requires behavior::seqable - auto fresh_seq(jtl::ref const s) + auto fresh_seq(oref const &s) { return s->fresh_seq(); } - object_ref fresh_seq(object_ref s); + object_ref fresh_seq(object_ref const s); template requires behavior::sequenceable - auto next(jtl::ref const s) + auto next(oref const &s) { return s->next(); } - object_ref next(object_ref s); + object_ref next(object_ref const s); template requires behavior::sequenceable_in_place - auto next_in_place(jtl::ref const s) + auto next_in_place(oref const &s) { return s->next_in_place(); } template requires(behavior::sequenceable && !behavior::sequenceable_in_place) - auto next_in_place(jtl::ref const s) + auto next_in_place(oref const &s) { /* Not all sequences can be updated in place. For those, just gracefully * do a normal next. */ return s->next(); } - object_ref next_in_place(object_ref s); + object_ref next_in_place(object_ref const s); - object_ref rest(object_ref s); + object_ref rest(object_ref const s); template requires behavior::sequenceable - auto first(jtl::ref const s) + auto first(oref const &s) { return s->first(); } - object_ref first(object_ref s); + object_ref first(object_ref const s); template requires behavior::sequenceable - auto second(jtl::ref const s) + auto second(oref const &s) { return next(s)->first(); } - object_ref second(object_ref s); - - bool is_empty(object_ref o); - bool is_seq(object_ref o); - bool is_sequential(object_ref o); - bool is_seqable(object_ref o); - bool is_collection(object_ref o); - bool is_list(object_ref o); - bool is_vector(object_ref o); - bool is_map(object_ref o); - bool is_associative(object_ref o); - bool is_set(object_ref o); - bool is_counted(object_ref o); - bool is_transientable(object_ref o); - bool is_sorted(object_ref o); - - object_ref transient(object_ref o); - object_ref persistent(object_ref o); - object_ref conj_in_place(object_ref coll, object_ref o); - object_ref disj_in_place(object_ref coll, object_ref o); + object_ref second(object_ref const s); + + bool is_empty(object_ref const o); + bool is_seq(object_ref const o); + bool is_sequential(object_ref const o); + bool is_seqable(object_ref const o); + bool is_collection(object_ref const o); + bool is_list(object_ref const o); + bool is_vector(object_ref const o); + bool is_map(object_ref const o); + bool is_associative(object_ref const o); + bool is_set(object_ref const o); + bool is_counted(object_ref const o); + bool is_transientable(object_ref const o); + bool is_sorted(object_ref const o); + + object_ref transient(object_ref const o); + object_ref persistent(object_ref const o); + object_ref conj_in_place(object_ref const coll, object_ref const o); + object_ref disj_in_place(object_ref const coll, object_ref const o); template requires behavior::associatively_writable_in_place - auto assoc_in_place(oref const m, object_ref const k, object_ref const v) + auto assoc_in_place(oref const &m, object_ref const k, object_ref const v) { return m->assoc_in_place(k, v); } - object_ref assoc_in_place(object_ref coll, object_ref k, object_ref v); - object_ref dissoc_in_place(object_ref coll, object_ref k); - object_ref pop_in_place(object_ref coll); + object_ref assoc_in_place(object_ref const coll, object_ref const k, object_ref const v); + object_ref dissoc_in_place(object_ref const coll, object_ref const k); + object_ref pop_in_place(object_ref const coll); - object_ref cons(object_ref head, object_ref tail); - object_ref conj(object_ref s, object_ref o); - object_ref disj(object_ref s, object_ref o); + object_ref cons(object_ref const head, object_ref const tail); + object_ref conj(object_ref const s, object_ref const o); + object_ref disj(object_ref const s, object_ref const o); template requires behavior::associatively_writable - auto assoc(oref const m, object_ref const k, object_ref const v) + auto assoc(oref const &m, object_ref const k, object_ref const v) { return m->assoc(k, v); } - object_ref assoc(object_ref m, object_ref k, object_ref v); - object_ref dissoc(object_ref m, object_ref k); - object_ref get(object_ref m, object_ref key); - object_ref get(object_ref m, object_ref key, object_ref fallback); - object_ref get_in(object_ref m, object_ref keys); - object_ref get_in(object_ref m, object_ref keys, object_ref fallback); - object_ref find(object_ref s, object_ref key); - bool contains(object_ref s, object_ref key); - object_ref merge(object_ref m, object_ref other); - object_ref merge_in_place(object_ref m, object_ref other); - object_ref subvec(object_ref o, i64 start, i64 end); - object_ref nth(object_ref o, object_ref idx); - object_ref nth(object_ref o, object_ref idx, object_ref fallback); - object_ref peek(object_ref o); - object_ref pop(object_ref o); - object_ref empty(object_ref o); - - jtl::immutable_string str(object_ref o); - jtl::immutable_string str(object_ref o, object_ref args); - - obj::persistent_list_ref list(object_ref s); - obj::persistent_vector_ref vec(object_ref s); - - bool sequence_equal(object_ref l, object_ref r); + object_ref assoc(object_ref const m, object_ref const k, object_ref const v); + object_ref dissoc(object_ref const m, object_ref const k); + object_ref get(object_ref const m, object_ref const key); + object_ref get(object_ref const m, object_ref const key, object_ref const fallback); + object_ref get_in(object_ref const m, object_ref const keys); + object_ref get_in(object_ref const m, object_ref const keys, object_ref const fallback); + object_ref find(object_ref const s, object_ref const key); + bool contains(object_ref const s, object_ref const key); + object_ref merge(object_ref const m, object_ref const other); + object_ref merge_in_place(object_ref const m, object_ref const other); + object_ref subvec(object_ref const o, i64 start, i64 end); + object_ref nth(object_ref const o, object_ref const idx); + object_ref nth(object_ref const o, object_ref const idx, object_ref const fallback); + object_ref peek(object_ref const o); + object_ref pop(object_ref const o); + object_ref empty(object_ref const o); + + jtl::immutable_string str(object_ref const o); + jtl::immutable_string str(object_ref const o, object_ref const args); + + obj::persistent_list_ref list(object_ref const s); + obj::persistent_vector_ref vec(object_ref const s); + + bool sequence_equal(object_ref const l, object_ref const r); usize sequence_length(object_ref const s); usize sequence_length(object_ref const s, usize const max); - object_ref reduce(object_ref f, object_ref init, object_ref s); - object_ref reduced(object_ref o); - bool is_reduced(object_ref o); + object_ref reduce(object_ref const f, object_ref const init, object_ref const s); + object_ref reduced(object_ref const o); + bool is_reduced(object_ref const o); - object_ref chunk_buffer(object_ref capacity); - object_ref chunk_append(object_ref buff, object_ref val); - object_ref chunk(object_ref buff); - object_ref chunk_first(object_ref o); - object_ref chunk_next(object_ref o); - object_ref chunk_rest(object_ref o); - object_ref chunk_cons(object_ref chunk, object_ref rest); - bool is_chunked_seq(object_ref o); + object_ref chunk_buffer(object_ref const capacity); + object_ref chunk_append(object_ref const buff, object_ref const val); + object_ref chunk(object_ref const buff); + object_ref chunk_first(object_ref const o); + object_ref chunk_next(object_ref const o); + object_ref chunk_rest(object_ref const o); + object_ref chunk_cons(object_ref const chunk, object_ref const rest); + bool is_chunked_seq(object_ref const o); - object_ref iterate(object_ref fn, object_ref o); + object_ref iterate(object_ref const fn, object_ref const o); - object_ref repeat(object_ref val); - object_ref repeat(object_ref n, object_ref val); + object_ref repeat(object_ref const val); + object_ref repeat(object_ref const n, object_ref const val); - object_ref sort(object_ref coll); + object_ref sort(object_ref const coll); - object_ref shuffle(object_ref coll); + object_ref shuffle(object_ref const coll); } diff --git a/compiler+runtime/include/cpp/jank/runtime/core/seq_ext.hpp b/compiler+runtime/include/cpp/jank/runtime/core/seq_ext.hpp index 4ec98e53e..887e1afe6 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/seq_ext.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/seq_ext.hpp @@ -10,11 +10,11 @@ namespace jank::runtime { template - bool equal(object const &o, It const begin, It const end) + bool equal(object const &o, It const &begin, It const &end) { return visit_seqable( - [](auto const typed_o, auto const begin, auto const end) -> bool { - using T = typename decltype(typed_o)::value_type; + [](auto const typed_o, auto const &begin, auto const &end) -> bool { + using T = typename jtl::decay_t::value_type; /* nil is seqable, but we don't want it to be equal to an empty collection. An empty seq itself is nil, but that's different. */ @@ -45,7 +45,7 @@ namespace jank::runtime template requires behavior::sequenceable - auto rest(oref const seq) + auto rest(oref const &seq) { if(seq.is_nil()) { diff --git a/compiler+runtime/include/cpp/jank/runtime/core/to_string.hpp b/compiler+runtime/include/cpp/jank/runtime/core/to_string.hpp index 3a2fca274..a976f2e99 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/to_string.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/to_string.hpp @@ -5,20 +5,20 @@ namespace jank::runtime { - object_ref first(object_ref s); - object_ref next(object_ref s); + object_ref first(object_ref const s); + object_ref next(object_ref const s); jtl::immutable_string to_string(object_ref const o); void to_string(char ch, jtl::string_builder &buff); - void to_string(object_ref o, jtl::string_builder &buff); + void to_string(object_ref const o, jtl::string_builder &buff); jtl::immutable_string to_code_string(object_ref const o); void to_code_string(char ch, jtl::string_builder &buff); - void to_code_string(object_ref o, jtl::string_builder &buff); + void to_code_string(object_ref const o, jtl::string_builder &buff); template requires(behavior::object_like && !behavior::sequenceable) - void to_string(oref const s, jtl::string_builder &buff) + void to_string(oref const &s, jtl::string_builder &buff) { s->to_string(buff); } @@ -48,7 +48,7 @@ namespace jank::runtime template requires behavior::sequenceable - void to_string(oref const s, jtl::string_builder &buff) + void to_string(oref const &s, jtl::string_builder &buff) { if(s.is_nil()) { @@ -87,7 +87,7 @@ namespace jank::runtime template requires behavior::sequenceable - jtl::immutable_string to_string(oref const s) + jtl::immutable_string to_string(oref const &s) { jtl::string_builder buff; runtime::to_string(s, buff); @@ -96,7 +96,7 @@ namespace jank::runtime template requires(behavior::object_like && !behavior::sequenceable) - void to_code_string(oref const s, jtl::string_builder &buff) + void to_code_string(oref const &s, jtl::string_builder &buff) { buff(s->to_code_string()); } @@ -126,7 +126,7 @@ namespace jank::runtime template requires behavior::sequenceable - void to_code_string(oref const s, jtl::string_builder &buff) + void to_code_string(oref const &s, jtl::string_builder &buff) { if(s.is_nil()) { @@ -165,7 +165,7 @@ namespace jank::runtime template requires behavior::sequenceable - jtl::immutable_string to_code_string(oref const s) + jtl::immutable_string to_code_string(oref const &s) { jtl::string_builder buff; runtime::to_code_string(s, buff); diff --git a/compiler+runtime/include/cpp/jank/runtime/core/truthy.hpp b/compiler+runtime/include/cpp/jank/runtime/core/truthy.hpp index 4eccaa19a..e90340380 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/truthy.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/truthy.hpp @@ -6,8 +6,8 @@ namespace jank::runtime { bool truthy(object const *o); - bool truthy(object_ref o); - bool truthy(obj::nil_ref); + bool truthy(object_ref const o); + bool truthy(obj::nil_ref const); bool truthy(obj::boolean_ref const o); bool truthy(bool const o); diff --git a/compiler+runtime/include/cpp/jank/runtime/detail/native_array_map.hpp b/compiler+runtime/include/cpp/jank/runtime/detail/native_array_map.hpp index daf2a73d9..f9aaaaea6 100644 --- a/compiler+runtime/include/cpp/jank/runtime/detail/native_array_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/detail/native_array_map.hpp @@ -30,11 +30,12 @@ namespace jank::runtime::detail template >> native_array_map(in_place_unique, jtl::ref const kvs, L const l) : data{ std::move(kvs.data) } + , cap{ static_cast(l) } , length{ static_cast(l) } { } - ~native_array_map() = default; + ~native_array_map(); void insert_unique(object_ref const key, object_ref const val); diff --git a/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp b/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp index 8eab57d00..a115e6602 100644 --- a/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp @@ -8,9 +8,6 @@ #include #include -#include -#include - #include #include @@ -36,15 +33,6 @@ namespace immer jank::memory_policy>; } -namespace bpptree::detail -{ - extern template struct BppTreeSet; - extern template struct BppTreeMap; -} - namespace jank::runtime::detail { using native_persistent_vector = immer::vector; @@ -54,11 +42,10 @@ namespace jank::runtime::detail set, std::equal_to, memory_policy>; using native_transient_hash_set = native_persistent_hash_set::transient_type; - /* TODO: These BppTree types will leak until we get them GC allocated. */ + /* TODO: Bring in proper immutable sorted maps/sets. */ using native_persistent_sorted_set - = bpptree::BppTreeSet::Persistent; - using native_transient_sorted_set - = bpptree::BppTreeSet::Transient; + = std::set>; + using native_transient_sorted_set = native_persistent_sorted_set; using native_persistent_hash_map = immer::map::Persistent; - using native_transient_sorted_map - = bpptree::BppTreeMap::Transient; + = std::map>>; + using native_transient_sorted_map = native_persistent_sorted_map; /* If an object requires this in its constructor, use your runtime context to intern * it instead. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/ns.hpp b/compiler+runtime/include/cpp/jank/runtime/ns.hpp index 56eb0ee0b..90c0f8ad8 100644 --- a/compiler+runtime/include/cpp/jank/runtime/ns.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/ns.hpp @@ -15,7 +15,7 @@ namespace jank::runtime using ns_ref = oref; - struct ns : gc + struct ns { static constexpr object_type obj_type{ object_type::ns }; static constexpr bool pointer_free{ false }; @@ -24,17 +24,17 @@ namespace jank::runtime ns(obj::symbol_ref const name); var_ref intern_var(jtl::immutable_string_view const &); - var_ref intern_var(obj::symbol_ref); + var_ref intern_var(obj::symbol_ref const); var_ref intern_owned_var(jtl::immutable_string_view const &); - var_ref intern_owned_var(obj::symbol_ref); - var_ref find_var(obj::symbol_ref); - jtl::result unmap(obj::symbol_ref sym); + var_ref intern_owned_var(obj::symbol_ref const); + var_ref find_var(obj::symbol_ref const); + jtl::result unmap(obj::symbol_ref const sym); - jtl::result add_alias(obj::symbol_ref sym, ns_ref ns); - void remove_alias(obj::symbol_ref sym); - ns_ref find_alias(obj::symbol_ref sym) const; + jtl::result add_alias(obj::symbol_ref const sym, ns_ref const ns); + void remove_alias(obj::symbol_ref const sym); + ns_ref find_alias(obj::symbol_ref const sym) const; - jtl::result refer(obj::symbol_ref sym, var_ref var); + jtl::result refer(obj::symbol_ref const sym, var_ref const var); obj::persistent_hash_map_ref get_mappings() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/array_chunk.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/array_chunk.hpp index c51f9a2f5..9c65eeea9 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/array_chunk.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/array_chunk.hpp @@ -6,7 +6,7 @@ namespace jank::runtime::obj { using array_chunk_ref = oref; - struct array_chunk : gc + struct array_chunk { static constexpr object_type obj_type{ object_type::array_chunk }; static constexpr bool pointer_free{ false }; @@ -27,8 +27,8 @@ namespace jank::runtime::obj array_chunk_ref chunk_next() const; array_chunk_ref chunk_next_in_place(); usize count() const; - object_ref nth(object_ref index) const; - object_ref nth(object_ref index, object_ref fallback) const; + object_ref nth(object_ref const index) const; + object_ref nth(object_ref const index, object_ref const fallback) const; object base{ obj_type }; native_vector buffer; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/atom.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/atom.hpp index 622ee06e1..435163ecc 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/atom.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/atom.hpp @@ -3,20 +3,20 @@ #include #include +#include +#include namespace jank::runtime::obj { using atom_ref = oref; - using persistent_vector_ref = oref; - using persistent_hash_map_ref = oref; - struct atom : gc + struct atom { static constexpr object_type obj_type{ object_type::atom }; static constexpr bool pointer_free{ false }; atom() = default; - atom(object_ref o); + atom(object_ref const o); /* behavior::object_like */ bool equal(object const &) const; @@ -29,29 +29,34 @@ namespace jank::runtime::obj object_ref deref() const; /* Replaces the old value with the specified value. Returns the new value. */ - object_ref reset(object_ref o); + object_ref reset(object_ref const o); /* Same as reset, but returns a vector of the old value and the new value. */ - persistent_vector_ref reset_vals(object_ref o); + persistent_vector_ref reset_vals(object_ref const o); /* Atomically updates the value of the atom with the specified fn. Returns the new value. */ - object_ref swap(object_ref fn); - object_ref swap(object_ref fn, object_ref a1); - object_ref swap(object_ref fn, object_ref a1, object_ref a2); - object_ref swap(object_ref fn, object_ref a1, object_ref a2, object_ref rest); + object_ref swap(object_ref const fn); + object_ref swap(object_ref const fn, object_ref const a1); + object_ref swap(object_ref const fn, object_ref const a1, object_ref const a2); + object_ref + swap(object_ref const fn, object_ref const a1, object_ref const a2, object_ref const rest); /* Same as swap, but returns a vector of the old value and the new value. */ - persistent_vector_ref swap_vals(object_ref fn); - persistent_vector_ref swap_vals(object_ref fn, object_ref a1); - persistent_vector_ref swap_vals(object_ref fn, object_ref a1, object_ref a2); - persistent_vector_ref swap_vals(object_ref fn, object_ref a1, object_ref a2, object_ref rest); + persistent_vector_ref swap_vals(object_ref const fn); + persistent_vector_ref swap_vals(object_ref const fn, object_ref const a1); + persistent_vector_ref swap_vals(object_ref const fn, object_ref const a1, object_ref const a2); + persistent_vector_ref + swap_vals(object_ref const fn, object_ref const a1, object_ref const a2, object_ref const rest); - object_ref compare_and_set(object_ref old_val, object_ref new_val); + object_ref compare_and_set(object_ref const old_val, object_ref const new_val); /* behavior::ref_like */ - void add_watch(object_ref key, object_ref fn); - void remove_watch(object_ref key); + void add_watch(object_ref const key, object_ref const fn); + void remove_watch(object_ref const key); object base{ obj_type }; + /* We have to hold only a raw pointer here, since std::atomic doesn't + * support more complex types. However, that means we need to manually + * handle reference counting for held values when swapping, resetting, etc. */ std::atomic val{}; /* Since watches is a 'persistent_hash_map", there in no guarantee in which * order watches are invoked. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/big_decimal.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/big_decimal.hpp index 5a8c0b2cb..03fddd534 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/big_decimal.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/big_decimal.hpp @@ -32,7 +32,7 @@ namespace jank::runtime::obj struct ratio; - struct big_decimal : gc + struct big_decimal { static constexpr object_type obj_type{ object_type::big_decimal }; static constexpr bool pointer_free{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/big_integer.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/big_integer.hpp index dfd88120c..a6bf1097d 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/big_integer.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/big_integer.hpp @@ -30,7 +30,7 @@ namespace jank::runtime::obj { using big_integer_ref = oref; - struct big_integer : gc + struct big_integer { static constexpr object_type obj_type{ object_type::big_integer }; static constexpr bool pointer_free{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/character.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/character.hpp index 9bb3245f7..cf88e79c9 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/character.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/character.hpp @@ -6,7 +6,7 @@ namespace jank::runtime::obj { using character_ref = oref; - struct character : gc + struct character { static constexpr object_type obj_type{ object_type::character }; static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/chunk_buffer.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/chunk_buffer.hpp index e1cb56d42..d13274750 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/chunk_buffer.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/chunk_buffer.hpp @@ -7,14 +7,14 @@ namespace jank::runtime::obj using array_chunk_ref = oref; using chunk_buffer_ref = oref; - struct chunk_buffer : gc + struct chunk_buffer { static constexpr object_type obj_type{ object_type::chunk_buffer }; static constexpr bool pointer_free{ false }; chunk_buffer() = default; chunk_buffer(usize capacity); - chunk_buffer(object_ref capacity); + chunk_buffer(object_ref const capacity); /* behavior::object_like */ bool equal(object const &) const; @@ -26,7 +26,7 @@ namespace jank::runtime::obj /* behavior::countable */ usize count() const; - void append(object_ref o); + void append(object_ref const o); obj::array_chunk_ref chunk(); object base{ obj_type }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/chunked_cons.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/chunked_cons.hpp index d4cc84e27..ab49f1fa5 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/chunked_cons.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/chunked_cons.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using cons_ref = oref; using chunked_cons_ref = oref; - struct chunked_cons : gc + struct chunked_cons { static constexpr object_type obj_type{ object_type::chunked_cons }; static constexpr bool pointer_free{ false }; @@ -18,8 +18,8 @@ namespace jank::runtime::obj chunked_cons() = default; chunked_cons(chunked_cons &&) noexcept = default; chunked_cons(chunked_cons const &) = default; - chunked_cons(object_ref head, object_ref tail); - chunked_cons(object_ref meta, object_ref head, object_ref tail); + chunked_cons(object_ref const head, object_ref const tail); + chunked_cons(object_ref const meta, object_ref const head, object_ref const tail); /* behavior::object_like */ bool equal(object const &) const; @@ -29,7 +29,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - chunked_cons_ref with_meta(object_ref m) const; + chunked_cons_ref with_meta(object_ref const m) const; /* behavior::seqable */ chunked_cons_ref seq() const; @@ -38,7 +38,7 @@ namespace jank::runtime::obj /* behavior::sequenceable */ object_ref first() const; object_ref next() const; - obj::cons_ref conj(object_ref head) const; + obj::cons_ref conj(object_ref const head) const; /* behavior::sequenceable_in_place */ chunked_cons_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/cons.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/cons.hpp index ce1728b0c..9264f6885 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/cons.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/cons.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj { using cons_ref = oref; - struct cons : gc + struct cons { static constexpr object_type obj_type{ object_type::cons }; static constexpr bool pointer_free{ false }; @@ -27,7 +27,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - cons_ref with_meta(object_ref m) const; + cons_ref with_meta(object_ref const m) const; /* behavior::seqable */ cons_ref seq() const; @@ -38,7 +38,7 @@ namespace jank::runtime::obj object_ref next() const; /* behavior::conjable */ - cons_ref conj(object_ref head) const; + cons_ref conj(object_ref const head) const; object base{ obj_type }; object_ref head{}; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/delay.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/delay.hpp index 1686d4604..e3d93fdb6 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/delay.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/delay.hpp @@ -6,13 +6,13 @@ namespace jank::runtime::obj { using delay_ref = oref; - struct delay : gc + struct delay { static constexpr object_type obj_type{ object_type::delay }; static constexpr bool pointer_free{ false }; delay() = default; - delay(object_ref fn); + delay(object_ref const fn); /* behavior::object_like */ bool equal(object const &) const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map.hpp index 7b5400d8c..0bdcd0b52 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map.hpp @@ -6,10 +6,10 @@ namespace jank::runtime { - bool is_map(object_ref o); - bool equal(object_ref l, object_ref r); - void to_string(object_ref o, jtl::string_builder &buff); - void to_code_string(object_ref o, jtl::string_builder &buff); + bool is_map(object_ref const o); + bool equal(object_ref const l, object_ref const r); + void to_string(object_ref const o, jtl::string_builder &buff); + void to_code_string(object_ref const o, jtl::string_builder &buff); namespace behavior::detail { @@ -22,7 +22,7 @@ namespace jank::runtime::obj::detail /* Array maps and hash maps share a lot of common code, so we have a common base. * No virtual fns are used, so this structure won't survive release optimizations. */ template - struct base_persistent_map : gc + struct base_persistent_map { static constexpr bool pointer_free{ false }; static constexpr bool is_map_like{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map_sequence.hpp index 00a75c3f4..b6ba03c67 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/detail/base_persistent_map_sequence.hpp @@ -5,8 +5,8 @@ namespace jank::runtime { - void to_string(object_ref o, jtl::string_builder &buff); - void to_code_string(object_ref o, jtl::string_builder &buff); + void to_string(object_ref const o, jtl::string_builder &buff); + void to_code_string(object_ref const o, jtl::string_builder &buff); namespace obj { @@ -17,7 +17,7 @@ namespace jank::runtime namespace jank::runtime::obj::detail { template - struct base_persistent_map_sequence : gc + struct base_persistent_map_sequence { static constexpr bool pointer_free{ false }; static constexpr bool is_sequential{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/detail/iterator_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/detail/iterator_sequence.hpp index 6dc8f22f4..a0672c7ea 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/detail/iterator_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/detail/iterator_sequence.hpp @@ -16,7 +16,7 @@ namespace jank::runtime::obj::detail iterator_sequence() = default; /* NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility) */ - iterator_sequence(object_ref const &c, It const &b, It const &e, usize const s); + iterator_sequence(object_ref const c, It const &b, It const &e, usize const s); /* behavior::object_like */ bool equal(object const &o) const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/inst.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/inst.hpp index 1ede41f1a..66f1ac589 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/inst.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/inst.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using inst_ref = oref; using inst_time_point = std::chrono::time_point; - struct inst : gc + struct inst { static constexpr object_type obj_type{ object_type::inst }; static constexpr bool pointer_free{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/integer_range.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/integer_range.hpp index 45b99a23a..73edde554 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/integer_range.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/integer_range.hpp @@ -18,18 +18,18 @@ namespace jank::runtime::obj static constexpr bool pointer_free{ false }; static constexpr bool is_sequential{ true }; - using bounds_check_t = bool (*)(integer_ref, integer_ref); + using bounds_check_t = bool (*)(integer_ref const, integer_ref const); /* Constructors are only to be used within integer_range.cpp. Prefer integer_range::create. */ integer_range() = default; integer_range(integer_range &&) noexcept = default; integer_range(integer_range const &) = default; - integer_range(integer_ref end); - integer_range(integer_ref start, obj::integer_ref end); - integer_range(integer_ref start, obj::integer_ref end, obj::integer_ref step); - integer_range(integer_ref start, - integer_ref end, - integer_ref step, + integer_range(integer_ref const end); + integer_range(integer_ref const start, obj::integer_ref const end); + integer_range(integer_ref const start, obj::integer_ref const end, obj::integer_ref const step); + integer_range(integer_ref const start, + integer_ref const end, + integer_ref const step, bounds_check_t bounds_check); //integer_range(integer_ptr start, // integer_ptr end, @@ -38,9 +38,10 @@ namespace jank::runtime::obj // array_chunk_ptr chunk, // integer_range_ptr chunk_next); - static object_ref create(integer_ref end); - static object_ref create(integer_ref start, obj::integer_ref end); - static object_ref create(integer_ref start, obj::integer_ref end, obj::integer_ref step); + static object_ref create(integer_ref const end); + static object_ref create(integer_ref const start, obj::integer_ref const end); + static object_ref + create(integer_ref const start, obj::integer_ref const end, obj::integer_ref const step); /* behavior::object_like */ bool equal(object const &) const; @@ -66,10 +67,10 @@ namespace jank::runtime::obj /* void force_chunk() const; */ /* behavior::conjable */ - cons_ref conj(object_ref head) const; + cons_ref conj(object_ref const head) const; /* behavior::metadatable */ - integer_range_ref with_meta(object_ref m) const; + integer_range_ref with_meta(object_ref const m) const; /* behavior::countable */ usize count() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/iterator.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/iterator.hpp index 2ed4522d3..857bf0f33 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/iterator.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/iterator.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using iterator_ref = oref; /* TODO: Rename to iterator_sequence. */ - struct iterator : gc + struct iterator { static constexpr object_type obj_type{ object_type::iterator }; static constexpr bool pointer_free{ false }; @@ -34,7 +34,7 @@ namespace jank::runtime::obj /* behavior::sequenceable */ object_ref first() const; iterator_ref next() const; - obj::cons_ref conj(object_ref head) const; + obj::cons_ref conj(object_ref const head) const; /* behavior::sequenceable_in_place */ iterator_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/jit_closure.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/jit_closure.hpp index a4187acb1..c9fdd944a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/jit_closure.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/jit_closure.hpp @@ -7,9 +7,7 @@ namespace jank::runtime::obj { using jit_closure_ref = oref; - struct jit_closure - : gc - , behavior::callable + struct jit_closure : behavior::callable { static constexpr object_type obj_type{ object_type::jit_closure }; static constexpr bool pointer_free{ false }; @@ -18,7 +16,7 @@ namespace jank::runtime::obj jit_closure(jit_closure &&) noexcept = default; jit_closure(jit_closure const &) = default; jit_closure(arity_flag_t arity_flags, void *context); - jit_closure(object_ref meta); + jit_closure(object_ref const meta); /* behavior::object_like */ bool equal(object const &) const; @@ -28,46 +26,59 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - jit_closure_ref with_meta(object_ref m); + jit_closure_ref with_meta(object_ref const m); /* behavior::callable */ object_ref call() final; - object_ref call(object_ref) final; - object_ref call(object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) final; - object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) - final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; + object_ref call(object_ref const) final; + object_ref call(object_ref const, object_ref const) final; + object_ref call(object_ref const, object_ref const, object_ref const) final; + object_ref call(object_ref const, object_ref const, object_ref const, object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; arity_flag_t get_arity_flags() const final; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/jit_function.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/jit_function.hpp index b36d62b6a..84960c689 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/jit_function.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/jit_function.hpp @@ -7,9 +7,7 @@ namespace jank::runtime::obj { using jit_function_ref = oref; - struct jit_function - : gc - , behavior::callable + struct jit_function : behavior::callable { static constexpr object_type obj_type{ object_type::jit_function }; static constexpr bool pointer_free{ false }; @@ -18,7 +16,7 @@ namespace jank::runtime::obj jit_function(jit_function &&) noexcept = default; jit_function(jit_function const &) = default; jit_function(arity_flag_t arity_flags); - jit_function(object_ref meta); + jit_function(object_ref const meta); /* behavior::object_like */ bool equal(object const &) const; @@ -28,47 +26,60 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - jit_function_ref with_meta(object_ref m); + jit_function_ref with_meta(object_ref const m); /* behavior::callable */ object_ref call() override; - object_ref call(object_ref) override; - object_ref call(object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref) override; + object_ref call(object_ref const) override; + object_ref call(object_ref const, object_ref const) override; + object_ref call(object_ref const, object_ref const, object_ref const) override; object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) override; - object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) - override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; + call(object_ref const, object_ref const, object_ref const, object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; arity_flag_t get_arity_flags() const override; object_ref this_object_ref() override; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/keyword.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/keyword.hpp index 73b260716..bbe54dc41 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/keyword.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/keyword.hpp @@ -1,16 +1,13 @@ #pragma once #include +#include #include namespace jank::runtime::obj { - using persistent_array_map_ref = oref; - using symbol_ref = oref; - using keyword_ref = oref; - /* The correct way to create a keyword for normal use is through interning via the RT context. */ - struct keyword : gc + struct keyword { static constexpr object_type obj_type{ object_type::keyword }; static constexpr bool pointer_free{ false }; @@ -43,14 +40,16 @@ namespace jank::runtime::obj jtl::immutable_string const &get_namespace() const; /* behavior::callable */ - object_ref call(object_ref); - object_ref call(object_ref, object_ref); + object_ref call(object_ref const); + object_ref call(object_ref const, object_ref const); bool operator==(keyword const &rhs) const; object base{ obj_type }; symbol_ref sym; }; + + using keyword_ref = oref; } /* TODO: Move to .cpp */ @@ -59,7 +58,7 @@ namespace std template <> struct hash { - size_t operator()(jank::runtime::obj::keyword_ref const o) const noexcept + size_t operator()(jank::runtime::obj::keyword_ref const o) const { return o->to_hash(); } @@ -68,7 +67,7 @@ namespace std template <> struct hash { - size_t operator()(jank::runtime::obj::keyword const &o) const noexcept + size_t operator()(jank::runtime::obj::keyword const &o) const { static auto hasher(std::hash{}); return hasher(const_cast(&o)); @@ -78,8 +77,8 @@ namespace std template <> struct equal_to { - bool operator()(jank::runtime::obj::keyword_ref const &lhs, - jank::runtime::obj::keyword_ref const &rhs) const noexcept + bool operator()(jank::runtime::obj::keyword_ref const lhs, + jank::runtime::obj::keyword_ref const rhs) const noexcept { return lhs == rhs; } diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp index 919651d9b..ed1ff4483 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp @@ -11,7 +11,7 @@ namespace jank::runtime::obj using lazy_sequence_ref = oref; /* TODO: IPending analog, to implement `realized?`. */ - struct lazy_sequence : gc + struct lazy_sequence { static constexpr object_type obj_type{ object_type::lazy_sequence }; static constexpr bool pointer_free{ false }; @@ -20,8 +20,8 @@ namespace jank::runtime::obj lazy_sequence() = default; lazy_sequence(lazy_sequence &&) noexcept = default; lazy_sequence(lazy_sequence const &) = default; - lazy_sequence(object_ref fn); - lazy_sequence(object_ref fn, object_ref sequence); + lazy_sequence(object_ref const fn); + lazy_sequence(object_ref const fn, object_ref const sequence); /* behavior::object_like */ bool equal(object const &) const; @@ -37,13 +37,13 @@ namespace jank::runtime::obj /* behavior::sequenceable */ object_ref first() const; object_ref next() const; - obj::cons_ref conj(object_ref head) const; + obj::cons_ref conj(object_ref const head) const; /* behavior::sequenceable_in_place */ //lazy_sequence_ref next_in_place(); /* behavior::metadatable */ - lazy_sequence_ref with_meta(object_ref m) const; + lazy_sequence_ref with_meta(object_ref const m) const; private: object_ref resolve_fn() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/multi_function.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/multi_function.hpp index 13f00fa4c..48d6c5359 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/multi_function.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/multi_function.hpp @@ -11,15 +11,16 @@ namespace jank::runtime::obj using persistent_hash_map_ref = oref; using multi_function_ref = oref; - struct multi_function - : gc - , behavior::callable + struct multi_function : behavior::callable { static constexpr object_type obj_type{ object_type::multi_function }; static constexpr bool pointer_free{ false }; multi_function() = delete; - multi_function(object_ref name, object_ref dispatch, object_ref default_, object_ref hierarchy); + multi_function(object_ref const name, + object_ref const dispatch, + object_ref const default_, + object_ref const hierarchy); /* behavior::object_like */ bool equal(object const &) const; @@ -30,58 +31,71 @@ namespace jank::runtime::obj /* behavior::callable */ object_ref call() override; - object_ref call(object_ref) override; - object_ref call(object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref, object_ref) override; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref) override; + object_ref call(object_ref const) override; + object_ref call(object_ref const, object_ref const) override; + object_ref call(object_ref const, object_ref const, object_ref const) override; object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) override; - object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) - override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) override; + call(object_ref const, object_ref const, object_ref const, object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) override; object_ref this_object_ref() final; multi_function_ref reset(); persistent_hash_map_ref reset_cache(); - multi_function_ref add_method(object_ref dispatch_val, object_ref method); - multi_function_ref remove_method(object_ref dispatch_val); - multi_function_ref prefer_method(object_ref x, object_ref y); - bool is_preferred(object_ref hierarchy, object_ref x, object_ref y) const; + multi_function_ref add_method(object_ref const dispatch_val, object_ref const method); + multi_function_ref remove_method(object_ref const dispatch_val); + multi_function_ref prefer_method(object_ref const x, object_ref const y); + bool is_preferred(object_ref const hierarchy, object_ref const x, object_ref const y) const; - static bool is_a(object_ref hierarchy, object_ref x, object_ref y); - bool is_dominant(object_ref hierarchy, object_ref x, object_ref y) const; + static bool is_a(object_ref const hierarchy, object_ref const x, object_ref const y); + bool is_dominant(object_ref const hierarchy, object_ref const x, object_ref const y) const; - object_ref get_fn(object_ref dispatch_val); - object_ref get_method(object_ref dispatch_val); - object_ref find_and_cache_best_method(object_ref dispatch_val); + object_ref get_fn(object_ref const dispatch_val); + object_ref get_method(object_ref const dispatch_val); + object_ref find_and_cache_best_method(object_ref const dispatch_val); object base{ obj_type }; object_ref dispatch{}; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/native_array_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/native_array_sequence.hpp index 65b4df1f6..77e74a519 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/native_array_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/native_array_sequence.hpp @@ -7,7 +7,7 @@ namespace jank::runtime::obj using native_array_sequence_ref = oref; using cons_ref = oref; - struct native_array_sequence : gc + struct native_array_sequence { static constexpr object_type obj_type{ object_type::native_array_sequence }; static constexpr bool pointer_free{ false }; @@ -20,7 +20,7 @@ namespace jank::runtime::obj native_array_sequence(object_ref * const arr, usize const index, usize const size); template - native_array_sequence(object_ref const first, Args const... rest) + native_array_sequence(object_ref const first, Args const &...rest) : arr{ make_array_box(first, rest...) } , size{ sizeof...(Args) + 1 } { @@ -43,7 +43,7 @@ namespace jank::runtime::obj /* behavior::sequence */ object_ref first() const; native_array_sequence_ref next() const; - obj::cons_ref conj(object_ref head); + obj::cons_ref conj(object_ref const head); /* behavior::sequenceable_in_place */ native_array_sequence_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/native_function_wrapper.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/native_function_wrapper.hpp index 0b3be7035..41d2b6db2 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/native_function_wrapper.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/native_function_wrapper.hpp @@ -12,7 +12,7 @@ namespace jank::runtime { /* This must be constructed with a std::function object, since we need put it into a * std::any and pull it out based on how we call it. i.e. if we try to call it with - * one param, we try to grab it from the std::any as a std::function. + * one param, we try to grab it from the std::any as a std::function. * * This means you can't just dump a lambda into this. Build a std::function from it first. */ struct function_type @@ -64,9 +64,7 @@ namespace jank::runtime { using native_function_wrapper_ref = oref; - struct native_function_wrapper - : gc - , behavior::callable + struct native_function_wrapper : behavior::callable { static constexpr object_type obj_type{ object_type::native_function_wrapper }; static constexpr bool pointer_free{ false }; @@ -86,79 +84,64 @@ namespace jank::runtime /* behavior::callable */ object_ref call() final; - object_ref call(object_ref) final; - object_ref call(object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref) final; - object_ref call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) final; - object_ref - call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) - final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; - object_ref call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) final; + object_ref call(object_ref const) final; + object_ref call(object_ref const, object_ref const) final; + object_ref call(object_ref const, object_ref const, object_ref const) final; + object_ref call(object_ref const, object_ref const, object_ref const, object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; + object_ref call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) final; object_ref this_object_ref() final; /* behavior::metadatable */ - native_function_wrapper_ref with_meta(object_ref m) const; + native_function_wrapper_ref with_meta(object_ref const m) const; object base{ obj_type }; obj::detail::function_type data{}; jtl::option meta; }; } - - namespace detail - { - /* TODO: Is this needed, given dynamic_call? */ - template - object_ref invoke(F const &f, Args &&...args) - { - if constexpr(std::is_function_v>>) - { - return f(std::forward(args)...); - } - else - { - auto const * const c((*f)->as_callable()); - - if(c) - { - return c->call(std::forward(args)...); - } - else - { - /* TODO: Better error. */ - std::cout << "(invoke) object is not callable: " << **f << std::endl; - throw std::runtime_error{ "object is not callable" }; - } - } - } - } } diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/native_pointer_wrapper.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/native_pointer_wrapper.hpp index 353adde85..d2ab6d1c7 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/native_pointer_wrapper.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/native_pointer_wrapper.hpp @@ -6,7 +6,7 @@ namespace jank::runtime::obj { using native_pointer_wrapper_ref = oref; - struct native_pointer_wrapper : gc + struct native_pointer_wrapper { static constexpr object_type obj_type{ object_type::native_pointer_wrapper }; static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/native_vector_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/native_vector_sequence.hpp index a586e2e02..14ecdafcd 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/native_vector_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/native_vector_sequence.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using cons_ref = oref; using native_vector_sequence_ref = oref; - struct native_vector_sequence : gc + struct native_vector_sequence { static constexpr object_type obj_type{ object_type::native_vector_sequence }; static constexpr bool pointer_free{ false }; @@ -40,7 +40,7 @@ namespace jank::runtime::obj /* behavior::sequence */ object_ref first() const; native_vector_sequence_ref next() const; - obj::cons_ref conj(object_ref head); + obj::cons_ref conj(object_ref const head); /* behavior::sequenceable_in_place */ native_vector_sequence_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/nil.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/nil.hpp index 6aa29abe5..5f5c727c4 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/nil.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/nil.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj using cons_ref = oref; using nil_ref = oref; - struct nil : gc + struct nil { static constexpr object_type obj_type{ object_type::nil }; static constexpr bool pointer_free{ true }; @@ -31,12 +31,12 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key); object_ref get(object_ref const key, object_ref const fallback); - object_ref get_entry(object_ref key); - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key); + bool contains(object_ref const key) const; /* behavior::associatively_writable */ - obj::persistent_array_map_ref assoc(object_ref key, object_ref val) const; - nil_ref dissoc(object_ref key) const; + obj::persistent_array_map_ref assoc(object_ref const key, object_ref const val) const; + nil_ref dissoc(object_ref const key) const; /* behavior::seqable */ nil_ref seq(); @@ -58,12 +58,5 @@ namespace jank::runtime bool operator==(object *, obj::nil_ref); bool operator!=(object *, obj::nil_ref); - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - extern obj::nil_ref jank_nil; - - namespace detail - { - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - extern obj::nil *jank_nil_ptr; - } + obj::nil_ref jank_nil(); } diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/number.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/number.hpp index 1dbeacbe0..5bd22be4e 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/number.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/number.hpp @@ -6,7 +6,7 @@ namespace jank::runtime::obj { using boolean_ref = oref; - struct boolean : gc + struct boolean { static constexpr object_type obj_type{ object_type::boolean }; static constexpr bool pointer_free{ true }; @@ -39,7 +39,7 @@ namespace jank::runtime::obj using integer_ref = oref; - struct integer : gc + struct integer { static constexpr object_type obj_type{ object_type::integer }; static constexpr bool pointer_free{ true }; @@ -73,7 +73,7 @@ namespace jank::runtime::obj using real_ref = oref; - struct real : gc + struct real { static constexpr object_type obj_type{ object_type::real }; static constexpr bool pointer_free{ true }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/opaque_box.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/opaque_box.hpp index 3de3c3970..2c1ddc4ad 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/opaque_box.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/opaque_box.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj { using opaque_box_ref = oref; - struct opaque_box : gc + struct opaque_box { static constexpr object_type obj_type{ object_type::opaque_box }; static constexpr bool pointer_free{ false }; @@ -23,7 +23,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - opaque_box_ref with_meta(object_ref m); + opaque_box_ref with_meta(object_ref const m); object base{ obj_type }; jtl::ptr data{}; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_array_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_array_map.hpp index fb698099e..0bf8f6388 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_array_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_array_map.hpp @@ -70,16 +70,16 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable */ - object_ref assoc(object_ref key, object_ref val) const; - persistent_array_map_ref dissoc(object_ref key) const; + object_ref assoc(object_ref const key, object_ref const val) const; + persistent_array_map_ref dissoc(object_ref const key) const; /* behavior::callable */ - object_ref call(object_ref) const; - object_ref call(object_ref, object_ref) const; + object_ref call(object_ref const) const; + object_ref call(object_ref const, object_ref const) const; /* behavior::transientable */ transient_array_map_ref to_transient() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_map.hpp index 770ac4542..5a91e40b5 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_map.hpp @@ -29,8 +29,8 @@ namespace jank::runtime::obj persistent_hash_map(persistent_hash_map const &) = default; persistent_hash_map(jtl::option const &meta, runtime::detail::native_array_map const &m, - object_ref key, - object_ref val); + object_ref const key, + object_ref const val); persistent_hash_map(value_type &&d); persistent_hash_map(value_type const &d); persistent_hash_map(jtl::option const &meta, value_type &&d); @@ -48,11 +48,7 @@ namespace jank::runtime::obj this->meta = meta; } - static persistent_hash_map_ref empty() - { - static auto const ret(make_box()); - return ret; - } + static persistent_hash_map_ref empty(); using base_persistent_map::base_persistent_map; @@ -76,16 +72,16 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable */ - persistent_hash_map_ref assoc(object_ref key, object_ref val) const; - persistent_hash_map_ref dissoc(object_ref key) const; + persistent_hash_map_ref assoc(object_ref const key, object_ref const val) const; + persistent_hash_map_ref dissoc(object_ref const key) const; /* behavior::callable */ - object_ref call(object_ref) const; - object_ref call(object_ref, object_ref) const; + object_ref call(object_ref const) const; + object_ref call(object_ref const, object_ref const) const; /* behavior::transientable */ obj::transient_hash_map_ref to_transient() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set.hpp index 6dc4fee59..083b5af7a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using persistent_hash_set_ref = oref; using persistent_hash_set_sequence_ref = oref; - struct persistent_hash_set : gc + struct persistent_hash_set { static constexpr object_type obj_type{ object_type::persistent_hash_set }; static constexpr bool pointer_free{ false }; @@ -49,7 +49,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - persistent_hash_set_ref with_meta(object_ref m) const; + persistent_hash_set_ref with_meta(object_ref const m) const; /* behavior::seqable */ obj::persistent_hash_set_sequence_ref seq() const; @@ -59,16 +59,16 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable */ - persistent_hash_set_ref conj(object_ref head) const; + persistent_hash_set_ref conj(object_ref const head) const; /* behavior::callable */ - object_ref call(object_ref) const; + object_ref call(object_ref const) const; /* behavior::transientable */ obj::transient_hash_set_ref to_transient() const; - bool contains(object_ref o) const; - persistent_hash_set_ref disj(object_ref o) const; + bool contains(object_ref const o) const; + persistent_hash_set_ref disj(object_ref const o) const; object base{ obj_type }; value_type data; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set_sequence.hpp index 08c427dab..9d6de52bb 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_hash_set_sequence.hpp @@ -11,8 +11,7 @@ namespace jank::runtime::obj using persistent_hash_set_sequence_ref = oref; struct persistent_hash_set_sequence - : gc - , obj::detail::iterator_sequence { static constexpr object_type obj_type{ object_type::persistent_hash_set_sequence }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp index 1f20768cc..1719decae 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj using nil_ref = oref; using persistent_list_ref = oref; - struct persistent_list : gc + struct persistent_list { using value_type = runtime::detail::native_persistent_list; @@ -17,10 +17,10 @@ namespace jank::runtime::obj static constexpr bool is_sequential{ true }; /* Create from a sequence. */ - static persistent_list_ref create(object_ref meta, object_ref s); - static persistent_list_ref create(object_ref s); - static persistent_list_ref create(persistent_list_ref s); - static persistent_list_ref create(nil_ref s); + static persistent_list_ref create(object_ref const meta, object_ref const s); + static persistent_list_ref create(object_ref const s); + static persistent_list_ref create(persistent_list_ref const s); + static persistent_list_ref create(nil_ref const s); persistent_list() = default; persistent_list(persistent_list &&) noexcept = default; @@ -57,7 +57,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - persistent_list_ref with_meta(object_ref m) const; + persistent_list_ref with_meta(object_ref const m) const; /* behavior::seqable */ obj::persistent_list_ref seq() const; @@ -67,7 +67,7 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable */ - persistent_list_ref conj(object_ref head) const; + persistent_list_ref conj(object_ref const head) const; /* behavior::sequenceable */ object_ref first() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_map.hpp index d23242dfd..18338d998 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_map.hpp @@ -28,7 +28,7 @@ namespace jank::runtime::obj persistent_sorted_map(persistent_sorted_map const &) = default; persistent_sorted_map(value_type &&d); persistent_sorted_map(value_type const &d); - persistent_sorted_map(object_ref meta, value_type &&d); + persistent_sorted_map(object_ref const meta, value_type &&d); persistent_sorted_map(jtl::option const &meta, value_type &&d); template @@ -68,16 +68,16 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable */ - persistent_sorted_map_ref assoc(object_ref key, object_ref val) const; - persistent_sorted_map_ref dissoc(object_ref key) const; + persistent_sorted_map_ref assoc(object_ref const key, object_ref const val) const; + persistent_sorted_map_ref dissoc(object_ref const key) const; /* behavior::callable */ - object_ref call(object_ref) const; - object_ref call(object_ref, object_ref) const; + object_ref call(object_ref const) const; + object_ref call(object_ref const, object_ref const) const; /* behavior::transientable */ obj::transient_sorted_map_ref to_transient() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set.hpp index 28efff3ce..1e3d43cb7 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using persistent_sorted_set_ref = oref; using persistent_sorted_set_sequence_ref = oref; - struct persistent_sorted_set : gc + struct persistent_sorted_set { static constexpr object_type obj_type{ object_type::persistent_sorted_set }; static constexpr bool pointer_free{ false }; @@ -22,7 +22,7 @@ namespace jank::runtime::obj persistent_sorted_set(persistent_sorted_set const &) = default; persistent_sorted_set(value_type &&d); persistent_sorted_set(value_type const &d); - persistent_sorted_set(object_ref meta, value_type &&d); + persistent_sorted_set(object_ref const meta, value_type &&d); persistent_sorted_set(jtl::option const &meta, value_type &&d); template @@ -49,7 +49,7 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::metadatable */ - persistent_sorted_set_ref with_meta(object_ref m) const; + persistent_sorted_set_ref with_meta(object_ref const m) const; /* behavior::seqable */ persistent_sorted_set_sequence_ref seq() const; @@ -59,16 +59,16 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable */ - persistent_sorted_set_ref conj(object_ref head) const; + persistent_sorted_set_ref conj(object_ref const head) const; /* behavior::callable */ - object_ref call(object_ref); + object_ref call(object_ref const); /* behavior::transientable */ obj::transient_sorted_set_ref to_transient() const; - bool contains(object_ref o) const; - persistent_sorted_set_ref disj(object_ref o) const; + bool contains(object_ref const o) const; + persistent_sorted_set_ref disj(object_ref const o) const; object base{ obj_type }; value_type data; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set_sequence.hpp index 05c655004..fde5a19c0 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_sorted_set_sequence.hpp @@ -11,8 +11,7 @@ namespace jank::runtime::obj using persistent_sorted_set_sequence_ref = oref; struct persistent_sorted_set_sequence - : gc - , obj::detail::iterator_sequence { static constexpr object_type obj_type{ object_type::persistent_sorted_set_sequence }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string.hpp index ff51d1704..3068d3a49 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using persistent_string_ref = oref; using persistent_string_sequence_ref = oref; - struct persistent_string : gc + struct persistent_string { static constexpr object_type obj_type{ object_type::persistent_string }; static constexpr bool pointer_free{ false }; @@ -42,8 +42,8 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::indexable */ object_ref nth(object_ref const index) const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string_sequence.hpp index 7d2e353a3..f2644a494 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_string_sequence.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj using persistent_string_ref = oref; using persistent_string_sequence_ref = oref; - struct persistent_string_sequence : gc + struct persistent_string_sequence { static constexpr object_type obj_type{ object_type::persistent_string_sequence }; static constexpr bool pointer_free{ false }; @@ -37,7 +37,7 @@ namespace jank::runtime::obj /* behavior::sequenceable */ object_ref first() const; persistent_string_sequence_ref next() const; - obj::cons_ref conj(object_ref head); + obj::cons_ref conj(object_ref const head); /* behavior::sequenceable_in_place */ persistent_string_sequence_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector.hpp index f763bdc0a..1613c6df8 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using persistent_vector_ref = oref; using persistent_vector_sequence_ref = oref; - struct persistent_vector : gc + struct persistent_vector { static constexpr object_type obj_type{ object_type::persistent_vector }; static constexpr bool pointer_free{ false }; @@ -38,7 +38,7 @@ namespace jank::runtime::obj { } - static persistent_vector_ref create(object_ref s); + static persistent_vector_ref create(object_ref const s); static persistent_vector_ref empty(); @@ -56,7 +56,7 @@ namespace jank::runtime::obj i64 compare(persistent_vector const &) const; /* behavior::metadatable */ - persistent_vector_ref with_meta(object_ref m) const; + persistent_vector_ref with_meta(object_ref const m) const; /* behavior::seqable */ persistent_vector_sequence_ref seq() const; @@ -66,28 +66,28 @@ namespace jank::runtime::obj usize count() const; /* behavior::associatively_readable */ - object_ref get(object_ref key) const; - object_ref get(object_ref key, object_ref fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get(object_ref const key) const; + object_ref get(object_ref const key, object_ref const fallback) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable */ - persistent_vector_ref assoc(object_ref key, object_ref val) const; - persistent_vector_ref dissoc(object_ref key) const; + persistent_vector_ref assoc(object_ref const key, object_ref const val) const; + persistent_vector_ref dissoc(object_ref const key) const; /* behavior::conjable */ - persistent_vector_ref conj(object_ref head) const; + persistent_vector_ref conj(object_ref const head) const; /* behavior::stackable */ object_ref peek() const; persistent_vector_ref pop() const; /* behavior::indexable */ - object_ref nth(object_ref index) const; - object_ref nth(object_ref index, object_ref fallback) const; + object_ref nth(object_ref const index) const; + object_ref nth(object_ref const index, object_ref const fallback) const; /* behavior::callable */ - object_ref call(object_ref) const; + object_ref call(object_ref const) const; /* behavior::transientable */ obj::transient_vector_ref to_transient() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector_sequence.hpp index 0cc124287..6b4914a76 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_vector_sequence.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj using persistent_vector_ref = oref; using persistent_vector_sequence_ref = oref; - struct persistent_vector_sequence : gc + struct persistent_vector_sequence { static constexpr object_type obj_type{ object_type::persistent_vector_sequence }; static constexpr bool pointer_free{ false }; @@ -17,8 +17,8 @@ namespace jank::runtime::obj persistent_vector_sequence() = default; persistent_vector_sequence(persistent_vector_sequence &&) noexcept = default; persistent_vector_sequence(persistent_vector_sequence const &) = default; - persistent_vector_sequence(obj::persistent_vector_ref v); - persistent_vector_sequence(obj::persistent_vector_ref v, usize i); + persistent_vector_sequence(obj::persistent_vector_ref const v); + persistent_vector_sequence(obj::persistent_vector_ref const v, usize i); /* behavior::object_like */ bool equal(object const &) const; @@ -37,7 +37,7 @@ namespace jank::runtime::obj /* behavior::sequenceable */ object_ref first() const; persistent_vector_sequence_ref next() const; - obj::cons_ref conj(object_ref head); + obj::cons_ref conj(object_ref const head); /* behavior::sequenceable_in_place */ persistent_vector_sequence_ref next_in_place(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/range.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/range.hpp index bbfe5a2be..8a9a9d7e8 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/range.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/range.hpp @@ -8,38 +8,41 @@ namespace jank::runtime::obj { using array_chunk_ref = oref; using cons_ref = oref; - using range_ptr = oref; + using range_ref = oref; /* A range from X to Y, exclusive, incrementing by S. This is for non-integer values. * For integer values, use integer_range. This is not countable in constant time, due * to floating point shenanigans. */ - struct range : gc + struct range { static constexpr object_type obj_type{ object_type::range }; static constexpr bool pointer_free{ false }; static constexpr bool is_sequential{ true }; static constexpr i64 chunk_size{ 32 }; - using bounds_check_t = bool (*)(object_ref, object_ref); + using bounds_check_t = bool (*)(object_ref const, object_ref const); /* Constructors are only to be used within range.cpp. Prefer range::create. */ range() = default; range(range &&) noexcept = default; range(range const &) = default; - range(object_ref end); - range(object_ref start, object_ref end); - range(object_ref start, object_ref end, object_ref step); - range(object_ref start, object_ref end, object_ref step, bounds_check_t bounds_check); - range(object_ref start, - object_ref end, - object_ref step, + range(object_ref const end); + range(object_ref const start, object_ref const end); + range(object_ref const start, object_ref const end, object_ref const step); + range(object_ref const start, + object_ref const end, + object_ref const step, + bounds_check_t bounds_check); + range(object_ref const start, + object_ref const end, + object_ref const step, bounds_check_t bounds_check, - obj::array_chunk_ref chunk, - range_ptr chunk_next); + obj::array_chunk_ref const chunk, + range_ref const chunk_next); - static object_ref create(object_ref end); - static object_ref create(object_ref start, object_ref end); - static object_ref create(object_ref start, object_ref end, object_ref step); + static object_ref create(object_ref const end); + static object_ref create(object_ref const start, object_ref const end); + static object_ref create(object_ref const start, object_ref const end, object_ref const step); /* behavior::object_like */ bool equal(object const &) const; @@ -49,26 +52,26 @@ namespace jank::runtime::obj uhash to_hash() const; /* behavior::seqable */ - range_ptr seq(); - range_ptr fresh_seq() const; + range_ref seq(); + range_ref fresh_seq() const; /* behavior::sequenceable */ object_ref first() const; - range_ptr next() const; + range_ref next() const; /* behavior::sequenceable_in_place */ - range_ptr next_in_place(); + range_ref next_in_place(); /* behavior::chunkable */ obj::array_chunk_ref chunked_first() const; - range_ptr chunked_next() const; + range_ref chunked_next() const; void force_chunk() const; /* behavior::conjable */ - obj::cons_ref conj(object_ref head) const; + obj::cons_ref conj(object_ref const head) const; /* behavior::metadatable */ - range_ptr with_meta(object_ref m) const; + range_ref with_meta(object_ref const m) const; object base{ obj_type }; object_ref start{}; @@ -76,8 +79,8 @@ namespace jank::runtime::obj object_ref step{}; bounds_check_t bounds_check{}; mutable obj::array_chunk_ref chunk{}; - mutable range_ptr chunk_next{}; - mutable range_ptr cached_next{}; + mutable range_ref chunk_next{}; + mutable range_ref cached_next{}; jtl::option meta{}; }; } diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/ratio.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/ratio.hpp index 6ecffb5de..ede52f9db 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/ratio.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/ratio.hpp @@ -10,7 +10,7 @@ namespace jank::runtime::obj ratio_data(i64 const, i64 const); ratio_data(native_big_integer const &, native_big_integer const &); ratio_data(big_integer const &, big_integer const &); - ratio_data(object_ref, object_ref); + ratio_data(object_ref const, object_ref const); ratio_data(ratio_data const &) = default; f64 to_real() const; @@ -24,7 +24,7 @@ namespace jank::runtime::obj using real_ref = oref; using ratio_ref = oref; - struct ratio : gc + struct ratio { static constexpr object_type obj_type{ object_type::ratio }; static constexpr bool pointer_free{ true }; @@ -58,55 +58,55 @@ namespace jank::runtime::obj }; object_ref operator+(ratio_data const &l, ratio_data const &r); - ratio_ref operator+(integer_ref l, ratio_data const &r); - ratio_ref operator+(ratio_data const &l, integer_ref r); - f64 operator+(real_ref l, ratio_data const &r); - f64 operator+(ratio_data const &l, real_ref r); + ratio_ref operator+(integer_ref const l, ratio_data const &r); + ratio_ref operator+(ratio_data const &l, integer_ref const r); + f64 operator+(real_ref const l, ratio_data const &r); + f64 operator+(ratio_data const &l, real_ref const r); f64 operator+(ratio_data const &l, f64 r); f64 operator+(f64 l, ratio_data const &r); ratio_ref operator+(ratio_data const &l, i64 r); ratio_ref operator+(i64 l, ratio_data const &r); object_ref operator-(ratio_data const &l, ratio_data const &r); - ratio_ref operator-(integer_ref l, ratio_data const &r); - ratio_ref operator-(ratio_data const &l, integer_ref r); - f64 operator-(real_ref l, ratio_data const &r); - f64 operator-(ratio_data const &l, real_ref r); + ratio_ref operator-(integer_ref const l, ratio_data const &r); + ratio_ref operator-(ratio_data const &l, integer_ref const r); + f64 operator-(real_ref const l, ratio_data const &r); + f64 operator-(ratio_data const &l, real_ref const r); f64 operator-(ratio_data const &l, f64 r); f64 operator-(f64 l, ratio_data const &r); ratio_ref operator-(ratio_data const &l, i64 r); ratio_ref operator-(i64 l, ratio_data const &r); object_ref operator*(ratio_data const &l, ratio_data const &r); - object_ref operator*(integer_ref l, ratio_data const &r); - object_ref operator*(ratio_data const &l, integer_ref r); - f64 operator*(real_ref l, ratio_data const &r); - f64 operator*(ratio_data const &l, real_ref r); + object_ref operator*(integer_ref const l, ratio_data const &r); + object_ref operator*(ratio_data const &l, integer_ref const r); + f64 operator*(real_ref const l, ratio_data const &r); + f64 operator*(ratio_data const &l, real_ref const r); f64 operator*(ratio_data const &l, f64 r); f64 operator*(f64 l, ratio_data const &r); object_ref operator*(ratio_data const &l, i64 r); object_ref operator*(i64 l, ratio_data const &r); object_ref operator/(ratio_data const &l, ratio_data const &r); - object_ref operator/(integer_ref l, ratio_data const &r); - ratio_ref operator/(ratio_data const &l, integer_ref r); - f64 operator/(real_ref l, ratio_data const &r); - f64 operator/(ratio_data const &l, real_ref r); + object_ref operator/(integer_ref const l, ratio_data const &r); + ratio_ref operator/(ratio_data const &l, integer_ref const r); + f64 operator/(real_ref const l, ratio_data const &r); + f64 operator/(ratio_data const &l, real_ref const r); f64 operator/(ratio_data const &l, f64 r); f64 operator/(f64 l, ratio_data const &r); ratio_ref operator/(ratio_data const &l, i64 r); object_ref operator/(i64 l, ratio_data const &r); bool operator==(ratio_data const &l, ratio_data const &r); - bool operator==(integer_ref l, ratio_data const &r); - bool operator==(ratio_data const &l, integer_ref r); - bool operator==(real_ref l, ratio_data const &r); - bool operator==(ratio_data const &l, real_ref r); + bool operator==(integer_ref const l, ratio_data const &r); + bool operator==(ratio_data const &l, integer_ref const r); + bool operator==(real_ref const l, ratio_data const &r); + bool operator==(ratio_data const &l, real_ref const r); bool operator==(ratio_data const &l, f64 r); bool operator==(f64 l, ratio_data const &r); bool operator==(ratio_data const &l, i64 r); bool operator==(i64 l, ratio_data const &r); bool operator<(ratio_data const &l, ratio_data const &r); - bool operator<(integer_ref l, ratio_data const &r); - bool operator<(ratio_data const &l, integer_ref r); - bool operator<(real_ref l, ratio_data const &r); - bool operator<(ratio_data const &l, real_ref r); + bool operator<(integer_ref const l, ratio_data const &r); + bool operator<(ratio_data const &l, integer_ref const r); + bool operator<(real_ref const l, ratio_data const &r); + bool operator<(ratio_data const &l, real_ref const r); bool operator<(ratio_data const &l, f64 r); bool operator<(f64 l, ratio_data const &r); bool operator<(ratio_data const &l, i64 r); @@ -114,19 +114,19 @@ namespace jank::runtime::obj bool operator<(bool l, ratio_data const &r); bool operator<(ratio_data const &l, bool r); bool operator<=(ratio_data const &l, ratio_data const &r); - bool operator<=(integer_ref l, ratio_data const &r); - bool operator<=(ratio_data const &l, integer_ref r); - bool operator<=(real_ref l, ratio_data const &r); - bool operator<=(ratio_data const &l, real_ref r); + bool operator<=(integer_ref const l, ratio_data const &r); + bool operator<=(ratio_data const &l, integer_ref const r); + bool operator<=(real_ref const l, ratio_data const &r); + bool operator<=(ratio_data const &l, real_ref const r); bool operator<=(ratio_data const &l, f64 r); bool operator<=(f64 l, ratio_data const &r); bool operator<=(ratio_data const &l, i64 r); bool operator<=(i64 l, ratio_data const &r); bool operator>(ratio_data const &l, ratio_data const &r); - bool operator>(integer_ref l, ratio_data const &r); - bool operator>(ratio_data const &l, integer_ref r); - bool operator>(real_ref l, ratio_data const &r); - bool operator>(ratio_data const &l, real_ref r); + bool operator>(integer_ref const l, ratio_data const &r); + bool operator>(ratio_data const &l, integer_ref const r); + bool operator>(real_ref const l, ratio_data const &r); + bool operator>(ratio_data const &l, real_ref const r); bool operator>(ratio_data const &l, f64 r); bool operator>(f64 l, ratio_data const &r); bool operator>(ratio_data const &l, i64 r); @@ -134,10 +134,10 @@ namespace jank::runtime::obj bool operator>(bool l, ratio_data const &r); bool operator>(ratio_data const &l, bool r); bool operator>=(ratio_data const &l, ratio_data const &r); - bool operator>=(integer_ref l, ratio_data const &r); - bool operator>=(ratio_data const &l, integer_ref r); - bool operator>=(real_ref l, ratio_data const &r); - bool operator>=(ratio_data const &l, real_ref r); + bool operator>=(integer_ref const l, ratio_data const &r); + bool operator>=(ratio_data const &l, integer_ref const r); + bool operator>=(real_ref const l, ratio_data const &r); + bool operator>=(ratio_data const &l, real_ref const r); bool operator>=(ratio_data const &l, f64 r); bool operator>=(f64 l, ratio_data const &r); bool operator>=(ratio_data const &l, i64 r); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/re_matcher.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/re_matcher.hpp index f01792d55..c0e2d7b71 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/re_matcher.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/re_matcher.hpp @@ -10,12 +10,12 @@ namespace jank::runtime::obj { using re_matcher_ref = oref; - struct re_matcher : gc_cleanup + struct re_matcher { static constexpr object_type obj_type{ object_type::re_matcher }; static constexpr bool pointer_free{ false }; - re_matcher(re_pattern_ref re, jtl::immutable_string const &s); + re_matcher(re_pattern_ref const re, jtl::immutable_string const &s); /* behavior::object_like */ bool equal(object const &) const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/re_pattern.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/re_pattern.hpp index f3024aa20..55d745cc5 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/re_pattern.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/re_pattern.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj { using re_pattern_ref = oref; - struct re_pattern : gc_cleanup + struct re_pattern { static constexpr object_type obj_type{ object_type::re_pattern }; static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/reduced.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/reduced.hpp index 1a1306001..32ab49db0 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/reduced.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/reduced.hpp @@ -6,13 +6,13 @@ namespace jank::runtime::obj { using reduced_ref = oref; - struct reduced : gc + struct reduced { static constexpr object_type obj_type{ object_type::reduced }; static constexpr bool pointer_free{ false }; reduced() = default; - reduced(object_ref o); + reduced(object_ref const o); /* behavior::object_like */ bool equal(object const &) const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp index 050b5a072..fb34aae75 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/repeat.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using cons_ref = oref; using repeat_ref = oref; - struct repeat : gc + struct repeat { static constexpr object_type obj_type{ object_type::repeat }; static constexpr bool pointer_free{ false }; @@ -17,11 +17,11 @@ namespace jank::runtime::obj static constexpr i64 infinite{ -1 }; repeat() = default; - repeat(object_ref value); - repeat(object_ref count, object_ref value); + repeat(object_ref const value); + repeat(object_ref const count, object_ref const value); - static object_ref create(object_ref value); - static object_ref create(object_ref count, object_ref value); + static object_ref create(object_ref const value); + static object_ref create(object_ref const count, object_ref const value); /* behavior::object_like */ bool equal(object const &) const; @@ -42,10 +42,10 @@ namespace jank::runtime::obj repeat_ref next_in_place(); /* behavior::conjable */ - obj::cons_ref conj(object_ref head) const; + obj::cons_ref conj(object_ref const head) const; /* behavior::metadatable */ - repeat_ref with_meta(object_ref m) const; + repeat_ref with_meta(object_ref const m) const; object base{ obj_type }; object_ref value{}; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/symbol.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/symbol.hpp index 10df7eb5d..b406b64d9 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/symbol.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/symbol.hpp @@ -9,7 +9,7 @@ namespace jank::runtime::obj using persistent_array_map_ref = oref; using symbol_ref = oref; - struct symbol : gc + struct symbol { static constexpr object_type obj_type{ object_type::symbol }; static constexpr bool pointer_free{ false }; @@ -21,8 +21,8 @@ namespace jank::runtime::obj symbol(jtl::immutable_string &&d); symbol(jtl::immutable_string const &ns, jtl::immutable_string const &n); symbol(jtl::immutable_string &&ns, jtl::immutable_string &&n); - symbol(object_ref meta, jtl::immutable_string const &ns, jtl::immutable_string const &n); - symbol(object_ref ns, object_ref n); + symbol(object_ref const meta, jtl::immutable_string const &ns, jtl::immutable_string const &n); + symbol(object_ref const ns, object_ref const n); symbol &operator=(symbol const &) = default; symbol &operator=(symbol &&) = default; @@ -44,7 +44,7 @@ namespace jank::runtime::obj i64 compare(symbol const &) const; /* behavior::metadatable */ - symbol_ref with_meta(object_ref m) const; + symbol_ref with_meta(object_ref const m) const; /* behavior::nameable */ jtl::immutable_string const &get_name() const; @@ -78,13 +78,13 @@ namespace std template <> struct hash { - size_t operator()(jank::runtime::obj::symbol_ref const &o) const noexcept; + size_t operator()(jank::runtime::obj::symbol_ref const o) const noexcept; }; template <> struct equal_to { - bool operator()(jank::runtime::obj::symbol_ref const &lhs, - jank::runtime::obj::symbol_ref const &rhs) const noexcept; + bool operator()(jank::runtime::obj::symbol_ref const lhs, + jank::runtime::obj::symbol_ref const rhs) const noexcept; }; } diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/tagged_literal.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/tagged_literal.hpp index 39a241f0a..104ffc73b 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/tagged_literal.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/tagged_literal.hpp @@ -6,12 +6,12 @@ namespace jank::runtime::obj { using tagged_literal_ref = oref; - struct tagged_literal : gc + struct tagged_literal { static constexpr object_type obj_type{ object_type::tagged_literal }; static constexpr bool pointer_free{ false }; - tagged_literal(object_ref tag, object_ref form); + tagged_literal(object_ref const tag, object_ref const form); /* behavior::object_like */ bool equal(object const &) const; @@ -23,8 +23,8 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; object base{ obj_type }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_array_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_array_map.hpp index 9eb6e32b3..f69f05373 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_array_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_array_map.hpp @@ -8,7 +8,7 @@ namespace jank::runtime::obj using transient_array_map_ref = oref; /* TODO: Benchmark how fast is the transient array map vs the transient hash map for small maps? */ - struct transient_array_map : gc + struct transient_array_map { static constexpr object_type obj_type{ object_type::transient_array_map }; static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_map.hpp index 19ef8fd54..dbaa65bc2 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_map.hpp @@ -12,7 +12,7 @@ namespace jank::runtime::obj { using transient_hash_map_ref = oref; - struct transient_hash_map : gc + struct transient_hash_map { static constexpr object_type obj_type{ object_type::transient_hash_map }; static constexpr bool pointer_free{ false }; @@ -43,22 +43,22 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable_in_place */ transient_hash_map_ref assoc_in_place(object_ref const key, object_ref const val); transient_hash_map_ref dissoc_in_place(object_ref const key); /* behavior::conjable_in_place */ - transient_hash_map_ref conj_in_place(object_ref head); + transient_hash_map_ref conj_in_place(object_ref const head); /* behavior::persistentable */ persistent_type_ref to_persistent(); /* behavior::callable */ - object_ref call(object_ref) const; - object_ref call(object_ref, object_ref) const; + object_ref call(object_ref const) const; + object_ref call(object_ref const, object_ref const) const; void assert_active() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_set.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_set.hpp index 4cae8df4a..280aef166 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_set.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_hash_set.hpp @@ -7,7 +7,7 @@ namespace jank::runtime::obj { using transient_hash_set_ref = oref; - struct transient_hash_set : gc + struct transient_hash_set { static constexpr object_type obj_type{ object_type::transient_hash_set }; static constexpr bool pointer_free{ false }; @@ -35,7 +35,7 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable_in_place */ - transient_hash_set_ref conj_in_place(object_ref elem); + transient_hash_set_ref conj_in_place(object_ref const elem); /* behavior::persistentable */ persistent_type_ref to_persistent(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp index 97e3fdcc1..8ea7ec99f 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp @@ -7,7 +7,7 @@ namespace jank::runtime::obj { using transient_sorted_map_ref = oref; - struct transient_sorted_map : gc + struct transient_sorted_map { static constexpr object_type obj_type{ object_type::transient_sorted_map }; static constexpr bool pointer_free{ false }; @@ -18,8 +18,7 @@ namespace jank::runtime::obj transient_sorted_map() = default; transient_sorted_map(transient_sorted_map &&) noexcept = default; transient_sorted_map(transient_sorted_map const &) = default; - transient_sorted_map(runtime::detail::native_persistent_sorted_map const &d); - transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d); + transient_sorted_map(value_type const &d); transient_sorted_map(value_type &&d); static transient_sorted_map_ref empty(); @@ -37,22 +36,22 @@ namespace jank::runtime::obj /* behavior::associatively_readable */ object_ref get(object_ref const key) const; object_ref get(object_ref const key, object_ref const fallback) const; - object_ref get_entry(object_ref key) const; - bool contains(object_ref key) const; + object_ref get_entry(object_ref const key) const; + bool contains(object_ref const key) const; /* behavior::associatively_writable_in_place */ transient_sorted_map_ref assoc_in_place(object_ref const key, object_ref const val); transient_sorted_map_ref dissoc_in_place(object_ref const key); /* behavior::conjable_in_place */ - transient_sorted_map_ref conj_in_place(object_ref head); + transient_sorted_map_ref conj_in_place(object_ref const head); /* behavior::persistentable */ persistent_type_ref to_persistent(); /* behavior::callable */ - object_ref call(object_ref) const; - object_ref call(object_ref, object_ref) const; + object_ref call(object_ref const) const; + object_ref call(object_ref const, object_ref const) const; void assert_active() const; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp index e2d679eaf..bbd60a91a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp @@ -7,7 +7,7 @@ namespace jank::runtime::obj { using transient_sorted_set_ref = oref; - struct transient_sorted_set : gc + struct transient_sorted_set { static constexpr object_type obj_type{ object_type::transient_sorted_set }; static constexpr bool pointer_free{ false }; @@ -18,8 +18,7 @@ namespace jank::runtime::obj transient_sorted_set() = default; transient_sorted_set(transient_sorted_set &&) noexcept = default; transient_sorted_set(transient_sorted_set const &) = default; - transient_sorted_set(runtime::detail::native_persistent_sorted_set const &d); - transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d); + transient_sorted_set(value_type const &d); transient_sorted_set(value_type &&d); static transient_sorted_set_ref empty(); @@ -35,7 +34,7 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable_in_place */ - transient_sorted_set_ref conj_in_place(object_ref elem); + transient_sorted_set_ref conj_in_place(object_ref const elem); /* behavior::persistentable */ persistent_type_ref to_persistent(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_vector.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_vector.hpp index cfb586f73..d211cb9ca 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_vector.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_vector.hpp @@ -7,7 +7,7 @@ namespace jank::runtime::obj { using transient_vector_ref = oref; - struct transient_vector : gc + struct transient_vector { static constexpr object_type obj_type{ object_type::transient_vector }; static constexpr bool pointer_free{ false }; @@ -35,7 +35,7 @@ namespace jank::runtime::obj usize count() const; /* behavior::conjable_in_place */ - transient_vector_ref conj_in_place(object_ref head); + transient_vector_ref conj_in_place(object_ref const head); /* behavior::persistentable */ persistent_type_ref to_persistent(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/uuid.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/uuid.hpp index f5f04b1e6..914e7cf46 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/uuid.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/uuid.hpp @@ -11,7 +11,7 @@ namespace jank::runtime::obj { using uuid_ref = oref; - struct uuid : gc + struct uuid { static constexpr object_type obj_type{ object_type::uuid }; static constexpr bool pointer_free{ false }; diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/volatile.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/volatile.hpp index f80517541..17ae5e38a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/volatile.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/volatile.hpp @@ -6,13 +6,13 @@ namespace jank::runtime::obj { using volatile_ref = oref; - struct volatile_ : gc + struct volatile_ { static constexpr object_type obj_type{ object_type::volatile_ }; static constexpr bool pointer_free{ false }; volatile_() = default; - volatile_(object_ref o); + volatile_(object_ref const o); /* behavior::object_like */ bool equal(object const &) const; @@ -24,7 +24,7 @@ namespace jank::runtime::obj /* behavior::derefable */ object_ref deref() const; - object_ref reset(object_ref o); + object_ref reset(object_ref const o); object base{ obj_type }; object_ref val{}; diff --git a/compiler+runtime/include/cpp/jank/runtime/object.hpp b/compiler+runtime/include/cpp/jank/runtime/object.hpp index 6ace6c701..2550f786a 100644 --- a/compiler+runtime/include/cpp/jank/runtime/object.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/object.hpp @@ -243,7 +243,16 @@ namespace jank::runtime struct object { + object() = default; + object(object const &) noexcept; + object(object &&) noexcept; + object(object_type) noexcept; + + object &operator=(object const &) noexcept; + object &operator=(object &&) noexcept; + object_type type{}; + std::atomic ref_count{}; }; namespace obj @@ -304,8 +313,8 @@ namespace jank::runtime bool operator()(object_ref const lhs, object_ref const rhs) const noexcept; }; - bool operator==(object const *, object_ref); - bool operator!=(object const *, object_ref); + bool operator==(object const *, object_ref const); + bool operator!=(object const *, object_ref const); } namespace std diff --git a/compiler+runtime/include/cpp/jank/runtime/oref.hpp b/compiler+runtime/include/cpp/jank/runtime/oref.hpp index 5c1f24e9e..7b8251db5 100644 --- a/compiler+runtime/include/cpp/jank/runtime/oref.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/oref.hpp @@ -9,6 +9,8 @@ #include +extern "C" void *jank_const_nil(); + namespace jank::runtime { namespace obj @@ -22,12 +24,6 @@ namespace jank::runtime /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ extern oref jank_false; - namespace detail - { - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - extern obj::nil *jank_nil_ptr; - } - template struct oref; @@ -40,118 +36,145 @@ namespace jank::runtime { using value_type = object; - constexpr oref() - : data{ std::bit_cast(detail::jank_nil_ptr) } - { - } + oref() = default; + oref(oref const &rhs) = default; + oref(oref &&rhs) noexcept = default; - constexpr oref(oref const &) = default; - constexpr oref(oref &&) noexcept = default; + oref(nullptr_t) noexcept = delete; - constexpr oref(nullptr_t) noexcept = delete; - - constexpr oref(value_type * const data) + oref(value_type * const data) noexcept : data{ data } { - jank_assert_throw(data); + jank_assert(data); } - constexpr oref(value_type const * const data) + oref(value_type const * const data) noexcept : data{ const_cast(data) } { - jank_assert_throw(data); + jank_assert(data); } template requires behavior::object_like - constexpr oref(T * const typed_data) + oref(T * const typed_data) noexcept : data{ &typed_data->base } { - jank_assert_throw(this->data); + jank_assert(this->data); } template requires behavior::object_like - constexpr oref(T const * const typed_data) + oref(T const * const typed_data) noexcept : data{ const_cast(&typed_data->base) } { - jank_assert_throw(this->data); + jank_assert(this->data); } template requires behavior::object_like - constexpr oref(oref const typed_data) noexcept - : data{ typed_data.erase() } + oref(oref const &typed_data) noexcept + : data{ typed_data.erase().data } + { + } + + ~oref() = default; + + void reset() noexcept { + data = std::bit_cast(jank_const_nil()); } - constexpr value_type *operator->() const + void reset(object * const o) noexcept { - jank_assert_throw(data); + data = o; + } + + void reset(oref const &o) noexcept + { + data = o.data; + } + + value_type *operator->() const noexcept + { + jank_assert(data); return data; } - constexpr value_type &operator*() const + value_type &operator*() const noexcept { - jank_assert_throw(data); + jank_assert(data); return *data; } - constexpr oref &operator=(oref const &rhs) noexcept = default; - constexpr oref &operator=(oref &&rhs) noexcept = default; + oref &operator=(oref const &rhs) noexcept = default; + oref &operator=(oref &&rhs) noexcept = default; - constexpr bool operator==(oref const &rhs) const noexcept + template + requires behavior::object_like + oref &operator=(oref const &rhs) noexcept + { + if(data == &rhs->base) + { + return *this; + } + + data = &rhs->base; + return *this; + } + + bool operator==(oref const &rhs) const noexcept { return data == rhs.data; } template requires behavior::object_like - constexpr bool operator==(oref const &rhs) const noexcept + bool operator==(oref const &rhs) const noexcept { - return data == rhs.erase(); + return data == rhs.erase().data; } - constexpr bool operator!=(oref const &rhs) const noexcept + bool operator!=(oref const &rhs) const noexcept { return data != rhs.data; } template requires behavior::object_like - constexpr bool operator!=(oref const &rhs) const noexcept + bool operator!=(oref const &rhs) const noexcept { - return data != rhs.erase(); + return data != rhs.erase().data; } - constexpr oref &operator=(jtl::nullptr_t) noexcept = delete; - constexpr bool operator==(jtl::nullptr_t) noexcept = delete; - constexpr bool operator!=(jtl::nullptr_t) noexcept = delete; + oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; - constexpr value_type *get() const noexcept + value_type *get() const noexcept { return data; } - constexpr value_type *erase() const noexcept + oref const &erase() const noexcept { - return data; + return *this; } - constexpr bool is_some() const noexcept + bool is_some() const noexcept { + /* NOLINTNEXTLINE(clang-analyzer-core.NullDereference): I cannot see how this can happen. We initialize to non-null and always ensure non-null on mutation. That's the whole point of this type. */ return data->type != object_type::nil; } - constexpr bool is_nil() const noexcept + bool is_nil() const noexcept { return data->type == object_type::nil; } - value_type *data{}; + value_type *data{ std::bit_cast(jank_const_nil()) }; }; - /* This specialization of oref is for fully-typed objects like nil, + /* This specialization of oref is for fully-typed objects like * persistent_list, persistent_array_map, etc. * * It cannot be null, but it can be nil. */ @@ -160,129 +183,173 @@ namespace jank::runtime { using value_type = T; - constexpr oref() - : data{ std::bit_cast(detail::jank_nil_ptr) } - { - } + oref() = default; + oref(oref const &rhs) noexcept = default; + oref(oref &&rhs) noexcept = default; - constexpr oref(nullptr_t) = delete; + oref(nullptr_t) = delete; - constexpr oref(jtl::remove_const_t * const data) + oref(jtl::remove_const_t * const data) noexcept : data{ data } { - jank_assert_throw(this->data); + jank_assert(this->data); } - constexpr oref(T const * const data) + oref(T const * const data) noexcept : data{ const_cast(data) } { - jank_assert_throw(this->data); + jank_assert(this->data); } template requires jtl::is_convertible - constexpr oref(oref const data) noexcept + oref(oref const &data) noexcept : data{ data.data } { } template requires(C::obj_type == object_type::nil) - constexpr oref(oref const data) noexcept + oref(oref const &data) noexcept : data{ data.data } { } - constexpr T *operator->() const + ~oref() = default; + + void reset() noexcept + { + data = std::bit_cast(jank_const_nil()); + } + + void reset(object * const o) noexcept + { + data = o; + } + + void reset(oref const &o) noexcept + { + data = o.data; + } + + void reset(T * const o) noexcept + { + data = o->base; + } + + void reset(oref const &o) noexcept + { + data = o.data; + } + + T *operator->() const noexcept { /* TODO: Add type name. */ - //jank_assert_fmt_throw(*this, "Null reference on oref<{}>", jtl::type_name()); - jank_assert_throw(is_some()); + //jank_assert_fmt(*this, "Null reference on oref<{}>", jtl::type_name()); + jank_assert(is_some()); return reinterpret_cast(data); } - constexpr T &operator*() const + T &operator*() const noexcept { - //jank_assert_fmt_throw(*this, "Null reference on oref<{}>", jtl::type_name()); - jank_assert_throw(is_some()); + //jank_assert_fmt(*this, "Null reference on oref<{}>", jtl::type_name()); + jank_assert(is_some()); return *reinterpret_cast(data); } - constexpr bool operator==(oref const &rhs) const + bool operator==(oref const &rhs) const { - return erase() == rhs; + return erase().data == rhs; } - constexpr bool operator!=(oref const &rhs) const + bool operator!=(oref const &rhs) const { - return erase() != rhs; + return erase().data != rhs; } template requires behavior::object_like - constexpr bool operator==(oref const &rhs) const + bool operator==(oref const &rhs) const { return data == rhs.data; } template requires behavior::object_like - constexpr bool operator!=(oref const &rhs) const + bool operator!=(oref const &rhs) const { return data != rhs.data; } - constexpr oref &operator=(std::remove_cv_t> * const rhs) + oref &operator=(oref const &rhs) noexcept = default; + oref &operator=(oref &&rhs) noexcept = default; + + oref &operator=(std::remove_cv_t> * const rhs) noexcept { + if(data == rhs) + { + return *this; + } + data = rhs; - jank_assert_throw(data); + jank_assert(data); return *this; } - constexpr oref &operator=(std::remove_cv_t> const * const rhs) + oref &operator=(std::remove_cv_t> const * const rhs) noexcept { + if(data == rhs) + { + return *this; + } + data = const_cast(rhs); - jank_assert_throw(data); + jank_assert(data); return *this; } template requires(C::obj_type == object_type::nil) - constexpr oref &operator=(oref const &) noexcept + oref &operator=(oref const &) noexcept { - data = std::bit_cast(detail::jank_nil_ptr); + if(is_nil()) + { + return *this; + } + + data = std::bit_cast(jank_const_nil()); return *this; } - constexpr oref &operator=(jtl::nullptr_t) noexcept = delete; - constexpr bool operator==(jtl::nullptr_t) noexcept = delete; - constexpr bool operator!=(jtl::nullptr_t) noexcept = delete; + oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; - constexpr object *get() const noexcept + object *get() const noexcept { - return erase(); + return &reinterpret_cast(data)->base; } - constexpr object *erase() const noexcept + oref erase() const noexcept { if(is_nil()) { - return std::bit_cast(detail::jank_nil_ptr); + return {}; } return &reinterpret_cast(data)->base; } - constexpr bool is_some() const noexcept + bool is_some() const noexcept { - return data != std::bit_cast(detail::jank_nil_ptr); + return data != std::bit_cast(jank_const_nil()); } - constexpr bool is_nil() const noexcept + bool is_nil() const noexcept { - return data == std::bit_cast(detail::jank_nil_ptr); + return data == std::bit_cast(jank_const_nil()); } - void *data{}; + void *data{ std::bit_cast(jank_const_nil()) }; }; template <> @@ -290,139 +357,129 @@ namespace jank::runtime { using value_type = obj::nil; - constexpr oref() - : data{ std::bit_cast(detail::jank_nil_ptr) } - { - } + oref() = default; + oref(oref const &) = default; + oref(oref &&) noexcept = default; - constexpr oref(nullptr_t) = delete; + oref(nullptr_t) = delete; - constexpr oref(value_type * const data) + oref(value_type * const data) noexcept : data{ data } { - jank_assert_throw(this->data); + jank_assert(this->data); } - constexpr oref(value_type const * const data) + oref(value_type const * const data) noexcept : data{ const_cast(data) } { - jank_assert_throw(this->data); + jank_assert(this->data); } template requires jtl::is_convertible - constexpr oref(oref const data) noexcept + oref(oref const &data) noexcept : data{ data.data } { } template requires(C::obj_type == object_type::nil) - constexpr oref(oref const data) noexcept + oref(oref const &data) noexcept : data{ data.data } { } - constexpr value_type *operator->() const + void reset() + { + } + + value_type *operator->() const { return data; } - constexpr value_type &operator*() const + value_type &operator*() const { return *data; } - constexpr bool operator==(oref const &rhs) const + bool operator==(oref const &rhs) const { return rhs.is_nil(); } - constexpr bool operator!=(oref const &rhs) const + bool operator!=(oref const &rhs) const { return rhs.is_some(); } template requires behavior::object_like - constexpr bool operator==(oref const &rhs) const + bool operator==(oref const &rhs) const { return rhs.is_nil(); } template requires behavior::object_like - constexpr bool operator!=(oref const &rhs) const + bool operator!=(oref const &rhs) const { return rhs.is_some(); } - constexpr oref &operator=(jtl::nullptr_t) noexcept = delete; - constexpr bool operator==(jtl::nullptr_t) noexcept = delete; - constexpr bool operator!=(jtl::nullptr_t) noexcept = delete; + oref &operator=(oref const &rhs) noexcept = default; + oref &operator=(oref &&rhs) noexcept = default; + + oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; - constexpr object *get() const noexcept + object *get() const noexcept { - return erase(); + return std::bit_cast(data); } - constexpr object *erase() const noexcept + oref erase() const noexcept { - return std::bit_cast(data); + return { std::bit_cast(jank_const_nil()) }; } - constexpr bool is_some() const noexcept + bool is_some() const noexcept { return false; } - constexpr bool is_nil() const noexcept + bool is_nil() const noexcept { return true; } - value_type *data{}; + value_type *data{ std::bit_cast(jank_const_nil()) }; }; template - constexpr jtl::ref make_box(jtl::ref const &o) + jtl::ref make_box(jtl::ref const &o) { static_assert(sizeof(jtl::ref) == sizeof(T *)); return o; } template - constexpr oref make_box(oref const &o) + oref make_box(oref const &o) { static_assert(sizeof(oref) == sizeof(T *)); return o; } - /* TODO: Constexpr these. */ + /* TODO: these. */ template jtl::ref make_box(Args &&...args) { static_assert(sizeof(jtl::ref) == sizeof(T *)); - T *ret{}; - if constexpr(requires { T::pointer_free; }) - { - if constexpr(T::pointer_free) - { - ret = new(PointerFreeGC) T{ std::forward(args)... }; - } - else - { - ret = new(GC) T{ std::forward(args)... }; - } - } - else - { - ret = new(GC) T{ std::forward(args)... }; - } - + /* TODO: Figure out cleanup for this. */ + T *ret{ new(GC) T{ std::forward(args)... } }; if(!ret) { - /* TODO: Panic. */ throw std::runtime_error{ "unable to allocate box" }; } return ret; @@ -440,29 +497,14 @@ namespace jank::runtime oref make_box(Args &&...args) { static_assert(sizeof(oref) == sizeof(T *)); - oref ret; - if constexpr(requires { T::pointer_free; }) - { - if constexpr(T::pointer_free) - { - ret = new(PointerFreeGC) T{ std::forward(args)... }; - } - else - { - ret = new(GC) T{ std::forward(args)... }; - } - } - else - { - ret = new(GC) T{ std::forward(args)... }; - } - + oref ret{ new(GC) T{ std::forward(args)... } }; return ret; } template - constexpr jtl::ref make_array_box() + jtl::ref make_array_box() { + /* TODO: Figure out cleanup for this. */ auto const ret(new(GC) T[N]{}); if(!ret) { @@ -472,8 +514,9 @@ namespace jank::runtime } template - constexpr jtl::ref make_array_box(usize const length) + jtl::ref make_array_box(usize const length) { + /* TODO: Figure out cleanup for this. */ auto const ret(new(GC) T[length]{}); if(!ret) { @@ -485,7 +528,7 @@ namespace jank::runtime template jtl::ref make_array_box(Args &&...args) { - /* TODO: pointer_free? */ + /* TODO: Figure out cleanup for this. */ auto const ret(new(GC) T[sizeof...(Args)]{ std::forward(args)... }); if(!ret) { @@ -499,5 +542,4 @@ namespace jank::runtime { return static_cast(ptr.data); } - } diff --git a/compiler+runtime/include/cpp/jank/runtime/perf.hpp b/compiler+runtime/include/cpp/jank/runtime/perf.hpp index 7de330e1e..a4418986c 100644 --- a/compiler+runtime/include/cpp/jank/runtime/perf.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/perf.hpp @@ -4,5 +4,5 @@ namespace jank::runtime::perf { - object_ref benchmark(object_ref opts, object_ref f); + object_ref benchmark(object_ref const opts, object_ref const f); } diff --git a/compiler+runtime/include/cpp/jank/runtime/sequence_range.hpp b/compiler+runtime/include/cpp/jank/runtime/sequence_range.hpp index c3bb71434..8b6a311a0 100644 --- a/compiler+runtime/include/cpp/jank/runtime/sequence_range.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/sequence_range.hpp @@ -65,7 +65,7 @@ namespace jank::runtime iterator end() const { - return { jank_nil }; + return { jank_nil() }; } sequence_range skip(usize const n) const @@ -99,7 +99,7 @@ namespace jank::runtime iterator(iterator const &) noexcept = default; iterator(iterator &&) noexcept = default; - iterator(oref const data) + iterator(oref const &data) : data{ data } { } @@ -143,7 +143,7 @@ namespace jank::runtime iterator end() const { - return { jank_nil }; + return { jank_nil() }; } sequence_range skip(usize const n) const @@ -163,7 +163,7 @@ namespace jank::runtime template requires behavior::seqable - auto make_sequence_range(oref const s) + auto make_sequence_range(oref const &s) { using S = typename decltype(s->seq())::value_type; diff --git a/compiler+runtime/include/cpp/jank/runtime/var.hpp b/compiler+runtime/include/cpp/jank/runtime/var.hpp index 4a8c5b442..01424e4db 100644 --- a/compiler+runtime/include/cpp/jank/runtime/var.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/var.hpp @@ -5,8 +5,10 @@ #include #include + #include #include +#include namespace jank::runtime { @@ -15,21 +17,16 @@ namespace jank::runtime using var_thread_binding_ref = oref; using var_unbound_root_ref = oref; - namespace obj - { - using persistent_hash_map_ref = oref; - } - - struct var : gc + struct var { static constexpr object_type obj_type{ object_type::var }; static constexpr bool pointer_free{ false }; var() = delete; - var(ns_ref const &n, obj::symbol_ref const &name); - var(ns_ref const &n, obj::symbol_ref const &name, object_ref root); - var(ns_ref const &n, - obj::symbol_ref const &name, + var(ns_ref const n, obj::symbol_ref const name); + var(ns_ref const n, obj::symbol_ref const name, object_ref const root); + var(ns_ref const n, + obj::symbol_ref const name, object_ref const root, bool dynamic, bool thread_bound); @@ -45,19 +42,20 @@ namespace jank::runtime bool equal(var const &) const; /* behavior::metadatable */ - var_ref with_meta(object_ref m); + var_ref with_meta(object_ref const m); bool is_bound() const; object_ref get_root() const; /* Binding a root changes it for all threads. */ - var_ref bind_root(object_ref r); - object_ref alter_root(object_ref f, object_ref args); + var_ref bind_root(object_ref const r); + object_ref alter_root(object_ref const f, object_ref const args); /* Setting a var does not change its root, it only affects the current thread * binding. If there is no thread binding, a var cannot be set. */ - jtl::string_result set(object_ref r) const; + jtl::string_result set(object_ref const r) const; var_ref set_dynamic(bool dyn); + obj::symbol_ref to_qualified_symbol() const; var_thread_binding_ref get_thread_binding() const; /* behavior::derefable */ @@ -82,12 +80,12 @@ namespace jank::runtime std::atomic_bool thread_bound{ false }; }; - struct var_thread_binding : gc + struct var_thread_binding { static constexpr object_type obj_type{ object_type::var_thread_binding }; static constexpr bool pointer_free{ false }; - var_thread_binding(object_ref value, std::thread::id id); + var_thread_binding(object_ref const value, std::thread::id id); /* behavior::object_like */ bool equal(object const &) const; @@ -106,12 +104,12 @@ namespace jank::runtime obj::persistent_hash_map_ref bindings{}; }; - struct var_unbound_root : gc + struct var_unbound_root { static constexpr object_type obj_type{ object_type::var_unbound_root }; static constexpr bool pointer_free{ true }; - var_unbound_root(var_ref var); + var_unbound_root(var_ref const var); /* behavior::object_like */ bool equal(object const &) const; @@ -125,36 +123,24 @@ namespace jank::runtime }; } -/* TODO: Move these to the .cpp */ namespace std { template <> struct hash { - size_t operator()(jank::runtime::var const &o) const noexcept - { - static auto hasher(std::hash{}); - return hasher(*o.name); - } + size_t operator()(jank::runtime::var const &o) const noexcept; }; template <> struct hash { - size_t operator()(jank::runtime::var_ref const &o) const noexcept - { - static auto hasher(std::hash{}); - return hasher(*o->name); - } + size_t operator()(jank::runtime::var_ref const o) const noexcept; }; template <> struct equal_to { bool - operator()(jank::runtime::var_ref const &lhs, jank::runtime::var_ref const &rhs) const noexcept - { - return lhs->equal(*rhs); - } + operator()(jank::runtime::var_ref const lhs, jank::runtime::var_ref const rhs) const noexcept; }; } diff --git a/compiler+runtime/include/cpp/jank/runtime/visit.hpp b/compiler+runtime/include/cpp/jank/runtime/visit.hpp index ef1f095d4..4cb2327d9 100644 --- a/compiler+runtime/include/cpp/jank/runtime/visit.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/visit.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -68,7 +69,7 @@ namespace jank::runtime template requires behavior::object_like [[gnu::hot]] - constexpr auto visit_object(F const &fn, oref const not_erased, Args &&...args) + auto visit_object(F const &fn, oref const not_erased, Args &&...args) { return fn(const_cast(¬_erased->base), std::forward(args)...); } @@ -213,21 +214,16 @@ namespace jank::runtime case object_type::opaque_box: return fn(expect_object(erased), std::forward(args)...); default: - { - jtl::string_builder sb; - sb("invalid object type: "); - sb(object_type_str(erased->type)); - sb(" raw value "); - sb(static_cast(erased->type)); - throw std::runtime_error{ sb.str() }; - } + jtl::panic("invalid object type: {}, raw value {}", + object_type_str(erased->type), + static_cast(erased->type)); } } /* Allows the visiting of a single type. */ template [[gnu::hot]] - constexpr auto visit_type(F const &fn, object_ref const erased, Args &&...args) + auto visit_type(F const &fn, object_ref const erased, Args &&...args) { if(erased->type == T::obj_type) { @@ -235,16 +231,16 @@ namespace jank::runtime } else { - throw std::runtime_error{ "invalid object type: " - + std::to_string(static_cast(erased->type)) }; + jtl::panic("invalid object type: {}, raw value {}", + object_type_str(erased->type), + static_cast(erased->type)); } } template requires(visitable && !std::convertible_to) [[gnu::hot]] - constexpr auto - visit_seqable(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) + auto visit_seqable(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch-enum" @@ -318,7 +314,7 @@ namespace jank::runtime /* Throws if the object isn't seqable. */ template [[gnu::hot]] - constexpr auto visit_seqable(F1 const &fn, object_ref const erased, Args &&...args) + auto visit_seqable(F1 const &fn, object_ref const erased, Args &&...args) { return visit_seqable( fn, @@ -336,8 +332,7 @@ namespace jank::runtime template requires(map_visitable && !std::convertible_to) [[gnu::hot]] - constexpr auto - visit_map_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) + auto visit_map_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch-enum" @@ -359,7 +354,7 @@ namespace jank::runtime /* Throws if the object isn't map-like. */ template [[gnu::hot]] - constexpr auto visit_map_like(F1 const &fn, object_ref const erased, Args &&...args) + auto visit_map_like(F1 const &fn, object_ref const erased, Args &&...args) { return visit_map_like( fn, @@ -373,8 +368,7 @@ namespace jank::runtime template requires(visitable && !std::convertible_to) [[gnu::hot]] - constexpr auto - visit_set_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) + auto visit_set_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch-enum" @@ -394,7 +388,7 @@ namespace jank::runtime /* Throws if the object isn't set-like. */ template [[gnu::hot]] - constexpr auto visit_set_like(F1 const &fn, object_ref const erased, Args &&...args) + auto visit_set_like(F1 const &fn, object_ref const erased, Args &&...args) { return visit_set_like( fn, @@ -408,8 +402,7 @@ namespace jank::runtime template requires(!std::convertible_to) [[gnu::hot]] - constexpr auto - visit_number_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) + auto visit_number_like(F1 const &fn, F2 const &else_fn, object_ref const erased, Args &&...args) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch-enum" @@ -434,7 +427,7 @@ namespace jank::runtime /* Throws if the object isn't number-like. */ template [[gnu::hot]] - constexpr auto visit_number_like(F1 const &fn, object_ref const erased, Args &&...args) + auto visit_number_like(F1 const &fn, object_ref const erased, Args &&...args) { return visit_number_like( fn, diff --git a/compiler+runtime/include/cpp/jank/runtime/weak_oref.hpp b/compiler+runtime/include/cpp/jank/runtime/weak_oref.hpp new file mode 100644 index 000000000..c90a60860 --- /dev/null +++ b/compiler+runtime/include/cpp/jank/runtime/weak_oref.hpp @@ -0,0 +1,456 @@ +#pragma once + +#include + +namespace jank::runtime +{ + template + struct weak_oref; + + /* This variation of ref is for type-erased objects. + * + * It cannot be null, but it can be nil. */ + template + requires(jtl::is_same, object>) + struct weak_oref + { + using value_type = object; + + weak_oref() + : data{ std::bit_cast(jank_const_nil()) } + { + } + + weak_oref(weak_oref const &rhs) = default; + weak_oref(weak_oref &&) noexcept = default; + + weak_oref(oref const &rhs) + : data{ rhs.data } + { + } + + weak_oref(nullptr_t) noexcept = delete; + + weak_oref(value_type * const data) + : data{ data } + { + jank_assert_throw(data); + } + + weak_oref(value_type const * const data) + : data{ const_cast(data) } + { + jank_assert_throw(data); + } + + template + requires behavior::object_like + weak_oref(T * const typed_data) + : data{ &typed_data->base } + { + jank_assert_throw(this->data); + } + + template + requires behavior::object_like + weak_oref(T const * const typed_data) + : data{ const_cast(&typed_data->base) } + { + jank_assert_throw(this->data); + } + + template + requires behavior::object_like + weak_oref(weak_oref const typed_data) noexcept + : data{ typed_data.erase().data } + { + } + + template + requires behavior::object_like + weak_oref(oref const &typed_data) noexcept + : data{ typed_data.erase().data } + { + } + + value_type *operator->() const + { + jank_assert_throw(data); + return data; + } + + value_type &operator*() const + { + jank_assert_throw(data); + return *data; + } + + weak_oref &operator=(weak_oref const &rhs) noexcept = default; + weak_oref &operator=(weak_oref &&rhs) noexcept = default; + + template + requires behavior::object_like + weak_oref &operator=(weak_oref const &rhs) noexcept + { + data = &rhs->base; + return *this; + } + + bool operator==(weak_oref const &rhs) const noexcept + { + return data == rhs.data; + } + + template + requires behavior::object_like + bool operator==(weak_oref const &rhs) const noexcept + { + return data == rhs.erase().data; + } + + bool operator!=(weak_oref const &rhs) const noexcept + { + return data != rhs.data; + } + + template + requires behavior::object_like + bool operator!=(weak_oref const &rhs) const noexcept + { + return data != rhs.erase().data; + } + + weak_oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; + + operator oref() const noexcept + { + return data; + } + + oref strong() const noexcept + { + return data; + } + + value_type *get() const noexcept + { + return data; + } + + weak_oref erase() const noexcept + { + return data; + } + + bool is_some() const noexcept + { + return data->type != object_type::nil; + } + + bool is_nil() const noexcept + { + return data->type == object_type::nil; + } + + value_type *data{}; + }; + + /* This specialization of weak_oref is for fully-typed objects like nil, + * persistent_list, persistent_array_map, etc. + * + * It cannot be null, but it can be nil. */ + template + struct weak_oref + { + using value_type = T; + + weak_oref() + : data{ std::bit_cast(jank_const_nil()) } + { + } + + weak_oref(nullptr_t) = delete; + + weak_oref(jtl::remove_const_t * const data) + : data{ data } + { + jank_assert_throw(this->data); + } + + weak_oref(T const * const data) + : data{ const_cast(data) } + { + jank_assert_throw(this->data); + } + + template + requires jtl::is_convertible + weak_oref(weak_oref const data) noexcept + : data{ data.data } + { + } + + template + requires jtl::is_convertible + weak_oref(oref const &data) noexcept + : data{ data.data } + { + } + + template + requires(C::obj_type == object_type::nil) + weak_oref(weak_oref const data) noexcept + : data{ data.data } + { + } + + template + requires(C::obj_type == object_type::nil) + weak_oref(oref const data) noexcept + : data{ data.data } + { + } + + T *operator->() const + { + /* TODO: Add type name. */ + //jank_assert_fmt_throw(*this, "Null reference on weak_oref<{}>", jtl::type_name()); + jank_assert_throw(is_some()); + return reinterpret_cast(data); + } + + T &operator*() const + { + //jank_assert_fmt_throw(*this, "Null reference on weak_oref<{}>", jtl::type_name()); + jank_assert_throw(is_some()); + return *reinterpret_cast(data); + } + + bool operator==(weak_oref const &rhs) const + { + return erase().data == rhs.erase().data; + } + + bool operator!=(weak_oref const &rhs) const + { + return erase().data != rhs.erase().data; + } + + template + requires behavior::object_like + bool operator==(weak_oref const &rhs) const + { + return data == rhs.data; + } + + template + requires behavior::object_like + bool operator!=(weak_oref const &rhs) const + { + return data != rhs.data; + } + + weak_oref &operator=(std::remove_cv_t> * const rhs) + { + data = rhs; + jank_assert_throw(data); + return *this; + } + + weak_oref &operator=(std::remove_cv_t> const * const rhs) + { + data = const_cast(rhs); + jank_assert_throw(data); + return *this; + } + + template + requires(C::obj_type == object_type::nil) + weak_oref &operator=(weak_oref const &) noexcept + { + data = std::bit_cast(jank_const_nil()); + return *this; + } + + weak_oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; + + operator oref() const noexcept + { + if(is_nil()) + { + return {}; + } + return reinterpret_cast(data); + } + + operator oref() const noexcept + { + return erase(); + } + + oref strong() const noexcept + { + return static_cast>(*this); + } + + object *get() const noexcept + { + return erase(); + } + + weak_oref erase() const noexcept + { + if(is_nil()) + { + return {}; + } + return &reinterpret_cast(data)->base; + } + + bool is_some() const noexcept + { + return data != std::bit_cast(jank_const_nil()); + } + + bool is_nil() const noexcept + { + return data == std::bit_cast(jank_const_nil()); + } + + void *data{}; + }; + + template <> + struct weak_oref + { + using value_type = obj::nil; + + weak_oref() + : data{ std::bit_cast(jank_const_nil()) } + { + } + + weak_oref(nullptr_t) = delete; + + weak_oref(value_type * const data) + : data{ data } + { + jank_assert_throw(this->data); + } + + weak_oref(value_type const * const data) + : data{ const_cast(data) } + { + jank_assert_throw(this->data); + } + + template + requires jtl::is_convertible + weak_oref(oref const data) noexcept + : data{ data.data } + { + } + + template + requires(C::obj_type == object_type::nil) + weak_oref(weak_oref const data) noexcept + : data{ data.data } + { + } + + template + requires(C::obj_type == object_type::nil) + weak_oref(oref const data) noexcept + : data{ data.data } + { + } + + value_type *operator->() const + { + return data; + } + + value_type &operator*() const + { + return *data; + } + + bool operator==(weak_oref const &rhs) const + { + return rhs.is_nil(); + } + + bool operator!=(weak_oref const &rhs) const + { + return rhs.is_some(); + } + + template + requires behavior::object_like + bool operator==(weak_oref const &rhs) const + { + return rhs.is_nil(); + } + + template + requires behavior::object_like + bool operator!=(weak_oref const &rhs) const + { + return rhs.is_some(); + } + + weak_oref &operator=(jtl::nullptr_t) noexcept = delete; + bool operator==(jtl::nullptr_t) noexcept = delete; + bool operator!=(jtl::nullptr_t) noexcept = delete; + + template + requires behavior::object_like + operator oref() const noexcept + { + return {}; + } + + operator oref() const noexcept + { + return {}; + } + + oref strong() const noexcept + { + return {}; + } + + object *get() const noexcept + { + return std::bit_cast(data); + } + + weak_oref erase() const noexcept + { + return std::bit_cast(data); + } + + bool is_some() const noexcept + { + return false; + } + + bool is_nil() const noexcept + { + return true; + } + + value_type *data{}; + }; + + template + weak_oref make_box(weak_oref const &o) + { + static_assert(sizeof(weak_oref) == sizeof(T *)); + return o; + } +} diff --git a/compiler+runtime/include/cpp/jank/type.hpp b/compiler+runtime/include/cpp/jank/type.hpp index dbd3eef3a..0fb35c802 100644 --- a/compiler+runtime/include/cpp/jank/type.hpp +++ b/compiler+runtime/include/cpp/jank/type.hpp @@ -43,7 +43,7 @@ namespace jank template using native_list = std::list>; template - using native_map = std::map>>; + using native_map = std::map, native_allocator>>; template using native_set = std::set, native_allocator>; diff --git a/compiler+runtime/include/cpp/jank/util/cli.hpp b/compiler+runtime/include/cpp/jank/util/cli.hpp index 8e792b4eb..603a25dbb 100644 --- a/compiler+runtime/include/cpp/jank/util/cli.hpp +++ b/compiler+runtime/include/cpp/jank/util/cli.hpp @@ -21,15 +21,55 @@ namespace jank::util::cli cpp }; + constexpr char const *codegen_type_str(codegen_type const type) + { + switch(type) + { + case codegen_type::llvm_ir: + return "llvm-ir"; + case codegen_type::cpp: + return "cpp"; + default: + return "unknown"; + } + } + + enum class compilation_target : u8 + { + /* The target will be determined based on the extension of the output. + * If that's not possible, we'll error out. */ + unspecified, + llvm_ir, + cpp, + object + }; + + constexpr char const *compilation_target_str(compilation_target const target) + { + switch(target) + { + case compilation_target::unspecified: + return "unspecified"; + case compilation_target::llvm_ir: + return "llvm-ir"; + case compilation_target::cpp: + return "cpp"; + case compilation_target::object: + return "object"; + default: + return "unknown"; + } + } + struct options { /* Runtime. */ - std::string module_path; - std::string profiler_file{ "jank.profile" }; + jtl::immutable_string module_path; + jtl::immutable_string profiler_file{ "jank.profile" }; bool profiler_enabled{}; bool perf_profiling_enabled{}; bool gc_incremental{}; - codegen_type codegen{ codegen_type::llvm_ir }; + codegen_type codegen{ codegen_type::cpp }; /* Native dependencies. */ native_vector include_dirs; @@ -43,21 +83,22 @@ namespace jank::util::cli bool direct_call{}; /* Run command. */ - std::string target_file; + jtl::immutable_string target_file; /* Compile command. */ - std::string target_module; - std::string target_runtime{ "dynamic" }; - std::string output_filename{ "a.out" }; - std::string output_object_filename; + jtl::immutable_string target_module; + jtl::immutable_string target_runtime{ "dynamic" }; + jtl::immutable_string output_filename{ "a.out" }; + + /* Compile-module command. */ + jtl::immutable_string output_module_filename; + compilation_target output_target{ compilation_target::unspecified }; /* REPL command. */ bool repl_server{}; - /* Extras. - * TODO: Use a native_persistent_vector instead. - * */ - std::vector extra_opts; + /* Extra flags, which will be passed to main. */ + native_vector extra_opts; command command{ command::repl }; }; @@ -65,6 +106,9 @@ namespace jank::util::cli /* NOLINTNEXTLINE */ extern options opts; - jtl::result parse(int const argc, char const **argv); - std::vector parse_empty(int const argc, char const **argv); + /* Affects the global opts. */ + jtl::result parse_opts(int const argc, char const **argv); + + /* Takes the CLI args and puts 'em in a vector. */ + native_vector parse_into_vector(int const argc, char const **argv); } diff --git a/compiler+runtime/include/cpp/jank/util/try.hpp b/compiler+runtime/include/cpp/jank/util/try.hpp index 17ed277fe..718c4e36a 100644 --- a/compiler+runtime/include/cpp/jank/util/try.hpp +++ b/compiler+runtime/include/cpp/jank/util/try.hpp @@ -69,7 +69,7 @@ namespace jank::util fun(e); \ then; \ } \ - catch(jank::error_ref const &e) \ + catch(jank::error_ref const e) \ { \ fun(e); \ then; \ diff --git a/compiler+runtime/include/cpp/jtl/immutable_string.hpp b/compiler+runtime/include/cpp/jtl/immutable_string.hpp index afc94dc41..ba05ea857 100644 --- a/compiler+runtime/include/cpp/jtl/immutable_string.hpp +++ b/compiler+runtime/include/cpp/jtl/immutable_string.hpp @@ -54,12 +54,10 @@ namespace jtl struct immutable_string { using value_type = char; - using allocator_type = jank::native_allocator; - using allocator_traits = std::allocator_traits; - using size_type = allocator_traits::size_type; using traits_type = std::char_traits; using pointer_type = value_type *; using const_pointer_type = value_type const *; + using size_type = usize; using iterator = pointer_type; using const_iterator = const_pointer_type; using reverse_iterator = std::reverse_iterator; @@ -705,7 +703,7 @@ namespace jtl * 3. As a large_storage instance, containing a pointer, size, and capacity */ /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) */ - struct storage : allocator_type + struct storage { /* TODO: What if we store a max of 22 chars and dedicate a byte for flags with no masking? */ union { @@ -724,7 +722,8 @@ namespace jtl /* NOTE: No performance difference between if/switch here. */ if(get_category() == category::large_owned) { - allocator_traits::deallocate(store, store.large.data, store.large.size + 1); + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + free(store.large.data); } } @@ -747,7 +746,7 @@ namespace jtl jank_debug_assert(s <= max_small_size); /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) */ store.small[s] = 0; - store.small[max_small_size] = value_type((max_small_size - s) << small_shift); + store.small[max_small_size] = static_cast((max_small_size - s) << small_shift); jank_debug_assert(get_category() == category::small && size() == s); } @@ -838,7 +837,9 @@ namespace jtl { jank_debug_assert(max_small_size < size); /* TODO: Apply gnu::malloc to this fn. */ - store.large.data = std::assume_aligned(store.allocate(size + 1)); + store.large.data + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + = std::assume_aligned(static_cast(malloc(size + 1))); traits_type::copy(store.large.data, data, size); store.large.data[size] = 0; store.large.size = size; @@ -849,7 +850,9 @@ namespace jtl constexpr void init_large_fill(value_type const fill, u8 const size) noexcept { jank_debug_assert(max_small_size < size); - store.large.data = std::assume_aligned(store.allocate(size + 1)); + store.large.data + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + = std::assume_aligned(static_cast(malloc(size + 1))); traits_type::assign(store.large.data, size, fill); store.large.data[size] = 0; store.large.size = size; @@ -864,7 +867,9 @@ namespace jtl { auto const size(lhs_size + rhs_size); jank_debug_assert(max_small_size < size); - store.large.data = std::assume_aligned(store.allocate(size + 1)); + store.large.data + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + = std::assume_aligned(static_cast(malloc(size + 1))); traits_type::copy(store.large.data, lhs, lhs_size); traits_type::copy(store.large.data + lhs_size, rhs, rhs_size); store.large.data[size] = 0; @@ -878,7 +883,9 @@ namespace jtl { auto const size(std::distance(begin, end)); jank_debug_assert(max_small_size < size); - store.large.data = std::assume_aligned(store.allocate(size + 1)); + store.large.data + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + = std::assume_aligned(static_cast(malloc(size + 1))); std::copy(begin, end, store.large.data); store.large.data[size] = 0; store.large.size = size; diff --git a/compiler+runtime/include/cpp/jtl/panic.hpp b/compiler+runtime/include/cpp/jtl/panic.hpp index 19d39a02e..4a42ddf70 100644 --- a/compiler+runtime/include/cpp/jtl/panic.hpp +++ b/compiler+runtime/include/cpp/jtl/panic.hpp @@ -8,6 +8,7 @@ namespace jtl { namespace detail { + [[noreturn]] void panic(char const *msg); } diff --git a/compiler+runtime/include/cpp/jtl/ref.hpp b/compiler+runtime/include/cpp/jtl/ref.hpp index 818ba3e41..7fca2646c 100644 --- a/compiler+runtime/include/cpp/jtl/ref.hpp +++ b/compiler+runtime/include/cpp/jtl/ref.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include #include #include @@ -101,23 +99,8 @@ namespace jtl ref make_ref(Args &&...args) { static_assert(sizeof(ref) == sizeof(T *)); - T *ret{}; - if constexpr(requires { T::pointer_free; }) - { - if constexpr(T::pointer_free) - { - ret = new(PointerFreeGC) T{ jtl::forward(args)... }; - } - else - { - ret = new(GC) T{ jtl::forward(args)... }; - } - } - else - { - ret = new(GC) T{ jtl::forward(args)... }; - } - + /* TODO: Figure out cleanup for this. */ + T *ret{ new(GC) T{ jtl::forward(args)... } }; jank_debug_assert(ret); return ret; } diff --git a/compiler+runtime/include/cpp/jtl/result.hpp b/compiler+runtime/include/cpp/jtl/result.hpp index 6162aa035..3fbd9d5ef 100644 --- a/compiler+runtime/include/cpp/jtl/result.hpp +++ b/compiler+runtime/include/cpp/jtl/result.hpp @@ -6,6 +6,12 @@ #include #include +namespace jank::error +{ + [[noreturn]] + void throw_internal_failure(jtl::immutable_string const &message); +} + namespace jtl { namespace detail @@ -30,6 +36,37 @@ namespace jtl struct result { }; + + template + [[noreturn]] + constexpr void panic(Result const &r) + { + using E = typename Result::error_type; + + /* A result can hold any type of error type, but when we expect a value + * and it's not there, we only want to throw a jank::error_ref. This + * not only makes catching easier, it also fits into our error reporting. + * + * So we need to do some work here to see if we have an error_ref, something + * we can use to build an error_ref (like a string), or just something else. */ + + /* This is a roundabout way of looking for error_ref. */ + if constexpr(requires(E t) { E::value_type::is_error; }) + { + throw r.expect_err(); + } + else if constexpr(jtl::is_same) + { + jank::error::throw_internal_failure(r.expect_err()); + } + else + { + immutable_string s{ "Unexpected result<" }; + s = s + type_name().data(); + s = s + ">"; + jank::error::throw_internal_failure(s); + } + } } constexpr detail::result ok() noexcept @@ -54,6 +91,9 @@ namespace jtl { static_assert(!std::same_as, "Result and error type must be different."); + using value_type = R; + using error_type = E; + constexpr result(detail::result &&r) noexcept : data{ R{ std::move(r.data) } } { @@ -112,9 +152,13 @@ namespace jtl return; } - /* TODO: Update all of these throws to throw a consistent type, regardless of the - * error type. This simplifies our catching logic. */ - throw expect_err(); + detail::panic(*this); + } + + constexpr R &expect_ok() + { + assert_ok(); + return std::get(data); } constexpr R const &expect_ok() const @@ -183,9 +227,8 @@ namespace jtl constexpr R unwrap_move() { if(!is_ok()) - /* TODO: Panic function. */ { - throw expect_err(); + detail::panic(*this); } return std::move(std::get(data)); } @@ -245,6 +288,8 @@ namespace jtl template struct [[nodiscard]] result { + using error_type = E; + constexpr result(detail::result &&) noexcept : data{ void_t{} } { @@ -288,7 +333,7 @@ namespace jtl return; } - throw expect_err(); + detail::panic(*this); } constexpr void expect_ok() const diff --git a/compiler+runtime/include/cpp/jtl/string_builder.hpp b/compiler+runtime/include/cpp/jtl/string_builder.hpp index d76874209..22767fd78 100644 --- a/compiler+runtime/include/cpp/jtl/string_builder.hpp +++ b/compiler+runtime/include/cpp/jtl/string_builder.hpp @@ -81,6 +81,7 @@ namespace jtl void reserve(usize capacity); value_type *data() const; usize size() const; + bool empty() const; jtl::immutable_string release(); std::string str() const; diff --git a/compiler+runtime/src/cpp/clojure/core_native.cpp b/compiler+runtime/src/cpp/clojure/core_native.cpp index 3c6d8e698..de1bdf027 100644 --- a/compiler+runtime/src/cpp/clojure/core_native.cpp +++ b/compiler+runtime/src/cpp/clojure/core_native.cpp @@ -32,7 +32,7 @@ namespace clojure::core_native { return runtime::visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -173,7 +173,7 @@ namespace clojure::core_native object_ref sleep(object_ref const ms) { std::this_thread::sleep_for(std::chrono::milliseconds(to_int(ms))); - return jank_nil; + return jank_nil(); } object_ref current_time() @@ -186,7 +186,7 @@ namespace clojure::core_native object_ref in_ns(object_ref const sym) { __rt_ctx->current_ns_var->set(__rt_ctx->intern_ns(try_object(sym))).expect_ok(); - return jank_nil; + return jank_nil(); } object_ref intern_ns(object_ref const sym) @@ -241,19 +241,19 @@ namespace clojure::core_native try_object(current_ns) ->add_alias(try_object(alias), try_object(remote_ns)) .expect_ok(); - return jank_nil; + return jank_nil(); } object_ref ns_unalias(object_ref const current_ns, object_ref const alias) { try_object(current_ns)->remove_alias(try_object(alias)); - return jank_nil; + return jank_nil(); } object_ref ns_unmap(object_ref const current_ns, object_ref const sym) { try_object(current_ns)->unmap(try_object(sym)).expect_ok(); - return jank_nil; + return jank_nil(); } object_ref refer(object_ref const current_ns, object_ref const sym, object_ref const var) @@ -261,19 +261,19 @@ namespace clojure::core_native expect_object(current_ns) ->refer(try_object(sym), expect_object(var)) .expect_ok(); - return jank_nil; + return jank_nil(); } object_ref load_module(object_ref const path) { __rt_ctx->load_module(runtime::to_string(path), module::origin::latest).expect_ok(); - return jank_nil; + return jank_nil(); } object_ref compile(object_ref const path) { __rt_ctx->compile_module(runtime::to_string(path)).expect_ok(); - return jank_nil; + return jank_nil(); } object_ref eval(object_ref const expr) @@ -298,7 +298,7 @@ namespace clojure::core_native } } -extern "C" jank_object_ref jank_load_clojure_core_native() +extern "C" void jank_load_clojure_core_native() { using namespace jank; using namespace jank::runtime; @@ -316,30 +316,23 @@ extern "C" jank_object_ref jank_load_clojure_core_native() __rt_ctx->intern_keyword("name").expect_ok(), make_box(obj::symbol{ __rt_ctx->current_ns()->to_string(), name }.to_string()))))); }); - auto const intern_fn_obj([=](jtl::immutable_string const &name, object_ref const fn) { - ns->intern_var(name)->bind_root(with_meta( - fn, - obj::persistent_hash_map::create_unique(std::make_pair( - __rt_ctx->intern_keyword("name").expect_ok(), - make_box(obj::symbol{ __rt_ctx->current_ns()->to_string(), name }.to_string()))))); - }); intern_fn("type", &type); intern_fn("nil?", &is_nil); intern_fn("identical?", &is_identical); intern_fn("empty?", &is_empty); intern_fn("empty", &empty); - intern_fn("count", static_cast(&sequence_length)); - intern_fn("boolean", static_cast(&truthy)); - intern_fn("integer", static_cast(&to_int)); - intern_fn("real", static_cast(&to_real)); - intern_fn("seq", static_cast(&seq)); - intern_fn("fresh-seq", static_cast(&fresh_seq)); - intern_fn("first", static_cast(&first)); - intern_fn("second", static_cast(&second)); - intern_fn("next", static_cast(&next)); - intern_fn("next-in-place", static_cast(&next_in_place)); - intern_fn("rest", static_cast(&rest)); + intern_fn("count", static_cast(&sequence_length)); + intern_fn("boolean", static_cast(&truthy)); + intern_fn("integer", static_cast(&to_int)); + intern_fn("real", static_cast(&to_real)); + intern_fn("seq", static_cast(&seq)); + intern_fn("fresh-seq", static_cast(&fresh_seq)); + intern_fn("first", static_cast(&first)); + intern_fn("second", static_cast(&second)); + intern_fn("next", static_cast(&next)); + intern_fn("next-in-place", static_cast(&next_in_place)); + intern_fn("rest", static_cast(&rest)); intern_fn("cons", &cons); intern_fn("coll?", &is_collection); intern_fn("seq?", &is_seq); @@ -351,12 +344,14 @@ extern "C" jank_object_ref jank_load_clojure_core_native() intern_fn("conj", &conj); intern_fn("map?", &is_map); intern_fn("associative?", &is_associative); - intern_fn("assoc", static_cast(&assoc)); - intern_fn("pr-str", static_cast(&to_code_string)); + intern_fn( + "assoc", + static_cast(&assoc)); + intern_fn("pr-str", static_cast(&to_code_string)); intern_fn("string?", &is_string); intern_fn("char?", &is_char); - intern_fn("to-string", static_cast(&to_string)); - intern_fn("str", static_cast(&str)); + intern_fn("str", + static_cast(&str)); intern_fn("symbol?", &is_symbol); intern_fn("true?", &is_true); intern_fn("false?", &is_false); @@ -376,7 +371,8 @@ extern "C" jank_object_ref jank_load_clojure_core_native() intern_fn("persistent!", &persistent); intern_fn("conj-in-place!", &conj_in_place); intern_fn("assoc-in-place!", - static_cast(&assoc_in_place)); + static_cast( + &assoc_in_place)); intern_fn("dissoc-in-place!", &dissoc_in_place); intern_fn("pop-in-place!", &pop_in_place); intern_fn("disj-in-place!", &disj_in_place); @@ -393,10 +389,10 @@ extern "C" jank_object_ref jank_load_clojure_core_native() intern_fn("volatile!", &volatile_); intern_fn("volatile?", &is_volatile); intern_fn("vreset!", &vreset); - intern_fn("+", static_cast(&add)); - intern_fn("-", static_cast(&sub)); - intern_fn("/", static_cast(&div)); - intern_fn("*", static_cast(&mul)); + intern_fn("+", static_cast(&add)); + intern_fn("-", static_cast(&sub)); + intern_fn("/", static_cast(&div)); + intern_fn("*", static_cast(&mul)); intern_fn("bit-not", &bit_not); intern_fn("bit-and", &bit_and); intern_fn("bit-or", &bit_or); @@ -409,20 +405,20 @@ extern "C" jank_object_ref jank_load_clojure_core_native() intern_fn("bit-shift-left", &bit_shift_left); intern_fn("bit-shift-right", &bit_shift_right); intern_fn("unsigned-bit-shift-right", &bit_unsigned_shift_right); - intern_fn("<", static_cast(<)); - intern_fn("<=", static_cast(<e)); + intern_fn("<", static_cast(<)); + intern_fn("<=", static_cast(<e)); intern_fn("compare", &runtime::compare); - intern_fn("min", static_cast(&min)); - intern_fn("max", static_cast(&max)); - intern_fn("inc", static_cast(&inc)); - intern_fn("dec", static_cast(&dec)); + intern_fn("min", static_cast(&min)); + intern_fn("max", static_cast(&max)); + intern_fn("inc", static_cast(&inc)); + intern_fn("dec", static_cast(&dec)); intern_fn("numerator", &numerator); intern_fn("denominator", &denominator); intern_fn("pos?", &is_pos); intern_fn("neg?", &is_neg); intern_fn("zero?", &is_zero); - intern_fn("rem", static_cast(&rem)); - intern_fn("quot", static_cast(")); + intern_fn("rem", &rem); + intern_fn("quot", "); intern_fn("integer?", &is_integer); intern_fn("real?", &is_real); intern_fn("ratio?", &is_ratio); @@ -531,324 +527,8 @@ extern "C" jank_object_ref jank_load_clojure_core_native() intern_fn("re-matches", &re_matches); /* TODO: jank.math? */ - intern_fn("sqrt", static_cast(&runtime::sqrt)); - intern_fn("tan", static_cast(&runtime::tan)); - intern_fn("abs", static_cast(&runtime::abs)); - intern_fn("pow", static_cast(&runtime::pow)); - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, false))); - fn->arity_1 = [](object *, object * const seq) -> object * { return list(seq).erase(); }; - intern_fn_obj("list", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(2, true, true))); - fn->arity_1 = [](object *, object *) -> object * { return jank_true.erase(); }; - fn->arity_2 = [](object *, object * const l, object * const r) -> object * { - return make_box(equal(l, r)).erase(); - }; - fn->arity_3 - = [](object *, object * const l, object * const r, object * const rest) -> object * { - if(!equal(l, r)) - { - return jank_false.erase(); - } - - return visit_seqable( - [](auto const typed_rest, object_ref const l) { - for(auto const e : make_sequence_range(typed_rest)) - { - if(!equal(l, e)) - { - return jank_false.erase(); - } - } - - return jank_true.erase(); - }, - rest, - l); - }; - intern_fn_obj("=", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(2, true, true))); - fn->arity_1 = [](object *, object *) -> object * { return jank_true.erase(); }; - fn->arity_2 = [](object *, object * const l, object * const r) -> object * { - return make_box(is_equiv(l, r)).erase(); - }; - fn->arity_3 - = [](object *, object * const l, object * const r, object * const rest) -> object * { - if(!is_equiv(l, r)) - { - return jank_false.erase(); - } - - for(auto it(fresh_seq(rest)); it != jank_nil; it = next_in_place(it)) - { - if(!is_equiv(l, first(it))) - { - return jank_false.erase(); - } - } - - return jank_true.erase(); - }; - intern_fn_obj("==", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, false))); - fn->arity_1 = [](object *, object * const seq) -> object * { return println(seq).erase(); }; - intern_fn_obj("println", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, false))); - fn->arity_1 = [](object *, object * const seq) -> object * { return print(seq).erase(); }; - intern_fn_obj("print", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, false))); - fn->arity_1 = [](object *, object * const seq) -> object * { return prn(seq).erase(); }; - intern_fn_obj("prn", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, false))); - fn->arity_1 = [](object *, object * const seq) -> object * { return pr(seq).erase(); }; - intern_fn_obj("pr", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, false, false))); - fn->arity_0 = [](object *) -> object * { return gensym(make_box("G__")).erase(); }; - fn->arity_1 - = [](object *, object * const prefix) -> object * { return gensym(prefix).erase(); }; - intern_fn_obj("gensym", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(4, true, true))); - fn->arity_2 = [](object *, object * const atom, object * const fn) -> object * { - return try_object(atom)->swap(fn).erase(); - }; - fn->arity_3 - = [](object *, object * const atom, object * const fn, object * const a1) -> object * { - return try_object(atom)->swap(fn, a1).erase(); - }; - fn->arity_4 - = [](object *, object * const atom, object * const fn, object * const a1, object * const a2) - -> object * { return try_object(atom)->swap(fn, a1, a2).erase(); }; - fn->arity_5 = [](object *, - object * const atom, - object * const fn, - object * const a1, - object * const a2, - object * const rest) -> object * { - return try_object(atom)->swap(fn, a1, a2, rest).erase(); - }; - intern_fn_obj("swap!", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(4, true, true))); - fn->arity_2 = [](object *, object * const atom, object * const fn) -> object * { - return try_object(atom)->swap_vals(fn).erase(); - }; - fn->arity_3 - = [](object *, object * const atom, object * const fn, object * const a1) -> object * { - return try_object(atom)->swap_vals(fn, a1).erase(); - }; - fn->arity_4 - = [](object *, object * const atom, object * const fn, object * const a1, object * const a2) - -> object * { return try_object(atom)->swap_vals(fn, a1, a2).erase(); }; - fn->arity_5 = [](object *, - object * const atom, - object * const fn, - object * const a1, - object * const a2, - object * const rest) -> object * { - return try_object(atom)->swap_vals(fn, a1, a2, rest).erase(); - }; - intern_fn_obj("swap-vals!", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(2, true, true))); - fn->arity_2 = [](object *, object * const vol, object * const fn) -> object * { - return vswap(vol, fn).erase(); - }; - fn->arity_3 - = [](object *, object * const vol, object * const fn, object * const rest) -> object * { - return vswap(vol, fn, rest).erase(); - }; - intern_fn_obj("vswap!", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, false, false))); - fn->arity_2 = [](object *, object * const s, object * const start) -> object * { - return subs(s, start).erase(); - }; - fn->arity_3 - = [](object *, object * const s, object * const start, object * const end) -> object * { - return subs(s, start, end).erase(); - }; - intern_fn_obj("subs", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, true))); - fn->arity_0 = [](object *) -> object * { return obj::persistent_hash_map::empty().erase(); }; - fn->arity_1 = [](object *, object * const kvs) -> object * { - return obj::persistent_hash_map::create_from_seq(kvs).erase(); - }; - intern_fn_obj("hash-map", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, true))); - fn->arity_0 = [](object *) -> object * { return obj::persistent_sorted_map::empty().erase(); }; - fn->arity_1 = [](object *, object * const kvs) -> object * { - return obj::persistent_sorted_map::create_from_seq(kvs).erase(); - }; - intern_fn_obj("sorted-map", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, true))); - fn->arity_0 = [](object *) -> object * { return obj::persistent_hash_set::empty().erase(); }; - fn->arity_1 = [](object *, object * const kvs) -> object * { - return obj::persistent_hash_set::create_from_seq(kvs).erase(); - }; - intern_fn_obj("hash-set", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(0, true, true))); - fn->arity_0 = [](object *) -> object * { return obj::persistent_sorted_set::empty().erase(); }; - fn->arity_1 = [](object *, object * const kvs) -> object * { - return obj::persistent_sorted_set::create_from_seq(kvs).erase(); - }; - intern_fn_obj("sorted-set", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(3, false, false))); - fn->arity_2 - = [](object *, object * const o, object * const k) -> object * { return get(o, k).erase(); }; - fn->arity_3 - = [](object *, object * const o, object * const k, object * const fallback) -> object * { - return get(o, k, fallback).erase(); - }; - intern_fn_obj("get", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(3, false, false))); - fn->arity_2 = [](object *, object * const o, object * const k) -> object * { - return get_in(o, k).erase(); - }; - fn->arity_3 - = [](object *, object * const o, object * const k, object * const fallback) -> object * { - return get_in(o, k, fallback).erase(); - }; - intern_fn_obj("get-in", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(3, false, false))); - fn->arity_0 = [](object *) -> object * { - return iterate(__rt_ctx->intern_var("clojure.core", "inc").expect_ok()->deref(), make_box(0)) - .erase(); - }; - fn->arity_1 - = [](object *, object * const end) -> object * { return obj::range::create(end).erase(); }; - fn->arity_2 = [](object *, object * const start, object * const end) -> object * { - return obj::range::create(start, end).erase(); - }; - fn->arity_3 - = [](object *, object * const start, object * const end, object * const step) -> object * { - return obj::range::create(start, end, step).erase(); - }; - intern_fn_obj("range", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(3, false, false))); - fn->arity_0 = [](object *) -> object * { - return iterate(__rt_ctx->intern_var("clojure.core", "inc").expect_ok()->deref(), make_box(0)) - .erase(); - }; - fn->arity_1 = [](object *, object * const end) -> object * { - return obj::integer_range::create(try_object(end)).erase(); - }; - fn->arity_2 = [](object *, object * const start, object * const end) -> object * { - return obj::integer_range::create(try_object(start), - try_object(end)) - .erase(); - }; - fn->arity_3 - = [](object *, object * const start, object * const end, object * const step) -> object * { - return obj::integer_range::create(try_object(start), - try_object(end), - try_object(step)) - .erase(); - }; - intern_fn_obj("integer-range", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(3, false, false))); - fn->arity_0 = [](object *) -> object * { - return iterate(__rt_ctx->intern_var("clojure.core", "inc").expect_ok()->deref(), make_box(0)) - .erase(); - }; - fn->arity_2 = [](object *, object * const coll, object * const index) -> object * { - return nth(coll, index).erase(); - }; - fn->arity_3 = - [](object *, object * const coll, object * const index, object * const fallback) -> object * { - return nth(coll, index, fallback).erase(); - }; - intern_fn_obj("nth", fn); - } - - { - auto const fn( - make_box(behavior::callable::build_arity_flags(2, false, false))); - fn->arity_1 - = [](object *, object * const val) -> object * { return obj::repeat::create(val).erase(); }; - fn->arity_2 = [](object *, object * const n, object * const val) -> object * { - return obj::repeat::create(n, val).erase(); - }; - intern_fn_obj("repeat", fn); - } - - return jank_nil.erase(); + intern_fn("sqrt", static_cast(&runtime::sqrt)); + intern_fn("tan", static_cast(&runtime::tan)); + intern_fn("abs", static_cast(&runtime::abs)); + intern_fn("pow", static_cast(&runtime::pow)); } diff --git a/compiler+runtime/src/cpp/jank/analyze/cpp_util.cpp b/compiler+runtime/src/cpp/jank/analyze/cpp_util.cpp index aac12ebaa..3a3fb783f 100644 --- a/compiler+runtime/src/cpp/jank/analyze/cpp_util.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/cpp_util.cpp @@ -292,6 +292,44 @@ namespace jank::analyze::cpp_util return res; } + jtl::immutable_string get_qualified_type_name(jtl::ptr const type) + { + if(type == untyped_object_ptr_type()) + { + return "jank::runtime::object_ref"; + } + /* TODO: Handle typed object refs, too. */ + + /* TODO: We probably want a recursive approach to this, for types and scopes. */ + auto const qual_type{ clang::QualType::getFromOpaquePtr(type) }; + if(qual_type->isNullPtrType()) + { + return "std::nullptr_t"; + } + + if(auto const *alias{ + llvm::dyn_cast_or_null(qual_type.getTypePtrOrNull()) }; + alias) + { + if(auto const *alias_decl{ alias->getDecl() }; alias_decl) + { + return get_qualified_name(alias_decl); + } + } + + if(auto const scope{ Cpp::GetScopeFromType(type) }; scope) + { + auto name{ get_qualified_name(scope) }; + if(Cpp::IsPointerType(type)) + { + name = name + "*"; + } + return name; + } + + return Cpp::GetTypeAsString(type); + } + /* This is a quick and dirty helper to get the RTTI for a given QualType. We need * this for exception catching. */ void register_rtti(jtl::ptr const type) diff --git a/compiler+runtime/src/cpp/jank/analyze/expr/cpp_type.cpp b/compiler+runtime/src/cpp/jank/analyze/expr/cpp_type.cpp index 5cc5fb46b..c8ff94ed5 100644 --- a/compiler+runtime/src/cpp/jank/analyze/expr/cpp_type.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/expr/cpp_type.cpp @@ -8,7 +8,7 @@ namespace jank::analyze::expr cpp_type::cpp_type(expression_position const position, local_frame_ptr const frame, bool const needs_box, - runtime::obj::symbol_ref sym, + runtime::obj::symbol_ref const sym, jtl::ptr const type) : expression{ expr_kind, position, frame, needs_box } , sym{ sym } diff --git a/compiler+runtime/src/cpp/jank/analyze/expr/function.cpp b/compiler+runtime/src/cpp/jank/analyze/expr/function.cpp index dc88c8ca5..388adbc89 100644 --- a/compiler+runtime/src/cpp/jank/analyze/expr/function.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/expr/function.cpp @@ -29,7 +29,7 @@ namespace jank::analyze::expr object_ref function_arity::to_runtime_data() const { object_ref param_maps(make_box()); - for(auto const e : params) + for(auto const &e : params) { param_maps = conj(param_maps, e); } diff --git a/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp b/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp index d5dc397db..be49eaa6c 100644 --- a/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,16 +14,6 @@ namespace jank::analyze { using namespace jank::runtime; - object_ref lifted_var::to_runtime_data() const - { - return obj::persistent_array_map::create_unique(make_box("var_name"), var_name); - } - - object_ref lifted_constant::to_runtime_data() const - { - return obj::persistent_array_map::create_unique(make_box("data"), data); - } - object_ref local_binding::to_runtime_data() const { return obj::persistent_array_map::create_unique( @@ -47,7 +38,7 @@ namespace jank::analyze } static jtl::option - find_local_impl(local_frame_ptr const start, obj::symbol_ref sym, bool const allow_captures) + find_local_impl(local_frame_ptr const start, obj::symbol_ref const sym, bool const allow_captures) { decltype(local_frame::binding_find_result::crossed_fns) crossed_fns; @@ -103,6 +94,13 @@ namespace jank::analyze res.first->second.has_boxed_usage = true; /* To start with, we assume it's only boxed. */ res.first->second.has_unboxed_usage = false; + + /* Native values which are captured get auto-boxed, so we need to adjust the type + * of the binding. */ + if(!cpp_util::is_any_object(res.first->second.type)) + { + res.first->second.type = cpp_util::untyped_object_ptr_type(); + } } } @@ -182,91 +180,15 @@ namespace jank::analyze return &find_closest_fn_frame(*l) == &find_closest_fn_frame(*r); } - obj::symbol_ref local_frame::lift_var(obj::symbol_ref const &sym) - { - auto &closest_fn(find_closest_fn_frame(*this)); - auto const &found(closest_fn.lifted_vars.find(sym)); - if(found != closest_fn.lifted_vars.end()) - { - return found->first; - } - - obj::symbol_ref qualified_sym{}; - if(sym->ns.empty()) - { - qualified_sym - = make_box(expect_object(__rt_ctx->current_ns_var->deref())->name->name, - sym->name); - } - else - { - qualified_sym = make_box(*sym); - } - - /* We use unique native names, just so var names don't clash with the underlying C++ API. */ - lifted_var lv{ __rt_ctx->unique_namespaced_string(munge(qualified_sym->name)), qualified_sym }; - closest_fn.lifted_vars.emplace(qualified_sym, std::move(lv)); - return qualified_sym; - } - - /* TODO: These are not used in IR gen. Remove entirely? */ - jtl::option> - local_frame::find_lifted_var(obj::symbol_ref const &sym) const - { - auto const &closest_fn(find_closest_fn_frame(*this)); - auto const &found(closest_fn.lifted_vars.find(sym)); - if(found != closest_fn.lifted_vars.end()) - { - return some(std::ref(found->second)); - } - return none; - } - - void local_frame::lift_constant(object_ref const constant) - { - auto &closest_fn(find_closest_fn_frame(*this)); - auto const &found(closest_fn.lifted_constants.find(constant)); - if(found != closest_fn.lifted_constants.end()) - { - return; - } - - auto const name(__rt_ctx->unique_symbol("const")); - auto const unboxed_name{ visit_number_like( - [&](auto const) -> jtl::option { return name.name + "__unboxed"; }, - []() -> jtl::option { return none; }, - constant) }; - - lifted_constant l{ name.name, unboxed_name, constant }; - closest_fn.lifted_constants.emplace(constant, std::move(l)); - } - - jtl::option> - local_frame::find_lifted_constant(object_ref const o) const - { - auto const &closest_fn(find_closest_fn_frame(*this)); - auto const &found(closest_fn.lifted_constants.find(o)); - if(found != closest_fn.lifted_constants.end()) - { - return some(std::ref(found->second)); - } - return none; - } - object_ref local_frame::to_runtime_data() const { - return obj::persistent_array_map::create_unique( - make_box("type"), - make_box(frame_type_str(type)), - make_box("parent"), - jank::detail::to_runtime_data(parent), - make_box("locals"), - jank::detail::to_runtime_data(locals), - make_box("captures"), - jank::detail::to_runtime_data(captures), - make_box("lifted_vars"), - jank::detail::to_runtime_data(lifted_vars), - make_box("lifted_constants"), - jank::detail::to_runtime_data(lifted_constants)); + return obj::persistent_array_map::create_unique(make_box("type"), + make_box(frame_type_str(type)), + make_box("parent"), + jank::detail::to_runtime_data(parent), + make_box("locals"), + jank::detail::to_runtime_data(locals), + make_box("captures"), + jank::detail::to_runtime_data(captures)); } } diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index 0d5262d3d..229df9061 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -1,5 +1,4 @@ #include -#include #include @@ -16,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -78,7 +78,7 @@ namespace jank::analyze auto const expansion( runtime::get(meta, __rt_ctx->intern_keyword("jank/macro-expansion").expect_ok())); - if(expansion == jank_nil) + if(expansion == jank_nil()) { return nullptr; } @@ -92,18 +92,18 @@ namespace jank::analyze { if(expansions.empty()) { - return jank_nil; + return jank_nil(); } /* Try to find an expansion which specifically has the `jank/macro-expansion` key * set in the meta. This is the root of our most recent expansion. */ - for(auto const latest : std::ranges::reverse_view(expansions)) + for(auto const &latest : std::ranges::reverse_view(expansions)) { auto const latest_meta{ meta(latest) }; auto const expansion( runtime::get(latest_meta, __rt_ctx->intern_keyword("jank/macro-expansion").expect_ok())); - if(expansion != jank_nil) + if(expansion != jank_nil()) { return expansion; } @@ -942,7 +942,9 @@ namespace jank::analyze latest_expansion(macro_expansions)); } if(is_ctor - && Cpp::IsAggregateConstructible(val->type, arg_types, __rt_ctx->unique_munged_string())) + && Cpp::IsAggregateConstructible(val->type, + arg_types, + runtime::munge(__rt_ctx->unique_namespaced_string()))) { //util::println("using aggregate initializaation"); return jtl::make_ref(position, @@ -1282,13 +1284,13 @@ namespace jank::analyze ->add_usage(read::parse::reparse_nth(l, 1)); } - auto qualified_sym(current_frame->lift_var(sym)); + auto qualified_sym(runtime::__rt_ctx->qualify_symbol(sym)); qualified_sym->meta = sym->meta; /* We always def in the current ns, so we want an owned var. */ - auto const var(__rt_ctx->intern_owned_var(qualified_sym)); - if(var.is_err()) + auto const var_res(__rt_ctx->intern_owned_var(qualified_sym)); + if(var_res.is_err()) { - return error::internal_analyze_failure(var.expect_err(), + return error::internal_analyze_failure(var_res.expect_err(), meta_source(sym), latest_expansion(macro_expansions)); } @@ -1316,7 +1318,7 @@ namespace jank::analyze } value_expr = some(value_result.expect_ok()); - vars.insert_or_assign(var.expect_ok(), value_expr.unwrap()); + vars.insert_or_assign(var_res.expect_ok(), value_expr.unwrap()); } if(has_docstring) @@ -1329,19 +1331,12 @@ namespace jank::analyze latest_expansion(macro_expansions)) ->add_usage(read::parse::reparse_nth(l, 2)); } - auto const meta_with_doc(runtime::assoc(qualified_sym->meta.unwrap_or(runtime::jank_nil), + auto const meta_with_doc(runtime::assoc(qualified_sym->meta.unwrap_or(runtime::jank_nil()), __rt_ctx->intern_keyword("doc").expect_ok(), docstring_obj)); qualified_sym = qualified_sym->with_meta(meta_with_doc); } - /* Lift this so it can be used during codegen. */ - /* TODO: I don't think lifting meta is actually needed anymore. Verify. */ - if(qualified_sym->meta.is_some()) - { - current_frame->lift_constant(qualified_sym->meta.unwrap()); - } - return jtl::make_ref(position, current_frame, true, qualified_sym, value_expr); } @@ -1578,6 +1573,8 @@ namespace jank::analyze auto &unwrapped_named_recursion(found_named_recursion.unwrap()); local_frame::register_captures(current_frame, unwrapped_named_recursion); + unwrapped_named_recursion.fn_frame->fn_ctx->is_named_recursive = true; + return jtl::make_ref( position, current_frame, @@ -1595,12 +1592,6 @@ namespace jank::analyze latest_expansion(macro_expansions)); } - /* Macros aren't lifted, since they're not used during runtime. */ - auto const macro_kw(__rt_ctx->intern_keyword("", "macro", true).expect_ok()); - if(var->meta.is_none() || get(var->meta.unwrap(), macro_kw).is_nil()) - { - current_frame->lift_var(qualified_sym); - } return jtl::make_ref(position, current_frame, true, qualified_sym, var); } @@ -1617,7 +1608,7 @@ namespace jank::analyze "The missing [] was expected here.", latest_expansion(macro_expansions)); } - auto const params_obj(first_form.unwrap()); + auto const ¶ms_obj(first_form.unwrap()); if(params_obj->type != runtime::object_type::persistent_vector) { return error::analyze_invalid_fn_parameters("A function parameter vector must be a vector.", @@ -1632,12 +1623,12 @@ namespace jank::analyze native_vector param_symbols; param_symbols.reserve(params->data.size()); - std::set unique_param_symbols; + native_set unique_param_symbols; bool is_variadic{}; for(auto it(params->data.begin()); it != params->data.end(); ++it) { - auto const p(*it); + auto const &p(*it); if(p->type != runtime::object_type::symbol) { auto const param_idx{ std::distance(params->data.begin(), it) }; @@ -1734,7 +1725,7 @@ namespace jank::analyze /* If it turns out this function uses recur, we need to ensure that its tail expression * is boxed. This is because unboxed values may use IIFE for initialization, which will * not work with the generated while/continue we use for recursion. */ - if(fn_ctx->is_tail_recursive) + if(fn_ctx->is_recur_recursive) { step::force_boxed(body_do); } @@ -1798,7 +1789,7 @@ namespace jank::analyze { auto const s(runtime::expect_object(first_elem)); name = s->name; - unique_name = __rt_ctx->unique_namespaced_string(name); + unique_name = __rt_ctx->unique_string(name); if(length < 3) { return error::analyze_invalid_fn("This function is missing its parameter vector.", @@ -1810,7 +1801,7 @@ namespace jank::analyze } else { - name = __rt_ctx->unique_namespaced_string("fn"); + name = __rt_ctx->unique_string("fn"); unique_name = name; } @@ -2036,7 +2027,7 @@ namespace jank::analyze } else { - fn_ctx.unwrap()->is_tail_recursive = true; + fn_ctx.unwrap()->is_recur_recursive = true; } return jtl::make_ref(position, @@ -2084,7 +2075,7 @@ namespace jank::analyze if(ret.values.empty()) { auto const nil{ - analyze_primitive_literal(jank_nil, current_frame, position, fn_ctx, needs_box) + analyze_primitive_literal(jank_nil(), current_frame, position, fn_ctx, needs_box) }; if(nil.is_err()) { @@ -2203,7 +2194,7 @@ namespace jank::analyze if(ret->body->values.empty()) { - auto const nil{ analyze_primitive_literal(jank_nil, + auto const nil{ analyze_primitive_literal(jank_nil(), ret->frame, expression_position::tail, fn_ctx, @@ -2259,7 +2250,7 @@ namespace jank::analyze /* All bindings in a letfn appear simultaneously and may be mutually recursive. * This makes creating a letfn locals frame a bit more involved than let, where locals - * are introduced left-to-right. For example, each binding in (letfn [(a [] b) (b [] a)]) + * are introduced left-to-right. For example, each binding in (letfn [(a [] b) (b [] a)]) * requires the other to be in scope in order to be analyzed. * * We tackle this in two steps. First, we create empty local bindings for all names. @@ -2308,7 +2299,7 @@ namespace jank::analyze /* Populate the local frame we prepared for sym in the previous loop with its binding. */ auto it(ret->pairs.emplace_back(sym, fexpr)); - auto local(ret->frame->locals.find(sym)->second); + auto &local(ret->frame->locals.find(sym)->second); local.value_expr = some(it.second); local.needs_box = it.second->needs_box; } @@ -2336,7 +2327,7 @@ namespace jank::analyze if(ret->body->values.empty()) { - auto const nil{ analyze_primitive_literal(jank_nil, + auto const nil{ analyze_primitive_literal(jank_nil(), ret->frame, expression_position::tail, fn_ctx, @@ -2544,7 +2535,7 @@ namespace jank::analyze auto const arg_sym(runtime::expect_object(arg)); - auto const qualified_sym(current_frame->lift_var(arg_sym)); + auto const qualified_sym{ __rt_ctx->qualify_symbol(arg_sym) }; auto const found_var(__rt_ctx->find_var(qualified_sym)); if(found_var.is_nil()) { @@ -2554,7 +2545,11 @@ namespace jank::analyze latest_expansion(macro_expansions)); } - return jtl::make_ref(position, current_frame, true, qualified_sym, found_var); + return jtl::make_ref(position, + current_frame, + true, + found_var->to_qualified_symbol(), + found_var); } processor::expression_result @@ -2566,8 +2561,7 @@ namespace jank::analyze { auto const pop_macro_expansions{ push_macro_expansions(*this, o) }; - auto const qualified_sym( - current_frame->lift_var(make_box(o->n->name->name, o->name->name))); + auto const qualified_sym(__rt_ctx->qualify_symbol(o->to_qualified_symbol())); return jtl::make_ref(position, current_frame, true, qualified_sym, o); } @@ -2634,7 +2628,8 @@ namespace jank::analyze finally_ }; - static runtime::obj::symbol catch_{ "catch" }, finally_{ "finally" }; + static runtime::obj::symbol_ref catch_{ make_box("catch") }, + finally_{ make_box("finally") }; bool has_catch{}, has_finally{}; for(auto it(list->fresh_seq()->next_in_place()); it.is_some(); it = it->next_in_place()) @@ -2642,7 +2637,7 @@ namespace jank::analyze auto const item(it->first()); auto const type(runtime::visit_seqable( [](auto const typed_item) { - using T = typename decltype(typed_item)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -2651,11 +2646,11 @@ namespace jank::analyze else { auto const first(runtime::first(typed_item->seq())); - if(runtime::equal(first, &catch_)) + if(runtime::equal(first, catch_)) { return try_expression_type::catch_; } - else if(runtime::equal(first, &finally_)) + else if(runtime::equal(first, finally_)) { return try_expression_type::finally_; } @@ -2817,8 +2812,6 @@ namespace jank::analyze bool const needs_box) { auto const pop_macro_expansions{ push_macro_expansions(*this, o) }; - - current_frame->lift_constant(o); return jtl::make_ref(position, current_frame, needs_box, o); } @@ -2863,9 +2856,6 @@ namespace jank::analyze jtl::make_ref(position, current_frame, true, std::move(exprs), o->meta)); auto const o(evaluate::eval(pre_eval_expr)); - /* TODO: Order lifted constants. Use sub constants during codegen. */ - current_frame->lift_constant(o); - return jtl::make_ref(position, current_frame, true, o); } @@ -2884,27 +2874,12 @@ namespace jank::analyze /* TODO: Detect literal and act accordingly. */ return visit_map_like( [&](auto const typed_o) -> processor::expression_result { - using T = typename decltype(typed_o)::value_type; - native_vector> exprs; exprs.reserve(typed_o->data.size()); for(auto const &kv : typed_o->data) { - /* The two maps (hash and sorted) have slightly different iterators, so we need to - * pull out the entries differently. */ - object_ref first{}, second{}; - if constexpr(std::same_as) - { - auto const &entry(kv.get()); - first = entry.first; - second = entry.second; - } - else - { - first = kv.first; - second = kv.second; - } + object_ref const first{ kv.first }, second{ kv.second }; auto k_expr(analyze(first, current_frame, expression_position::value, fn_ctx, true)); if(k_expr.is_err()) @@ -2989,9 +2964,6 @@ namespace jank::analyze typed_o->meta)); auto const constant(evaluate::eval(pre_eval_expr)); - /* TODO: Order lifted constants. Use sub constants during codegen. */ - current_frame->lift_constant(constant); - return jtl::make_ref(position, current_frame, true, constant); } @@ -3360,18 +3332,10 @@ namespace jank::analyze if(Cpp::IsVariable(scope)) { vk = expr::cpp_value::value_kind::variable; - /* TODO: A Clang bug prevents us from supporting references to static members. - * https://github.com/llvm/llvm-project/issues/146956 - */ - if(!Cpp::IsStaticDatamember(scope) && !Cpp::IsPointerType(type)) + if(!Cpp::IsPointerType(type)) { - /* TODO: Error if it's static and non-primitive. */ type = Cpp::GetLValueReferenceType(type); } - if(Cpp::IsArrayType(Cpp::GetNonReferenceType(type))) - { - type = Cpp::GetPointerType(Cpp::GetArrayElementType(Cpp::GetNonReferenceType(type))); - } } else if(Cpp::IsEnumConstant(scope)) { @@ -3597,7 +3561,7 @@ namespace jank::analyze for(usize i{}; i < arg_count; ++i, it = it.rest()) { auto arg_expr{ - analyze(it.first().unwrap(), current_frame, expression_position::value, fn_ctx, needs_box) + analyze(it.first().unwrap(), current_frame, expression_position::value, fn_ctx, true) }; if(arg_expr.is_err()) { @@ -3979,7 +3943,7 @@ namespace jank::analyze /* Since we're reusing analyze_cpp_call, we need to rebuild our list a bit. We * want to remove the cpp/cast and the type and then add back in a new head. Since * cpp_call takes in a cpp_value, it doesn't look at the head, but it needs to be there. */ - auto const call_l{ make_box(l->data.rest().rest().conj(jank_nil)) }; + auto const call_l{ make_box(l->data.rest().rest().conj(jank_nil())) }; return analyze_cpp_call(call_l, cpp_value, current_frame, position, fn_ctx, needs_box); } if(cpp_util::is_any_object(type_expr->type) && cpp_util::is_trait_convertible(value_type)) @@ -4091,7 +4055,7 @@ namespace jank::analyze auto const count(l->count()); if(count < 2) { - return error::analyze_invalid_cpp_cast( + return error::analyze_invalid_cpp_unbox( "This call to 'cpp/unbox' is missing a C++ type and a value as arguments.", object_source(l->first()), latest_expansion(macro_expansions)) @@ -4099,7 +4063,7 @@ namespace jank::analyze } else if(count < 3) { - return error::analyze_invalid_cpp_cast( + return error::analyze_invalid_cpp_unbox( "This call to 'cpp/unbox' is missing a value to unbox as an argument.", object_source(l->first()), latest_expansion(macro_expansions)) @@ -4107,7 +4071,7 @@ namespace jank::analyze } else if(3 < count) { - return error::analyze_invalid_cpp_cast( + return error::analyze_invalid_cpp_unbox( "A call to 'cpp/unbox' must only have a C++ type and a " "value as arguments and nothing else.", object_source(l->next()->next()->next()->first()), @@ -4387,7 +4351,7 @@ namespace jank::analyze } val->val_kind = expr::cpp_value::value_kind::variable; - val->type = Cpp::GetTypeFromScope(member_scope); + val->type = Cpp::GetLValueReferenceType(Cpp::GetTypeFromScope(member_scope)); val->scope = member_scope; return val; } diff --git a/compiler+runtime/src/cpp/jank/aot/processor.cpp b/compiler+runtime/src/cpp/jank/aot/processor.cpp index c0afcf7ae..8174c41d5 100644 --- a/compiler+runtime/src/cpp/jank/aot/processor.cpp +++ b/compiler+runtime/src/cpp/jank/aot/processor.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace jank::aot @@ -42,9 +43,9 @@ extern "C" int jank_init_with_pch(int const argc, char const * const pch_data, jank_usize pch_size, int (*fn)(int const, char const ** const)); -extern "C" jank_object_ref jank_load_clojure_core_native(); -extern "C" jank_object_ref jank_load_clojure_core(); -extern "C" jank_object_ref jank_load_jank_compiler_native(); +extern "C" void jank_load_clojure_core_native(); +extern "C" void jank_load_clojure_core(); +extern "C" void jank_load_jank_compiler_native(); extern "C" jank_object_ref jank_var_intern_c(char const *, char const *); extern "C" jank_object_ref jank_deref(jank_object_ref); extern "C" jank_object_ref jank_call2(jank_object_ref, jank_object_ref, jank_object_ref); @@ -55,9 +56,7 @@ extern "C" jank_object_ref jank_parse_command_line_args(int, char const **); auto const modules_rlocked{ __rt_ctx->loaded_modules_in_order.rlock() }; for(auto const &it : *modules_rlocked) { - util::format_to(sb, - R"(extern "C" jank_object_ref {}();)", - module::module_to_load_function(it)); + util::format_to(sb, R"(extern "C" void {}();)", module::module_to_load_function(it)); sb("\n"); } @@ -120,58 +119,10 @@ int main(int argc, const char** argv) return main_file_path; } - jtl::result processor::compile(jtl::immutable_string const &module) const + static jtl::result, error_ref> build_compiler_args() { - auto const main_var(__rt_ctx->find_var(module, "-main")); - if(main_var.is_nil()) - { - return error::aot_unresolved_main(util::format( - "The entrypoint of the program is expected to be #'{}/-main, but this var is missing.", - module)); - } - std::vector compiler_args{}; - auto const modules_rlocked{ __rt_ctx->loaded_modules_in_order.rlock() }; - for(auto const &it : *modules_rlocked) - { - /* Core modules will be linked as part of libjank-standalone.a. */ - if(runtime::module::is_core_module(it)) - { - continue; - } - - auto const &module_path{ util::format("{}.o", - relative_to_cache_dir(module::module_to_path(it))) }; - - if(std::filesystem::exists(module_path.c_str())) - { - compiler_args.push_back(strdup(module_path.c_str())); - } - else - { - auto const find_res{ __rt_ctx->module_loader.find(it, module::origin::latest) }; - if(find_res.is_ok() && find_res.expect_ok().sources.o.is_some()) - { - compiler_args.push_back(strdup(find_res.expect_ok().sources.o.unwrap().path.c_str())); - } - else - { - return error::internal_aot_failure(util::format("Compiled module '{}' not found.", it)); - } - } - } - - auto const entrypoint_path{ gen_entrypoint(module) }; - compiler_args.push_back(strdup("-x")); - compiler_args.push_back(strdup("c++")); - compiler_args.push_back(strdup(entrypoint_path.c_str())); - - for(auto const &include_dir : util::cli::opts.include_dirs) - { - compiler_args.push_back(strdup(util::format("-I{}", include_dir).c_str())); - } - auto const clang_path_str{ util::find_clang() }; if(clang_path_str.is_none()) { @@ -194,6 +145,13 @@ int main(int argc, const char** argv) compiler_args.emplace_back(strdup("-L")); compiler_args.emplace_back(strdup(util::format("{}/lib", jank_resource_dir).c_str())); + std::stringstream flags{ JANK_JIT_FLAGS }; + std::string flag; + while(std::getline(flags, flag, ' ')) + { + compiler_args.emplace_back(strdup(flag.c_str())); + } + { std::string_view const flags{ JANK_AOT_FLAGS }; size_t start{}; @@ -215,6 +173,16 @@ int main(int argc, const char** argv) } } + if(auto const extra{ getenv("JANK_EXTRA_FLAGS") }; extra) + { + std::stringstream flags{ extra }; + std::string flag; + while(std::getline(flags, flag, ' ')) + { + compiler_args.emplace_back(strdup(flag.c_str())); + } + } + if constexpr(jtl::current_platform == jtl::platform::macos_like) { compiler_args.push_back(strdup("-L/opt/homebrew/lib")); @@ -225,6 +193,82 @@ int main(int argc, const char** argv) compiler_args.push_back(strdup(util::format("-L{}", library_dir).c_str())); } + for(auto const &include_dir : util::cli::opts.include_dirs) + { + compiler_args.push_back(strdup(util::format("-I{}", include_dir).c_str())); + } + + for(auto const &define : util::cli::opts.define_macros) + { + compiler_args.push_back(strdup(util::format("-D{}", define).c_str())); + } + + compiler_args.push_back(strdup("-std=c++20")); + compiler_args.push_back(strdup("-Wno-c23-extensions")); + if constexpr(jtl::current_platform == jtl::platform::linux_like) + { + compiler_args.push_back(strdup("-Wl,--export-dynamic")); + } + compiler_args.push_back(strdup("-rdynamic")); + /* TODO: Change this based on the CLI optimization level. */ + compiler_args.push_back(strdup("-O2")); + + return compiler_args; + } + + jtl::result + processor::build_executable(jtl::immutable_string const &module) const + { + auto const main_var(__rt_ctx->find_var(module, "-main")); + if(main_var.is_nil()) + { + return error::aot_unresolved_main(util::format( + "The entrypoint of the program is expected to be #'{}/-main, but this var was not found.", + module)); + } + + auto const compiler_args_res{ build_compiler_args() }; + if(compiler_args_res.is_err()) + { + return compiler_args_res.expect_err(); + } + std::vector compiler_args{ jtl::move(compiler_args_res.expect_ok()) }; + + auto const modules_rlocked{ __rt_ctx->loaded_modules_in_order.rlock() }; + for(auto const &it : *modules_rlocked) + { + /* Core modules will be linked as part of libjank-standalone.a. */ + if(runtime::module::is_core_module(it)) + { + continue; + } + + auto const &module_path{ util::format("{}.o", + relative_to_cache_dir(module::module_to_path(it))) }; + + if(std::filesystem::exists(module_path.c_str())) + { + compiler_args.push_back(strdup(module_path.c_str())); + } + else + { + auto const find_res{ __rt_ctx->module_loader.find(it, module::origin::latest) }; + if(find_res.is_ok() && find_res.expect_ok().sources.o.is_some()) + { + compiler_args.push_back(strdup(find_res.expect_ok().sources.o.unwrap().path.c_str())); + } + else + { + return error::internal_aot_failure(util::format("Compiled module '{}' not found.", it)); + } + } + } + + auto const entrypoint_path{ gen_entrypoint(module) }; + compiler_args.push_back(strdup("-x")); + compiler_args.push_back(strdup("c++")); + compiler_args.push_back(strdup(entrypoint_path.c_str())); + for(auto const &lib : { "-ljank-standalone", /* Default libraries that jank depends on. */ "-lm", @@ -237,6 +281,11 @@ int main(int argc, const char** argv) compiler_args.push_back(strdup(lib)); } + for(auto const &lib : util::cli::opts.libs) + { + compiler_args.push_back(strdup(util::format("-l{}", lib).c_str())); + } + /* On non-macOS platforms, explicitly link libstdc++. * macOS uses libc++ implicitly via Clang. */ if constexpr(jtl::current_platform != jtl::platform::macos_like) @@ -244,20 +293,6 @@ int main(int argc, const char** argv) compiler_args.push_back(strdup("-lstdc++")); } - for(auto const &define : util::cli::opts.define_macros) - { - compiler_args.push_back(strdup(util::format("-D{}", define).c_str())); - } - - compiler_args.push_back(strdup("-std=c++20")); - compiler_args.push_back(strdup("-Wno-c23-extensions")); - if constexpr(jtl::current_platform == jtl::platform::linux_like) - { - compiler_args.push_back(strdup("-Wl,--export-dynamic")); - } - compiler_args.push_back(strdup("-rdynamic")); - compiler_args.push_back(strdup("-O2")); - /* Required because of `strdup` usage and need to manually free the memory. * Clang expects C strings that we own. */ /* TODO: I doubt this is really needed. These strings aren't captured by Clang. */ @@ -282,4 +317,63 @@ int main(int argc, const char** argv) return ok(); } + + jtl::result + processor::compile_object(jtl::immutable_string const &module_name, + jtl::immutable_string const &cpp_source) const + { + auto const compiler_args_res{ build_compiler_args() }; + if(compiler_args_res.is_err()) + { + return compiler_args_res.expect_err(); + } + std::vector compiler_args{ jtl::move(compiler_args_res.expect_ok()) }; + + /* TODO: Use runtime::context::get_output_module_name. */ + std::filesystem::path const module_path{ + util::cli::opts.output_module_filename.empty() + ? util::format("{}/{}.o", __rt_ctx->binary_cache_dir, module::module_to_path(module_name)) + : jtl::immutable_string{ util::cli::opts.output_module_filename } + }; + std::filesystem::create_directories(module_path.parent_path()); + + auto const tmp{ std::filesystem::temp_directory_path() }; + std::string path_tmp{ tmp / "jank-compile-XXXXXX" }; + mkstemp(path_tmp.data()); + + { + std::ofstream ofs{ path_tmp }; + ofs << cpp_source; + //ofs << util::format_cpp_source(cpp_source).expect_ok(); + } + + std::filesystem::path const jank_resource_dir{ util::resource_dir().c_str() }; + compiler_args.push_back("-include"); + auto const prelude_path{ jank_resource_dir / "include/cpp/jank/prelude.hpp" }; + compiler_args.push_back(prelude_path.c_str()); + + compiler_args.push_back("-c"); + compiler_args.push_back("-o"); + compiler_args.push_back(module_path.c_str()); + + compiler_args.push_back("-x"); + compiler_args.push_back("c++"); + compiler_args.push_back(path_tmp.c_str()); + + compiler_args.push_back("-w"); + compiler_args.push_back("-Wno-c++11-narrowing"); + + /* TODO: This has an unwind issue which prevents exceptions thrown from these compiled + * objects from being caught in jank itself. */ + + //util::println("compilation command: {} ", compiler_args); + + auto const res{ util::invoke_clang(compiler_args) }; + if(res.is_err()) + { + return res.expect_err(); + } + + return ok(); + } } diff --git a/compiler+runtime/src/cpp/jank/c_api.cpp b/compiler+runtime/src/cpp/jank/c_api.cpp index 9f68c43fe..1ab3877ae 100644 --- a/compiler+runtime/src/cpp/jank/c_api.cpp +++ b/compiler+runtime/src/cpp/jank/c_api.cpp @@ -54,18 +54,29 @@ extern "C" jank_object_ref jank_eval(jank_object_ref const s) { auto const s_obj(try_object(reinterpret_cast(s))); - return __rt_ctx->eval_string(s_obj->data).unwrap_or(jank_nil).erase(); + return __rt_ctx->eval_string(s_obj->data).unwrap_or(jank_nil()).erase().data; } jank_object_ref jank_read_string(jank_object_ref const s) { auto const s_obj(try_object(reinterpret_cast(s))); - return __rt_ctx->read_string(s_obj->data).erase(); + return __rt_ctx->read_string(s_obj->data).erase().data; } jank_object_ref jank_read_string_c(char const * const s) { - return __rt_ctx->read_string(s).erase(); + return __rt_ctx->read_string(s).erase().data; + } + + jank_object_ref jank_ns_intern(jank_object_ref const sym) + { + auto const sym_obj(try_object(reinterpret_cast(sym))); + return __rt_ctx->intern_ns(sym_obj).erase().data; + } + + jank_object_ref jank_ns_intern_c(char const * const sym) + { + return __rt_ctx->intern_ns(sym).erase().data; } void jank_ns_set_symbol_counter(char const * const ns, jank_u64 const count) @@ -80,53 +91,56 @@ extern "C" __rt_ctx->intern_ns(ns_obj->data); auto const name_obj(try_object(reinterpret_cast(name))); - return __rt_ctx->intern_var(ns_obj->data, name_obj->data).expect_ok().erase(); + return __rt_ctx->intern_var(ns_obj->data, name_obj->data).expect_ok().erase().data; } jank_object_ref jank_var_intern_c(char const * const ns, char const * const name) { __rt_ctx->intern_ns(ns); - return __rt_ctx->intern_var(ns, name).expect_ok().erase(); + return __rt_ctx->intern_var(ns, name).expect_ok().erase().data; } jank_object_ref jank_var_bind_root(jank_object_ref const var, jank_object_ref const val) { auto const var_obj(try_object(reinterpret_cast(var))); auto const val_obj(reinterpret_cast(val)); - return var_obj->bind_root(val_obj).erase(); + return var_obj->bind_root(val_obj).erase().data; } jank_object_ref jank_var_set_dynamic(jank_object_ref const var, jank_object_ref const dynamic) { auto const var_obj(try_object(reinterpret_cast(var))); auto const dynamic_obj(reinterpret_cast(dynamic)); - return var_obj->set_dynamic(truthy(dynamic_obj)).erase(); + return var_obj->set_dynamic(truthy(dynamic_obj)).erase().data; } jank_object_ref jank_keyword_intern(jank_object_ref const ns, jank_object_ref const name) { auto const ns_obj(reinterpret_cast(ns)); auto const name_obj(reinterpret_cast(name)); - return __rt_ctx->intern_keyword(to_string(ns_obj), to_string(name_obj)).expect_ok().erase(); + return __rt_ctx->intern_keyword(to_string(ns_obj), to_string(name_obj)) + .expect_ok() + .erase() + .data; } jank_object_ref jank_deref(jank_object_ref const o) { auto const o_obj(reinterpret_cast(o)); - return deref(o_obj).erase(); + return deref(o_obj).erase().data; } jank_object_ref jank_call0(jank_object_ref const f) { auto const f_obj(reinterpret_cast(f)); - return dynamic_call(f_obj).erase(); + return dynamic_call(f_obj).erase().data; } jank_object_ref jank_call1(jank_object_ref const f, jank_object_ref const a1) { auto const f_obj(reinterpret_cast(f)); auto const a1_obj(reinterpret_cast(a1)); - return dynamic_call(f_obj, a1_obj).erase(); + return dynamic_call(f_obj, a1_obj).erase().data; } jank_object_ref @@ -135,7 +149,7 @@ extern "C" auto const f_obj(reinterpret_cast(f)); auto const a1_obj(reinterpret_cast(a1)); auto const a2_obj(reinterpret_cast(a2)); - return dynamic_call(f_obj, a1_obj, a2_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj).erase().data; } jank_object_ref jank_call3(jank_object_ref const f, @@ -147,7 +161,7 @@ extern "C" auto const a1_obj(reinterpret_cast(a1)); auto const a2_obj(reinterpret_cast(a2)); auto const a3_obj(reinterpret_cast(a3)); - return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj).erase().data; } jank_object_ref jank_call4(jank_object_ref const f, @@ -161,7 +175,7 @@ extern "C" auto const a2_obj(reinterpret_cast(a2)); auto const a3_obj(reinterpret_cast(a3)); auto const a4_obj(reinterpret_cast(a4)); - return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj).erase().data; } jank_object_ref jank_call5(jank_object_ref const f, @@ -177,7 +191,7 @@ extern "C" auto const a3_obj(reinterpret_cast(a3)); auto const a4_obj(reinterpret_cast(a4)); auto const a5_obj(reinterpret_cast(a5)); - return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj).erase().data; } jank_object_ref jank_call6(jank_object_ref const f, @@ -195,7 +209,7 @@ extern "C" auto const a4_obj(reinterpret_cast(a4)); auto const a5_obj(reinterpret_cast(a5)); auto const a6_obj(reinterpret_cast(a6)); - return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj, a6_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj, a6_obj).erase().data; } jank_object_ref jank_call7(jank_object_ref const f, @@ -215,7 +229,7 @@ extern "C" auto const a5_obj(reinterpret_cast(a5)); auto const a6_obj(reinterpret_cast(a6)); auto const a7_obj(reinterpret_cast(a7)); - return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj, a6_obj, a7_obj).erase(); + return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj, a6_obj, a7_obj).erase().data; } jank_object_ref jank_call8(jank_object_ref const f, @@ -238,7 +252,8 @@ extern "C" auto const a7_obj(reinterpret_cast(a7)); auto const a8_obj(reinterpret_cast(a8)); return dynamic_call(f_obj, a1_obj, a2_obj, a3_obj, a4_obj, a5_obj, a6_obj, a7_obj, a8_obj) - .erase(); + .erase() + .data; } jank_object_ref jank_call9(jank_object_ref const f, @@ -272,7 +287,8 @@ extern "C" a7_obj, a8_obj, a9_obj) - .erase(); + .erase() + .data; } jank_object_ref jank_call10(jank_object_ref const f, @@ -309,7 +325,8 @@ extern "C" a8_obj, a9_obj, a10_obj) - .erase(); + .erase() + .data; } jank_object_ref jank_call11(jank_object_ref const f, @@ -349,44 +366,45 @@ extern "C" a9_obj, a10_obj, try_object(rest_obj)) - .erase(); + .erase() + .data; } jank_object_ref jank_const_nil() { - return jank_nil.erase(); + return jank_nil().data; } jank_object_ref jank_const_true() { - return jank_true.erase(); + return jank_true.erase().data; } jank_object_ref jank_const_false() { - return jank_false.erase(); + return jank_false.erase().data; } jank_object_ref jank_integer_create(jank_i64 const i) { - return make_box(i).erase(); + return make_box(i).erase().data; } jank_object_ref jank_big_integer_create(char const * const s) { jank_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_big_decimal_create(char const * const s) { jank_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_real_create(jank_f64 const r) { - return make_box(r).erase(); + return make_box(r).erase().data; } jank_object_ref @@ -394,44 +412,45 @@ extern "C" { return make_box(runtime::obj::ratio_data(reinterpret_cast(numerator), reinterpret_cast(denominator))) - .erase(); + .erase() + .data; } jank_object_ref jank_string_create(char const *s) { jank_debug_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_symbol_create(jank_object_ref const ns, jank_object_ref const name) { auto const ns_obj(reinterpret_cast(ns)); auto const name_obj(reinterpret_cast(name)); - return make_box(ns_obj, name_obj).erase(); + return make_box(ns_obj, name_obj).erase().data; } jank_object_ref jank_character_create(char const *s) { jank_debug_assert(s); - return make_box(read::parse::get_char_from_literal(s).unwrap()).erase(); + return make_box(read::parse::get_char_from_literal(s).unwrap()).erase().data; } jank_object_ref jank_regex_create(char const *s) { jank_debug_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_uuid_create(char const *s) { jank_debug_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_inst_create(char const *s) { jank_debug_assert(s); - return make_box(s).erase(); + return make_box(s).erase().data; } jank_object_ref jank_list_create(jank_u64 const size, ...) @@ -451,7 +470,7 @@ extern "C" va_end(args); runtime::detail::native_persistent_list const npl{ v.rbegin(), v.rend() }; - return make_box(std::move(npl)).erase(); + return make_box(std::move(npl)).erase().data; } jank_object_ref jank_vector_create(jank_u64 const size, ...) @@ -469,7 +488,7 @@ extern "C" } va_end(args); - return trans.to_persistent().erase(); + return trans.to_persistent().erase().data; } /* TODO: Meta for maps, vectors, sets, symbols, and fns. */ @@ -491,7 +510,7 @@ extern "C" } va_end(args); - return trans.to_persistent().erase(); + return trans.to_persistent().erase().data; } jank_object_ref jank_set_create(u64 const size, ...) @@ -509,12 +528,12 @@ extern "C" } va_end(args); - return trans.to_persistent().erase(); + return trans.to_persistent().erase().data; } jank_object_ref jank_box(char const * const type, void const * const o) { - return make_box(o, type).erase(); + return make_box(o, type).erase().data; } void *jank_unbox(char const * const type, jank_object_ref const o) @@ -564,7 +583,7 @@ extern "C" jank_object_ref jank_function_create(jank_arity_flags const arity_flags) { - return make_box(arity_flags).erase(); + return make_box(arity_flags).erase().data; } void @@ -731,7 +750,7 @@ extern "C" jank_object_ref jank_closure_create(jank_arity_flags const arity_flags, void * const context) { - return make_box(arity_flags, context).erase(); + return make_box(arity_flags, context).erase().data; } void @@ -940,8 +959,8 @@ extern "C" { if(o_obj->type == object_type::integer) { - /* We don't hash the integer if it's an int32 value. This is to be consistent with how keys are hashed in jank's - * case macro. */ + /* We don't hash the integer if it's within an i32 value. + * This is to be consistent with how keys are hashed in jank's case macro. */ integer = (integer >= std::numeric_limits::min() && integer <= std::numeric_limits::max()) ? integer @@ -1021,10 +1040,23 @@ extern "C" * Notably, this might make text encoding become more platform dependent. */ std::locale::global(std::locale("")); - /* The GC needs to enabled even before arg parsing, since our native types, + /* The GC needs to initialized even before arg parsing, since our native types, * like strings, use the GC for allocations. It can still be configured later. */ GC_set_all_interior_pointers(1); - GC_enable(); + + /* Collection is disabled on macOS, due to a combination of two issues. Firstly, + * bdwgc will prematurely collect if we don't use malloc redirection. My research + * indicates that this is due to (at least) bdwgc not knowing about globals within + * JIT compiled C++. Secondly, we can't use malloc redirection on macOS due to an + * issue which leads to a crash in LLVM code. + * + * https://github.com/bdwgc/bdwgc/issues/829 */ + if constexpr(jtl::current_platform == jtl::platform::macos_like) + { + /* Although this is called enable, by calling it right here, we actually disable the GC. */ + GC_enable(); + } + GC_init(); llvm::llvm_shutdown_obj const Y{}; @@ -1052,13 +1084,13 @@ extern "C" jank_object_ref jank_parse_command_line_args(int const argc, char const **argv) { obj::transient_vector trans; - auto const args{ util::cli::parse_empty(argc, argv) }; + auto const args{ util::cli::parse_into_vector(argc, argv) }; for(auto const &arg : args) { trans.conj_in_place(make_box(arg)); } - return trans.to_persistent().erase(); + return trans.to_persistent().erase().data; } } diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index 4349af672..edd8225c4 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -83,7 +83,7 @@ namespace jank::codegen compilation_target target); /* For this ctor, we're inheriting the context from another function, which means * we're building a nested function. */ - impl(analyze::expr::function_ref expr, std::unique_ptr ctx); + impl(analyze::expr::function_ref expr, jtl::ref ctx); jtl::string_result gen(); llvm::Value *gen(analyze::expression_ref, analyze::expr::function_arity const &); @@ -127,8 +127,8 @@ namespace jank::codegen llvm::Value *gen(analyze::expr::cpp_new_ref, analyze::expr::function_arity const &); llvm::Value *gen(analyze::expr::cpp_delete_ref, analyze::expr::function_arity const &); - llvm::Value *gen_var(obj::symbol_ref qualified_name) const; - llvm::Value *gen_var_root(obj::symbol_ref qualified_name, var_root_kind kind) const; + llvm::Value *gen_var(obj::symbol_ref const qualified_name) const; + llvm::Value *gen_var_root(obj::symbol_ref const qualified_name, var_root_kind kind) const; llvm::Value *gen_c_string(jtl::immutable_string const &s) const; void create_function(); @@ -136,21 +136,21 @@ namespace jank::codegen void create_global_ctor() const; llvm::GlobalVariable *create_global_var(jtl::immutable_string const &name) const; - llvm::Value *gen_global(runtime::obj::nil_ref) const; - llvm::Value *gen_global(runtime::obj::boolean_ref b) const; - llvm::Value *gen_global(runtime::obj::integer_ref i) const; - llvm::Value *gen_global(runtime::obj::big_integer_ref i) const; - llvm::Value *gen_global(runtime::obj::big_decimal_ref i) const; - llvm::Value *gen_global(runtime::obj::real_ref r) const; - llvm::Value *gen_global(runtime::obj::ratio_ref r) const; - llvm::Value *gen_global(runtime::obj::persistent_string_ref s) const; - llvm::Value *gen_global(runtime::obj::symbol_ref s) const; - llvm::Value *gen_global(runtime::obj::keyword_ref k) const; - llvm::Value *gen_global(runtime::obj::character_ref c) const; - llvm::Value *gen_global(runtime::obj::re_pattern_ref re) const; - llvm::Value *gen_global(runtime::obj::uuid_ref u) const; - llvm::Value *gen_global(runtime::obj::inst_ref i) const; - llvm::Value *gen_global_from_read_string(runtime::object_ref o) const; + llvm::Value *gen_global(runtime::obj::nil_ref const) const; + llvm::Value *gen_global(runtime::obj::boolean_ref const b) const; + llvm::Value *gen_global(runtime::obj::integer_ref const i) const; + llvm::Value *gen_global(runtime::obj::big_integer_ref const i) const; + llvm::Value *gen_global(runtime::obj::big_decimal_ref const i) const; + llvm::Value *gen_global(runtime::obj::real_ref const r) const; + llvm::Value *gen_global(runtime::obj::ratio_ref const r) const; + llvm::Value *gen_global(runtime::obj::persistent_string_ref const s) const; + llvm::Value *gen_global(runtime::obj::symbol_ref const s) const; + llvm::Value *gen_global(runtime::obj::keyword_ref const k) const; + llvm::Value *gen_global(runtime::obj::character_ref const c) const; + llvm::Value *gen_global(runtime::obj::re_pattern_ref const re) const; + llvm::Value *gen_global(runtime::obj::uuid_ref const u) const; + llvm::Value *gen_global(runtime::obj::inst_ref const i) const; + llvm::Value *gen_global_from_read_string(runtime::object_ref const o) const; llvm::Value *gen_function_instance(analyze::expr::function_ref expr, analyze::expr::function_arity const &fn_arity); llvm::Value *gen_aot_call(Cpp::AotCall const &call, @@ -174,13 +174,17 @@ namespace jank::codegen llvm::StructType *get_or_insert_struct_type(std::string const &name, std::vector const &fields) const; + util::scope_exit gen_stack_save(); + void gen_stack_restore(); + jtl::ptr gen_ret(jtl::ptr const value); + jtl::ptr gen_ret(); + compilation_target target{}; analyze::expr::function_ref root_fn; jtl::ptr llvm_fn{}; - std::unique_ptr ctx; + jtl::ref ctx; native_unordered_map> locals; - /* TODO: Use gc allocator to avoid leaks. */ - std::list deferred_inits{}; + native_list deferred_inits{}; jtl::ref llvm_ctx; jtl::ref llvm_module; jtl::ptr current_loop; @@ -197,6 +201,7 @@ namespace jank::codegen * We don't use this within the current fn, but it's passed upward to * the fn gen which is above us, all the way up to the module level. */ native_unordered_map global_rtti; + native_vector> stack_saves; }; struct llvm_type_info @@ -206,6 +211,16 @@ namespace jank::codegen usize alignment{}; }; + static jtl::immutable_string unique_munged_string() + { + return runtime::munge(__rt_ctx->unique_namespaced_string()); + } + + static jtl::immutable_string unique_munged_string(jtl::immutable_string const &prefix) + { + return runtime::munge(__rt_ctx->unique_namespaced_string(prefix)); + } + static llvm::Type *llvm_builtin_type(reusable_context const &ctx, jtl::ref const llvm_ctx, jtl::ptr const type) @@ -405,7 +420,7 @@ namespace jank::codegen || Cpp::IsPointerType(param_type) /*|| Cpp::IsArrayType(param_type)*/) }; - auto const fn_callable{ Cpp::MakeAotCallable(match, __rt_ctx->unique_munged_string()) }; + auto const fn_callable{ Cpp::MakeAotCallable(match, unique_munged_string()) }; link_module(ctx, reinterpret_cast(fn_callable.getModule())); llvm::Value *arg_alloc{ arg }; @@ -488,9 +503,8 @@ namespace jank::codegen /* Whenever we have an object in an `alloca`, we need to load it before using. This fn only * makes sense to use with jank objects, as opposed to native values. */ - static llvm::Value *load_if_needed(std::unique_ptr const &ctx, - llvm::Value *arg, - jtl::ptr const type) + static llvm::Value * + load_if_needed(jtl::ref const ctx, llvm::Value *arg, jtl::ptr const type) { if(!arg) { @@ -504,8 +518,7 @@ namespace jank::codegen return arg; } - static llvm::Value * - load_if_needed(std::unique_ptr const &ctx, llvm::Value * const arg) + static llvm::Value *load_if_needed(jtl::ref const ctx, llvm::Value * const arg) { return load_if_needed(ctx, arg, cpp_util::untyped_object_ptr_type()); } @@ -513,7 +526,7 @@ namespace jank::codegen reusable_context::reusable_context(jtl::immutable_string const &module_name, std::unique_ptr llvm_ctx) : module_name{ module_name } - , ctor_name{ __rt_ctx->unique_munged_string("jank_global_init") } + , ctor_name{ unique_munged_string("jank_global_init") } //, llvm_ctx{ std::make_unique() } //, llvm_ctx{ reinterpret_cast *>( // reinterpret_cast( @@ -525,8 +538,7 @@ namespace jank::codegen , mam{ std::make_unique() } , pic{ std::make_unique() } { - auto m{ std::make_unique(__rt_ctx->unique_munged_string(module_name).c_str(), - *llvm_ctx) }; + auto m{ std::make_unique(unique_munged_string(module_name).c_str(), *llvm_ctx) }; module = llvm::orc::ThreadSafeModule{ std::move(m), std::move(llvm_ctx) }; auto const raw_ctx{ extract_context(module) }; @@ -585,8 +597,8 @@ namespace jank::codegen } llvm_processor::llvm_processor(expr::function_ref const expr, - std::unique_ptr ctx) - : _impl{ make_ref(expr, jtl::move(ctx)) } + jtl::ref const ctx) + : _impl{ make_ref(expr, ctx) } { } @@ -595,13 +607,13 @@ namespace jank::codegen compilation_target const target) : target{ target } , root_fn{ expr } - , ctx{ std::make_unique(module_name, std::make_unique()) } + , ctx{ make_ref(module_name, std::make_unique()) } , llvm_ctx{ extract_context(ctx->module) } , llvm_module{ ctx->module.getModuleUnlocked() } { } - llvm_processor::impl::impl(expr::function_ref const expr, std::unique_ptr ctx) + llvm_processor::impl::impl(expr::function_ref const expr, jtl::ref ctx) : target{ compilation_target::function } , root_fn{ expr } , ctx{ std::move(ctx) } @@ -733,7 +745,7 @@ namespace jank::codegen jtl::string_result llvm_processor::impl::gen() { - profile::timer const timer{ "ir gen" }; + profile::timer const timer{ util::format("ir gen {}", root_fn->name) }; if(target != compilation_target::function) { create_global_ctor(); @@ -760,7 +772,7 @@ namespace jank::codegen continue; } - ctx->builder->CreateRet(gen_global(jank_nil)); + gen_ret(gen_global(jank_nil())); } if(target != compilation_target::function) @@ -778,7 +790,7 @@ namespace jank::codegen { gen_c_string(util::format("global ctor for {}", root_fn->name)) }); } - ctx->builder->CreateRetVoid(); + gen_ret(); } /* For modules, we need to make sure to define RTTI symbols manually. Since @@ -851,8 +863,8 @@ namespace jank::codegen auto const set_dynamic_fn( llvm_module->getOrInsertFunction("jank_var_set_dynamic", set_dynamic_fn_type)); - auto const dynamic{ truthy( - get(expr->name->meta.unwrap_or(jank_nil), __rt_ctx->intern_keyword("dynamic").expect_ok())) }; + auto const dynamic{ truthy(get(expr->name->meta.unwrap_or(jank_nil()), + __rt_ctx->intern_keyword("dynamic").expect_ok())) }; auto const dynamic_global{ gen_global(make_box(dynamic)) }; @@ -860,7 +872,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(ref); + return gen_ret(ref); } return ref; @@ -901,7 +913,7 @@ namespace jank::codegen } if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -914,7 +926,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(var); + return gen_ret(var); } return var; @@ -991,7 +1003,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1038,7 +1050,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(ret); + return gen_ret(ret); } return ret; @@ -1065,7 +1077,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1092,7 +1104,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1120,7 +1132,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1147,7 +1159,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1164,7 +1176,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(load_if_needed(ctx, ret)); + return gen_ret(load_if_needed(ctx, ret)); } return ret; @@ -1176,17 +1188,7 @@ namespace jank::codegen { llvm::IRBuilder<>::InsertPointGuard const guard{ *ctx->builder }; - llvm_processor nested{ expr, std::move(ctx) }; - - /* We need to make sure to transfer ownership of the context back, even if an exception - * is thrown. */ - util::scope_exit const finally{ [&]() { - if(nested._impl->ctx) - { - ctx = std::move(nested._impl->ctx); - } - } }; - + llvm_processor const nested{ expr, ctx }; auto const res{ nested.gen() }; if(res.is_err()) { @@ -1194,10 +1196,6 @@ namespace jank::codegen res.expect_ok(); } - /* This is covered by finally, but clang-tidy can't figure that out, so we have - * to make this more clear. */ - ctx = std::move(nested._impl->ctx); - global_rtti.insert(nested._impl->global_rtti.begin(), nested._impl->global_rtti.end()); } @@ -1205,7 +1203,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(fn_obj); + return gen_ret(fn_obj); } return fn_obj; @@ -1247,6 +1245,7 @@ namespace jank::codegen ctx->builder->CreateStore(store.first, store.second); } + gen_stack_restore(); return ctx->builder->CreateBr(current_loop.data); } else @@ -1296,7 +1295,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1316,7 +1315,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(fn_obj); + return gen_ret(fn_obj); } return fn_obj; @@ -1394,7 +1393,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -1448,6 +1447,8 @@ namespace jank::codegen ctx->builder->CreateBr(loop_block); ctx->builder->SetInsertPoint(loop_block); + auto const stack_save{ gen_stack_save() }; + auto const ret(gen(expr->body, arity)); locals = std::move(old_locals); @@ -1457,6 +1458,7 @@ namespace jank::codegen auto const postloop_block(llvm::BasicBlock::Create(*llvm_ctx, "postloop", current_fn)); if(!ctx->builder->GetInsertBlock()->getTerminator()) { + gen_stack_restore(); ctx->builder->CreateBr(postloop_block); } ctx->builder->SetInsertPoint(postloop_block); @@ -1588,10 +1590,10 @@ namespace jank::codegen } else { - else_ = gen_global(jank_nil); + else_ = gen_global(jank_nil()); if(expr->position == expression_position::tail) { - else_ = ctx->builder->CreateRet(else_); + else_ = gen_ret(else_); } } @@ -1662,10 +1664,10 @@ namespace jank::codegen /* Since this code path never completes, it doesn't matter what we return. * Using `jank_nil` to satisfy some IR requirements. */ - auto const ret{ gen_global(jank_nil) }; + auto const ret{ gen_global(jank_nil()) }; if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(ret); + return gen_ret(ret); } return ret; } @@ -1728,7 +1730,7 @@ namespace jank::codegen llvm::AllocaInst *result_slot{ entry_builder.CreateAlloca(ptr_ty, nullptr, "try.result.slot") }; llvm::BasicBlock *finally_bb{}; llvm::BasicBlock *unwind_action_bb{}; - ctx->builder->CreateStore(gen_global(jank_nil), result_slot); + ctx->builder->CreateStore(gen_global(jank_nil()), result_slot); if(has_finally) { @@ -1861,7 +1863,7 @@ namespace jank::codegen /* We also need to surface this RTTI upward, to the module level, so it * can end up in the generated object file. */ auto const callable{ - Cpp::MakeRTTICallable(catch_type, exception_rtti, __rt_ctx->unique_munged_string()) + Cpp::MakeRTTICallable(catch_type, exception_rtti, unique_munged_string()) }; global_rtti.emplace(exception_rtti, callable); } @@ -1921,7 +1923,7 @@ namespace jank::codegen { if(!catch_val) { - catch_val = gen_global(jank_nil); + catch_val = gen_global(jank_nil()); } ctx->builder->CreateStore(catch_val, result_slot); if(has_finally) @@ -2072,7 +2074,7 @@ namespace jank::codegen if(is_return) { - ctx->builder->CreateRet(final_val); + gen_ret(final_val); } return final_val; } @@ -2156,10 +2158,10 @@ namespace jank::codegen } link_module(*ctx, parse_res->TheModule.get()); - auto const ret{ gen_global(jank_nil) }; + auto const ret{ gen_global(jank_nil()) }; if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(ret); + return gen_ret(ret); } return ret; } @@ -2183,7 +2185,7 @@ namespace jank::codegen ctx->builder->CreateStore(null, alloc); if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(alloc); + return gen_ret(alloc); } return alloc; } @@ -2198,7 +2200,7 @@ namespace jank::codegen ctx->builder->CreateStore(ir_val, alloc); if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(alloc); + return gen_ret(alloc); } return alloc; } @@ -2216,19 +2218,19 @@ namespace jank::codegen ctx->builder->CreateStore(ir_val, alloc); if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(alloc); + return gen_ret(alloc); } return alloc; } - auto const callable{ Cpp::IsFunctionPointerType(expr->type) - /* We pass the type and the scope in here so that unresolved template + auto const callable{ + Cpp::IsFunctionPointerType(expr->type) + /* We pass the type and the scope in here so that unresolved template * scopes can be turned into the correct specialization which matches * the type we have. */ - ? Cpp::MakeFunctionValueAotCallable(expr->scope, - expr->type, - __rt_ctx->unique_munged_string()) - : Cpp::MakeAotCallable(expr->scope, __rt_ctx->unique_munged_string()) }; + ? Cpp::MakeFunctionValueAotCallable(expr->scope, expr->type, unique_munged_string()) + : Cpp::MakeAotCallable(expr->scope, unique_munged_string()) + }; jank_debug_assert(callable); link_module(*ctx, reinterpret_cast(callable.getModule())); @@ -2244,7 +2246,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(alloc); + return gen_ret(alloc); } return alloc; @@ -2265,7 +2267,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(load_if_needed(ctx, converted)); + return gen_ret(load_if_needed(ctx, converted)); } return converted; @@ -2441,16 +2443,16 @@ namespace jank::codegen { if(is_void) { - return ctx->builder->CreateRet(gen_global(jank_nil)); + return gen_ret(gen_global(jank_nil())); } auto const ret_load{ ctx->builder->CreateLoad(ctx->builder->getPtrTy(), ret_alloc, "ret") }; - return ctx->builder->CreateRet(ret_load); + return gen_ret(ret_load); } if(is_void) { - return gen_global(jank_nil); + return gen_global(jank_nil()); } return ret_alloc; } @@ -2479,30 +2481,28 @@ namespace jank::codegen if(expr->source_expr->kind == expression_kind::cpp_value) { auto const source{ llvm::cast(expr->source_expr.data) }; - return gen_aot_call( - Cpp::MakeAotCallable(source->scope, arg_types, __rt_ctx->unique_munged_string()), - source->scope, - expr->type, - Cpp::GetName(source->scope), - expr->arg_exprs, - expr->position, - expr->kind, - arity); + return gen_aot_call(Cpp::MakeAotCallable(source->scope, arg_types, unique_munged_string()), + source->scope, + expr->type, + Cpp::GetName(source->scope), + expr->arg_exprs, + expr->position, + expr->kind, + arity); } else { auto const source_type{ cpp_util::expression_type(expr->source_expr) }; auto arg_exprs{ expr->arg_exprs }; arg_exprs.insert(arg_exprs.begin(), expr->source_expr); - return gen_aot_call( - Cpp::MakeApplyCallable(source_type, arg_types, __rt_ctx->unique_munged_string()), - nullptr, - expr->type, - "call", - jtl::move(arg_exprs), - expr->position, - expr->kind, - arity); + return gen_aot_call(Cpp::MakeApplyCallable(source_type, arg_types, unique_munged_string()), + nullptr, + expr->type, + "call", + jtl::move(arg_exprs), + expr->position, + expr->kind, + arity); } } @@ -2520,7 +2520,7 @@ namespace jank::codegen * We can save ourselves the time of JIT compiling more C++ and make the IR easier * to optimize. */ ctor_fn_callable - = Cpp::MakeBuiltinConstructorAotCallable(expr->type, __rt_ctx->unique_munged_string()); + = Cpp::MakeBuiltinConstructorAotCallable(expr->type, unique_munged_string()); } else { @@ -2531,7 +2531,7 @@ namespace jank::codegen ctor_fn_callable = Cpp::MakeBuiltinConstructorAotCallable(expr->type, needs_conversion ? expr->type : arg_type, - __rt_ctx->unique_munged_string()); + unique_munged_string()); } } else if(expr->is_aggregate) @@ -2541,15 +2541,14 @@ namespace jank::codegen { arg_types.emplace_back(cpp_util::expression_type(arg_expr)); } - ctor_fn_callable - = Cpp::MakeAggregateInitializationAotCallable(expr->type, - arg_types, - __rt_ctx->unique_munged_string()); + ctor_fn_callable = Cpp::MakeAggregateInitializationAotCallable(expr->type, + arg_types, + unique_munged_string()); } else { jank_debug_assert(expr->fn); - ctor_fn_callable = Cpp::MakeAotCallable(expr->fn, __rt_ctx->unique_munged_string()); + ctor_fn_callable = Cpp::MakeAotCallable(expr->fn, unique_munged_string()); } jank_debug_assert(ctor_fn_callable); @@ -2573,7 +2572,7 @@ namespace jank::codegen llvm::Value * llvm_processor::impl::gen(expr::cpp_member_call_ref const expr, expr::function_arity const &arity) { - return gen_aot_call(Cpp::MakeAotCallable(expr->fn, __rt_ctx->unique_munged_string()), + return gen_aot_call(Cpp::MakeAotCallable(expr->fn, unique_munged_string()), expr->fn, cpp_util::expression_type(expr), Cpp::GetName(expr->fn), @@ -2586,7 +2585,7 @@ namespace jank::codegen llvm::Value *llvm_processor::impl::gen(expr::cpp_member_access_ref const expr, expr::function_arity const &arity) { - return gen_aot_call(Cpp::MakeAotCallable(expr->scope, __rt_ctx->unique_munged_string()), + return gen_aot_call(Cpp::MakeAotCallable(expr->scope, unique_munged_string()), nullptr, expr->type, Cpp::GetName(expr->scope), @@ -2662,7 +2661,7 @@ namespace jank::codegen return gen_aot_call(Cpp::MakeBuiltinOperatorAotCallable(static_cast(expr->op), expr->type, arg_types, - __rt_ctx->unique_munged_string()), + unique_munged_string()), nullptr, expr->type, name.getAsString(), @@ -2710,7 +2709,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return call; @@ -2737,7 +2736,7 @@ namespace jank::codegen if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(call); + return gen_ret(call); } return alloc; @@ -2763,7 +2762,7 @@ namespace jank::codegen if(!Cpp::IsTriviallyDestructible(expr->type)) { auto const dtor{ Cpp::GetDestructor(Cpp::GetScopeFromType(expr->type)) }; - auto const dtor_callable{ Cpp::MakeAotCallable(dtor, __rt_ctx->unique_munged_string()) }; + auto const dtor_callable{ Cpp::MakeAotCallable(dtor, unique_munged_string()) }; link_module(*ctx, reinterpret_cast(dtor_callable.getModule())); auto const reg_fn_type(llvm::FunctionType::get(ctx->builder->getVoidTy(), @@ -2811,7 +2810,7 @@ namespace jank::codegen if(!Cpp::IsTriviallyDestructible(value_type)) { auto const dtor{ Cpp::GetDestructor(Cpp::GetScopeFromType(value_type)) }; - auto const dtor_callable{ Cpp::MakeAotCallable(dtor, __rt_ctx->unique_munged_string()) }; + auto const dtor_callable{ Cpp::MakeAotCallable(dtor, unique_munged_string()) }; link_module(*ctx, reinterpret_cast(dtor_callable.getModule())); auto const dtor_fn_type( @@ -2832,10 +2831,10 @@ namespace jank::codegen llvm::SmallVector const args{ val }; ctx->builder->CreateCall(fn, args); - auto const ret{ gen_global(jank_nil) }; + auto const ret{ gen_global(jank_nil()) }; if(expr->position == expression_position::tail) { - return ctx->builder->CreateRet(ret); + return gen_ret(ret); } return ret; @@ -3740,6 +3739,63 @@ namespace jank::codegen return struct_type; } + util::scope_exit llvm_processor::impl::gen_stack_save() + { + /* In some cases, such as loops, we use LLVM's stack preservation intrinsics. + * These will help us reset the stack on each iteration so that each new alloc + * doesn't actually keep grabbing more stack space. + * + * However, there is some tricky logic in balancing each save/restore, since we + * can have multiple terminators in an IR function and we need to make sure that + * each of them gets a restore. Also, we can have nested saves and we need to + * make sure they get restored in the correct order. */ + auto const stack_ptr{ ctx->builder->CreateStackSave() }; + stack_saves.emplace_back(stack_ptr); + + /* The main logic here is to pop the back of the stack, but we add some error handling + * as well, to detect cases where we're not restoring in the correct order. */ + return { [stack_ptr, this]() { + ssize found{ -1 }; + for(ssize i{}; std::cmp_not_equal(i, stack_saves.size()); ++i) + { + if(stack_saves[i].data == stack_ptr) + { + found = i; + } + } + + jank_debug_assert(found == -1 || found == static_cast(stack_saves.size()) - 1); + if(found != -1) + { + stack_saves.erase(stack_saves.begin() + found); + } + } }; + } + + void llvm_processor::impl::gen_stack_restore() + { + jank_debug_assert(!stack_saves.empty()); + ctx->builder->CreateStackRestore(stack_saves.back()); + } + + jtl::ptr llvm_processor::impl::gen_ret(jtl::ptr const value) + { + for(auto it{ stack_saves.rbegin() }; it != stack_saves.rend(); ++it) + { + ctx->builder->CreateStackRestore(*it); + } + return ctx->builder->CreateRet(value); + } + + jtl::ptr llvm_processor::impl::gen_ret() + { + for(auto it{ stack_saves.rbegin() }; it != stack_saves.rend(); ++it) + { + ctx->builder->CreateStackRestore(*it); + } + return ctx->builder->CreateRetVoid(); + } + void llvm_processor::optimize() const { jtl::immutable_string_view const print_settings{ getenv("JANK_PRINT_IR") ?: "" }; diff --git a/compiler+runtime/src/cpp/jank/codegen/processor.cpp b/compiler+runtime/src/cpp/jank/codegen/processor.cpp index 6fba00c93..88710df18 100644 --- a/compiler+runtime/src/cpp/jank/codegen/processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/processor.cpp @@ -6,12 +6,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include +#include #include /* The strategy for codegen to C++ is quite simple. Codegen always happens on a @@ -20,8 +22,8 @@ * jank fn has a nested fn, it becomes a nested struct, since this whole * generation works recursively. * - * Analysis lifts constants and vars, so those just become members which are - * initialized in the ctor. + * During codegen, we lift constants and vars, so those just become members which + * are initialized in the ctor. * * The most interesting part is the translation of expressions into statements, * so that something like `(println (if foo bar spam))` can become sane C++. @@ -34,22 +36,28 @@ * roughly this C++: * * ```c++ - * object_ref thing_result(thing->call()); - * object_ref if_result; + * object_ref thing_tmp(thing->call()); + * object_ref if_tmp; * if(foo) - * { if_result = bar; } + * { if_tmp = bar; } * else - * { if_result = spam; } - * println->call(thing_result, if_result); + * { if_tmp = spam; } + * println->call(thing_tmp, if_tmp); * ``` * * This is optimized by knowing what position every expression in, so trivial expressions used * as arguments, for example, don't need to be first stored in temporaries. * - * Lastly, this is complicated by tracking boxing requirements so that not everything is an - * `object_ref`. Judicious use of `auto` and semantic analysis alows us to track when unboxing - * is supported, although we very rarely know for certain if something is unboxed. We usually - * only know if it _could_ be. + * Code generation has a target, which is either for eval or for a module. + * When the target is for eval, each generated function is standalone. This + * is the normal operation. However, when doing AOT compilation, our target + * will be a module and we'll do some code size optimizations to group all + * of the functions within a module into one namespace, dedupe constants, etc. + */ + +/* TODO: Size optimizations: + * - Remove object requirement for if condition + * - Remove extra if_n = jank_nil() on empty branches */ namespace jank::codegen @@ -64,7 +72,24 @@ namespace jank::codegen * the actual param names as mutable locals outside of the while loop. */ constexpr jtl::immutable_string_view const recur_suffix{ "__recur" }; - /* TODO: Consider making this a on the typed object: the C++ name. */ + static jtl::immutable_string + lift_constant(native_unordered_map, + runtime::very_equal_to> &lifted_constants, + object_ref const o) + { + auto const existing{ lifted_constants.find(o) }; + if(existing != lifted_constants.end()) + { + return existing->second; + } + + auto const &native_name{ runtime::munge(__rt_ctx->unique_string("const")) }; + lifted_constants.emplace(o, native_name); + return native_name; + } + static jtl::immutable_string gen_constant_type(runtime::object_ref const o, bool const boxed) { #pragma clang diagnostic push @@ -72,77 +97,54 @@ namespace jank::codegen switch(o->type) { case jank::runtime::object_type::nil: - { - return "jank::runtime::obj::nil_ref"; - } + return "jank::runtime::obj::nil_ref"; case jank::runtime::object_type::boolean: - { - return "jank::runtime::obj::boolean_ref"; - } + return "jank::runtime::obj::boolean_ref"; case jank::runtime::object_type::integer: + if(boxed) { - if(boxed) - { - return "jank::runtime::obj::integer_ref"; - } - return "jank::i64"; + return "jank::runtime::obj::integer_ref"; } + return "jank::i64"; case jank::runtime::object_type::character: + if(boxed) { - if(boxed) - { - return "jank::runtime::obj::character_ref"; - } - return "jank::runtime::obj::character"; + return "jank::runtime::obj::character_ref"; } + return "jank::runtime::obj::character"; case jank::runtime::object_type::real: + if(boxed) { - if(boxed) - { - return "jank::runtime::obj::real_ref"; - } - return "jank::f64"; + return "jank::runtime::obj::real_ref"; } + return "jank::f64"; case jank::runtime::object_type::symbol: - { - return "jank::runtime::obj::symbol_ref"; - } + return "jank::runtime::obj::symbol_ref"; case jank::runtime::object_type::keyword: - { - return "jank::runtime::obj::keyword_ref"; - } + return "jank::runtime::obj::keyword_ref"; case jank::runtime::object_type::persistent_string: - { - return "jank::runtime::obj::persistent_string_ref"; - } + return "jank::runtime::obj::persistent_string_ref"; case jank::runtime::object_type::persistent_list: - { - return "jank::runtime::obj::persistent_list_ref"; - } + return "jank::runtime::obj::persistent_list_ref"; case jank::runtime::object_type::persistent_vector: - { - return "jank::runtime::obj::persistent_vector_ref"; - } + return "jank::runtime::obj::persistent_vector_ref"; case jank::runtime::object_type::persistent_hash_set: - { - return "jank::runtime::obj::persistent_hash_set_ref"; - } + return "jank::runtime::obj::persistent_hash_set_ref"; case jank::runtime::object_type::persistent_array_map: - { - return "jank::runtime::obj::persistent_array_map_ref"; - } + return "jank::runtime::obj::persistent_array_map_ref"; case jank::runtime::object_type::var: - { - return "jank::runtime::var_ref"; - } + return "jank::runtime::var_ref"; default: - { - return "jank::runtime::object_ref"; - } + return "jank::runtime::object_ref"; } #pragma clang diagnostic pop } + static bool should_gen_meta(jtl::option const &meta) + { + return meta.is_some() && !runtime::is_empty(meta.unwrap()); + } + static void gen_constant(runtime::object_ref const o, jtl::string_builder &buffer, bool const boxed) { @@ -158,7 +160,7 @@ namespace jank::codegen if constexpr(std::same_as) { - util::format_to(buffer, "jank::runtime::jank_nil"); + util::format_to(buffer, "jank::runtime::jank_nil()"); } else if constexpr(std::same_as) { @@ -183,8 +185,41 @@ namespace jank::codegen { util::format_to(buffer, "jank::runtime::make_box(static_cast({}))", - typed_o->data); + "f64>("); + + if(std::isinf(typed_o->data)) + { + util::format_to(buffer, "INFINITY"); + } + else if(std::isnan(typed_o->data)) + { + util::format_to(buffer, "NAN"); + } + else + { + util::format_to(buffer, "{}", typed_o->data); + } + + util::format_to(buffer, "))"); + } + else if constexpr(std::same_as) + { + util::format_to(buffer, + "jank::runtime::make_box(\"{}\")", + typed_o->to_string()); + } + else if constexpr(std::same_as) + { + util::format_to(buffer, + "jank::runtime::make_box(\"{}\")", + typed_o->to_string()); + } + else if constexpr(std::same_as) + { + util::format_to(buffer, + "jank::runtime::obj::ratio::create({}, {})", + typed_o->data.numerator, + typed_o->data.denominator); } else if constexpr(std::same_as) { @@ -205,8 +240,8 @@ namespace jank::codegen else if constexpr(std::same_as) { util::format_to(buffer, - R"(jank::runtime::make_box({}))", - typed_o->to_code_string()); + R"(jank::runtime::make_box("{}"))", + util::escape(typed_o->to_string())); } else if constexpr(std::same_as) { @@ -216,111 +251,190 @@ namespace jank::codegen typed_o->sym->ns, typed_o->sym->name); } - else if constexpr(std::same_as) + else if constexpr(std::same_as) { util::format_to(buffer, - "jank::runtime::make_box({})", - typed_o->to_code_string()); + R"(jank::runtime::make_box({}))", + /* We remove the # prefix here. */ + typed_o->to_code_string().substr(1)); } - else if constexpr(std::same_as) + else if constexpr(std::same_as) { util::format_to(buffer, - "jank::runtime::make_box("); - if(typed_o->meta.is_some()) + R"(jank::runtime::make_box("{}"))", + typed_o->to_string()); + } + else if constexpr(std::same_as) + { + if(typed_o->data.empty()) + { + util::format_to(buffer, "jank::runtime::obj::persistent_string::empty()"); + } + else { - /* TODO: If meta is empty, use empty() fn. We'll need a gen helper for this. */ util::format_to(buffer, - "jank::runtime::__rt_ctx->read_string(\"{}\"), ", - util::escape(runtime::to_code_string(typed_o->meta.unwrap()))); + "jank::runtime::make_box({})", + typed_o->to_code_string()); } - util::format_to(buffer, "std::in_place "); - for(auto const &form : typed_o->data) + } + else if constexpr(std::same_as) + { + if(typed_o->data.empty()) { - util::format_to(buffer, ", "); - gen_constant(form, buffer, true); + util::format_to(buffer, "jank::runtime::obj::persistent_vector::empty()"); + if(should_gen_meta(typed_o->meta)) + { + util::format_to(buffer, "->with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ")"); + } + } + else + { + util::format_to(buffer, + "jank::runtime::make_box("); + if(should_gen_meta(typed_o->meta)) + { + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ","); + } + util::format_to(buffer, "std::in_place "); + for(auto const &form : typed_o->data) + { + util::format_to(buffer, ", "); + gen_constant(form, buffer, true); + } + util::format_to(buffer, ")"); } - util::format_to(buffer, ")"); } else if constexpr(std::same_as) { - util::format_to(buffer, - "jank::runtime::make_box("); - if(typed_o->meta.is_some()) + if(typed_o->data.empty()) { - util::format_to(buffer, - "jank::runtime::__rt_ctx->read_string(\"{}\"), ", - util::escape(runtime::to_code_string(typed_o->meta.unwrap()))); + util::format_to(buffer, "jank::runtime::obj::persistent_list::empty()"); + if(should_gen_meta(typed_o->meta)) + { + util::format_to(buffer, "->with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ")"); + } } - util::format_to(buffer, "std::in_place "); - for(auto const &form : typed_o->data) + else { - util::format_to(buffer, ", "); - gen_constant(form, buffer, true); + util::format_to(buffer, + "jank::runtime::make_box("); + if(should_gen_meta(typed_o->meta)) + { + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ","); + } + util::format_to(buffer, "std::in_place "); + for(auto const &form : typed_o->data) + { + util::format_to(buffer, ", "); + gen_constant(form, buffer, true); + } + util::format_to(buffer, ")"); } - util::format_to(buffer, ")"); } else if constexpr(std::same_as) { - util::format_to(buffer, - "jank::runtime::make_box("); - if(typed_o->meta.is_some()) + if(typed_o->data.empty()) { - util::format_to(buffer, - "jank::runtime::__rt_ctx->read_string(\"{}\"), ", - util::escape(runtime::to_code_string(typed_o->meta.unwrap()))); + util::format_to(buffer, "jank::runtime::obj::persistent_hash_set::empty()"); + if(should_gen_meta(typed_o->meta)) + { + util::format_to(buffer, "->with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ")"); + } } - util::format_to(buffer, "std::in_place "); - for(auto const &form : typed_o->data) + else { - util::format_to(buffer, ", "); - gen_constant(form, buffer, true); + util::format_to(buffer, + "jank::runtime::make_box("); + if(should_gen_meta(typed_o->meta)) + { + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ","); + } + util::format_to(buffer, "std::in_place "); + for(auto const &form : typed_o->data) + { + util::format_to(buffer, ", "); + gen_constant(form, buffer, true); + } + util::format_to(buffer, ")"); } - util::format_to(buffer, ")"); } else if constexpr(std::same_as) { - bool need_comma{}; - if(typed_o->meta.is_some()) + if(typed_o->data.empty()) { - util::format_to(buffer, - "jank::runtime::obj::persistent_array_map::create_unique_with_meta("); - util::format_to(buffer, - "jank::runtime::__rt_ctx->read_string(\"{}\")", - util::escape(runtime::to_code_string(typed_o->meta.unwrap()))); - need_comma = true; + util::format_to(buffer, "jank::runtime::obj::persistent_array_map::empty()"); + if(should_gen_meta(typed_o->meta)) + { + util::format_to(buffer, "->with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ")"); + } } else { - util::format_to(buffer, "jank::runtime::obj::persistent_array_map::create_unique("); - } - for(auto const &form : typed_o->data) - { - if(need_comma) + bool need_comma{}; + if(should_gen_meta(typed_o->meta)) + { + util::format_to( + buffer, + "jank::runtime::obj::persistent_array_map::create_unique_with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + need_comma = true; + } + else { + util::format_to(buffer, "jank::runtime::obj::persistent_array_map::create_unique("); + } + for(auto const &form : typed_o->data) + { + if(need_comma) + { + util::format_to(buffer, ", "); + } + need_comma = true; + gen_constant(form.first, buffer, true); util::format_to(buffer, ", "); + gen_constant(form.second, buffer, true); } - need_comma = true; - gen_constant(form.first, buffer, true); - util::format_to(buffer, ", "); - gen_constant(form.second, buffer, true); + util::format_to(buffer, ")"); } - util::format_to(buffer, ")"); } else if constexpr(std::same_as) { - auto const has_meta{ typed_o->meta.is_some() }; - if(has_meta) + if(typed_o->data.empty()) { - util::format_to(buffer, "jank::runtime::reset_meta("); + util::format_to(buffer, "jank::runtime::obj::persistent_hash_map::empty()"); + if(should_gen_meta(typed_o->meta)) + { + util::format_to(buffer, "->with_meta("); + gen_constant(typed_o->meta.unwrap(), buffer, true); + util::format_to(buffer, ")"); + } } - util::format_to(buffer, - "jank::runtime::__rt_ctx->read_string(\"{}\")", - util::escape(typed_o->to_code_string())); - if(has_meta) + else { + auto const has_meta{ should_gen_meta(typed_o->meta) }; + if(has_meta) + { + util::format_to(buffer, "jank::runtime::with_meta("); + } util::format_to(buffer, - ", jank::runtime::__rt_ctx->read_string(\"{}\"))", - util::escape(runtime::to_code_string(typed_o->meta.unwrap()))); + "jank::runtime::__rt_ctx->read_string(\"{}\")", + util::escape(typed_o->to_code_string())); + if(has_meta) + { + util::format_to(buffer, ","); + gen_constant(typed_o->meta.unwrap(), buffer, true); + } } } /* Cons, etc. */ @@ -329,7 +443,7 @@ namespace jank::codegen util::format_to( buffer, "jank::runtime::make_box(std::in_place"); - for(auto it : runtime::make_sequence_range(typed_o)) + for(auto const it : runtime::make_sequence_range(typed_o)) { util::format_to(buffer, ", "); gen_constant(it, buffer, true); @@ -344,25 +458,12 @@ namespace jank::codegen }, o); } - - static jtl::immutable_string boxed_local_name(jtl::immutable_string const &local_name) - { - return local_name + "__boxed"; - } } - handle::handle(jtl::immutable_string const &name, bool const boxed) + handle::handle(jtl::immutable_string const &name, bool const) + : boxed_name{ name } + , unboxed_name{ boxed_name } { - if(boxed) - { - boxed_name = name; - unboxed_name = boxed_name; - } - else - { - unboxed_name = name; - boxed_name = util::format("jank::runtime::make_box({})", unboxed_name); - } } handle::handle(jtl::immutable_string const &boxed_name) @@ -377,42 +478,19 @@ namespace jank::codegen { if(this->boxed_name.empty()) { - this->boxed_name = util::format("jank::runtime::make_box({})", unboxed_name); + this->boxed_name = unboxed_name; } } handle::handle(analyze::local_binding_ptr const binding) + : boxed_name{ runtime::munge(binding->native_name) } + , unboxed_name{ boxed_name } { - if(binding->needs_box) - { - boxed_name = runtime::munge(binding->native_name); - unboxed_name = boxed_name; - } - else if(binding->has_boxed_usage) - { - unboxed_name = runtime::munge(binding->native_name); - boxed_name = detail::boxed_local_name(unboxed_name); - } - else - { - unboxed_name = runtime::munge(binding->native_name); - } } - jtl::immutable_string handle::str(bool const needs_box) const + jtl::immutable_string handle::str(bool const) const { - if(needs_box) - { - if(boxed_name.empty()) - { - throw std::runtime_error{ util::format("Missing boxed name for handle {}", unboxed_name) }; - } - return boxed_name; - } - else - { - return unboxed_name; - } + return boxed_name; } processor::processor(analyze::expr::function_ref const expr, @@ -421,32 +499,56 @@ namespace jank::codegen : root_fn{ expr } , module{ module } , target{ target } - , struct_name{ root_fn->unique_name } + , struct_name{ runtime::munge(root_fn->unique_name) } { assert(root_fn->frame.data); } - jtl::option processor::gen(analyze::expression_ref const ex, - analyze::expr::function_arity const &fn_arity, - bool const box_needed) + jtl::option + processor::gen(analyze::expression_ref const ex, analyze::expr::function_arity const &fn_arity) { jtl::option ret; - visit_expr([&, this](auto const typed_ex) { ret = gen(typed_ex, fn_arity, box_needed); }, ex); + visit_expr([&, this](auto const typed_ex) { ret = gen(typed_ex, fn_arity); }, ex); return ret; } - jtl::option processor::gen(analyze::expr::def_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + static jtl::immutable_string + lift_var(native_unordered_map &lifted_vars, + jtl::immutable_string const &qualified_name, + bool const owned) { - auto const &var(expr->frame->find_lifted_var(expr->name).unwrap().get()); - auto const &munged_name(runtime::munge(var.native_name)); - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string(munged_name))); + auto const existing{ lifted_vars.find(qualified_name) }; + if(existing != lifted_vars.end()) + { + return existing->second.native_name; + } - jtl::option> meta; + static jtl::immutable_string const dot{ "\\." }; + auto const us{ __rt_ctx->unique_string(qualified_name) }; + auto const native_name{ runtime::munge_and_replace(us, dot, "_") }; + lifted_vars.emplace(qualified_name, processor::lifted_var{ native_name, owned }); + return native_name; + } + + jtl::option + processor::gen(analyze::expr::def_ref const expr, analyze::expr::function_arity const &fn_arity) + { + /* def uses a var, but we don't lift it. Even if it's lifted by another usage, + * it'll be re-interned here as an owned var. This needs to happen at the point + * of the def, rather than prior (i.e. due to lifting), since there could be + * some other var-related effects such as refer which need to happen before + * def. */ + auto var_tmp(runtime::munge(__rt_ctx->unique_string("var"))); + util::format_to( + body_buffer, + R"(auto const {}(jank::runtime::__rt_ctx->intern_owned_var("{}").expect_ok());)", + var_tmp, + expr->name->to_string()); + + jtl::option meta; if(expr->name->meta.is_some()) { - meta = expr->frame->find_lifted_constant(expr->name->meta.unwrap()).unwrap(); + meta = detail::lift_constant(lifted_constants, expr->name->meta.unwrap()); } /* Forward declarations just intern the var and evaluate to it. */ @@ -455,109 +557,129 @@ namespace jank::codegen if(meta.is_some()) { auto const dynamic{ truthy( - get(meta.unwrap().get().data, __rt_ctx->intern_keyword("dynamic").expect_ok())) }; - return util::format("{}->with_meta({})->set_dynamic({})", - runtime::munge(var.native_name), - runtime::munge(meta.unwrap().get().native_name), - dynamic); + get(expr->name->meta.unwrap(), __rt_ctx->intern_keyword("dynamic").expect_ok())) }; + + auto v{ + util::format("{}->with_meta({})->set_dynamic({})", var_tmp, meta.unwrap(), dynamic) + }; + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return {};", v); + return none; + } + return v; } else { - return util::format("{}->with_meta(jank::runtime::jank_nil)", - runtime::munge(var.native_name)); + auto v{ util::format("{}->with_meta(jank::runtime::jank_nil())", var_tmp) }; + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return {};", v); + return none; + } + return v; } } - auto const val(gen(expr->value.unwrap(), fn_arity, true).unwrap()); + auto const val(gen(expr->value.unwrap(), fn_arity).unwrap()); switch(expr->position) { case analyze::expression_position::value: + if(meta.is_some()) { - if(meta.is_some()) - { - auto const dynamic{ truthy( - get(meta.unwrap().get().data, __rt_ctx->intern_keyword("dynamic").expect_ok())) }; - return util::format("{}->bind_root({})->with_meta({})->set_dynamic({})", - runtime::munge(var.native_name), - val.str(true), - runtime::munge(meta.unwrap().get().native_name), - dynamic); - } - else - { - return util::format("{}->bind_root({})->with_meta(jank::runtime::jank_nil)", - runtime::munge(var.native_name), - val.str(true)); - } + auto const dynamic{ truthy( + get(expr->name->meta.unwrap(), __rt_ctx->intern_keyword("dynamic").expect_ok())) }; + return util::format("{}->bind_root({})->with_meta({})->set_dynamic({})", + var_tmp, + val.str(true), + meta.unwrap(), + dynamic); } - case analyze::expression_position::tail: + else { - util::format_to(body_buffer, "return "); + return util::format("{}->bind_root({})->with_meta(jank::runtime::jank_nil())", + var_tmp, + val.str(true)); } + case analyze::expression_position::tail: + util::format_to(body_buffer, "return "); + [[fallthrough]]; case analyze::expression_position::statement: + if(meta.is_some()) { - if(meta.is_some()) - { - auto const dynamic{ truthy( - get(meta.unwrap().get().data, __rt_ctx->intern_keyword("dynamic").expect_ok())) }; - util::format_to(body_buffer, - "{}->bind_root({})->with_meta({})->set_dynamic({});", - runtime::munge(var.native_name), - val.str(true), - runtime::munge(meta.unwrap().get().native_name), - dynamic); - } - else - { - util::format_to(body_buffer, - "{}->bind_root({})->with_meta(jank::runtime::jank_nil);", - runtime::munge(var.native_name), - val.str(true)); - } - return none; + auto const dynamic{ truthy( + get(expr->name->meta.unwrap(), __rt_ctx->intern_keyword("dynamic").expect_ok())) }; + util::format_to(body_buffer, + "{}->bind_root({})->with_meta({})->set_dynamic({});", + var_tmp, + val.str(true), + meta.unwrap(), + dynamic); + } + else + { + util::format_to(body_buffer, + "{}->bind_root({})->with_meta(jank::runtime::jank_nil());", + var_tmp, + val.str(true)); } + return none; } } - jtl::option processor::gen(analyze::expr::var_deref_ref const expr, - analyze::expr::function_arity const &, - bool const) + jtl::option + processor::gen(analyze::expr::var_deref_ref const expr, analyze::expr::function_arity const &) { - auto const &var(expr->frame->find_lifted_var(expr->qualified_name).unwrap().get()); + auto const &var(lift_var(lifted_vars, expr->var->to_qualified_symbol()->to_string(), false)); switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: - { - return util::format("{}->deref()", runtime::munge(var.native_name)); - } + return util::format("{}->deref()", var); case analyze::expression_position::tail: - { - util::format_to(body_buffer, "return {}->deref();", runtime::munge(var.native_name)); - return none; - } + util::format_to(body_buffer, "return {}->deref();", var); + return none; } } - jtl::option processor::gen(analyze::expr::var_ref_ref const expr, - analyze::expr::function_arity const &, - bool const) + jtl::option + processor::gen(analyze::expr::var_ref_ref const expr, analyze::expr::function_arity const &) { - auto const &var(expr->frame->find_lifted_var(expr->qualified_name).unwrap().get()); + auto const &var(lift_var(lifted_vars, expr->qualified_name->to_string(), false)); switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: - { - return runtime::munge(var.native_name); - } + return var; case analyze::expression_position::tail: - { - util::format_to(body_buffer, "return {};", runtime::munge(var.native_name)); - return none; - } + util::format_to(body_buffer, "return {};", var); + return none; + } + } + + void processor::format_dynamic_call(jtl::immutable_string const &source_tmp, + jtl::immutable_string const &ret_tmp, + native_vector const &arg_exprs, + analyze::expr::function_arity const &fn_arity) + { + native_vector arg_tmps; + arg_tmps.reserve(arg_exprs.size()); + for(auto const &arg_expr : arg_exprs) + { + arg_tmps.emplace_back(gen(arg_expr, fn_arity).unwrap()); } + + util::format_to(body_buffer, + "auto const {}(jank::runtime::dynamic_call({}", + ret_tmp, + source_tmp); + for(size_t i{}; i < arg_tmps.size(); ++i) + { + util::format_to(body_buffer, ", {}", arg_tmps[i].str(true)); + } + + util::format_to(body_buffer, "));"); } void processor::format_elided_var(jtl::immutable_string const &start, @@ -565,15 +687,14 @@ namespace jank::codegen jtl::immutable_string const &ret_tmp, native_vector const &arg_exprs, analyze::expr::function_arity const &fn_arity, - bool const arg_box_needed, - bool const ret_box_needed) + bool ret_box_needed) { /* TODO: Assert arg count when we know it. */ native_vector arg_tmps; arg_tmps.reserve(arg_exprs.size()); for(auto const &arg_expr : arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, fn_arity, arg_box_needed).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, fn_arity).unwrap()); } jtl::immutable_string ret_box; @@ -589,7 +710,7 @@ namespace jank::codegen { util::format_to(body_buffer, ", "); } - util::format_to(body_buffer, "{}", arg_tmps[i].str(arg_box_needed)); + util::format_to(body_buffer, "{}", arg_tmps[i].str(false)); need_comma = true; } util::format_to(body_buffer, "{}{});", end, (ret_box_needed ? ")" : "")); @@ -598,17 +719,16 @@ namespace jank::codegen void processor::format_direct_call(jtl::immutable_string const &source_tmp, jtl::immutable_string const &ret_tmp, native_vector const &arg_exprs, - analyze::expr::function_arity const &fn_arity, - bool const arg_box_needed) + analyze::expr::function_arity const &fn_arity) { native_vector arg_tmps; arg_tmps.reserve(arg_exprs.size()); for(auto const &arg_expr : arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, fn_arity, arg_box_needed).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, fn_arity).unwrap()); } - util::format_to(body_buffer, "auto const {}({}.call(", ret_tmp, source_tmp); + util::format_to(body_buffer, "auto const {}({}->call(", ret_tmp, source_tmp); bool need_comma{}; for(size_t i{}; i < runtime::max_params && i < arg_tmps.size(); ++i) @@ -623,372 +743,281 @@ namespace jank::codegen util::format_to(body_buffer, "));"); } - void processor::format_dynamic_call(jtl::immutable_string const &source_tmp, - jtl::immutable_string const &ret_tmp, - native_vector const &arg_exprs, - analyze::expr::function_arity const &fn_arity, - bool const arg_box_needed) + jtl::option + processor::gen(analyze::expr::call_ref const expr, analyze::expr::function_arity const &fn_arity) { - //util::println("format_dynamic_call source {}", source_tmp); - native_vector arg_tmps; - arg_tmps.reserve(arg_exprs.size()); - for(auto const &arg_expr : arg_exprs) - { - //util::println("\tformat_dynamic_call arg {}", - // runtime::to_code_string(arg_expr->to_runtime_data())); - arg_tmps.emplace_back(gen(arg_expr, fn_arity, arg_box_needed).unwrap()); - } - - util::format_to(body_buffer, - "auto const {}(jank::runtime::dynamic_call({}", - ret_tmp, - source_tmp); - for(size_t i{}; i < runtime::max_params && i < arg_tmps.size(); ++i) - { - util::format_to(body_buffer, ", {}", arg_tmps[i].str(true)); - } + handle ret_tmp{ runtime::munge(__rt_ctx->unique_string("call")) }; - if(runtime::max_params < arg_tmps.size()) - { - util::format_to( - body_buffer, - ", jank::runtime::make_box(std::in_place"); - for(size_t i{ runtime::max_params }; i < arg_tmps.size(); ++i) - { - util::format_to(body_buffer, ", {}", arg_tmps[i].str(true)); - } - util::format_to(body_buffer, ")"); - } - util::format_to(body_buffer, "));"); - } - - jtl::option processor::gen(analyze::expr::call_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const box_needed) - { - /* TODO: Doesn't take into account boxing. */ - handle ret_tmp{ runtime::munge(__rt_ctx->unique_namespaced_string("call")) }; /* Clojure's codegen actually skips vars for certain calls to clojure.core * fns; this is not the same as direct linking, which uses `invokeStatic` * instead. Rather, this makes calls to `get` become `RT.get`, calls to `+` become * `Numbers.add`, and so on. We do the same thing here. */ bool elided{}; /* TODO: Use the actual var meta to do this, not a hard-coded set of if checks. */ - if(auto const * const ref = dynamic_cast(expr->source_expr.data)) + if(auto const ref{ dynamic_cast(expr->source_expr.data) }; ref) { - auto const &name{ ref->var->name->name }; + auto const &sym{ ref->var->name->name }; if(ref->var->n->name->name != "clojure.core") { } - else if(name == "get") + else if(sym == "get") { format_elided_var("jank::runtime::get(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } else if(expr->arg_exprs.empty()) { - if(name == "rand") + if(sym == "rand") { format_elided_var("jank::runtime::rand(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } } else if(expr->arg_exprs.size() == 1) { - //if(name == "print") - //{ - // format_elided_var("jank::runtime::print(", - // ")", - // ret_tmp.str(false), - // expr->arg_exprs, - // fn_arity, - // true, - // false); - // elided = true; - //} - if(name == "abs") + if(sym == "abs") { format_elided_var("jank::runtime::abs(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "sqrt") + else if(sym == "sqrt") { format_elided_var("jank::runtime::sqrt(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "int") + else if(sym == "int") { format_elided_var("jank::runtime::to_int(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "seq") + else if(sym == "seq") { format_elided_var("jank::runtime::seq(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } - else if(name == "fresh-seq") + else if(sym == "fresh_seq") { format_elided_var("jank::runtime::fresh_seq(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } - else if(name == "first") + else if(sym == "first") { format_elided_var("jank::runtime::first(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } - else if(name == "next") + else if(sym == "next") { format_elided_var("jank::runtime::next(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } - else if(name == "next-in-place") + else if(sym == "next_in_place") { format_elided_var("jank::runtime::next_in_place(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } - else if(name == "nil?") + else if(sym == "nil?") { format_elided_var("jank::runtime::is_nil(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, - box_needed); + true); elided = true; } - else if(name == "some?") + else if(sym == "some?") { format_elided_var("jank::runtime::is_some(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, - box_needed); + true); elided = true; } } else if(expr->arg_exprs.size() == 2) { - if(name == "+") + if(sym == "+") { format_elided_var("jank::runtime::add(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "-") + else if(sym == "-") { format_elided_var("jank::runtime::sub(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "*") + else if(sym == "*") { format_elided_var("jank::runtime::mul(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "/") + else if(sym == "/") { format_elided_var("jank::runtime::div(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "<") + else if(sym == "<") { format_elided_var("jank::runtime::lt(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "<=") + else if(sym == "<=") { format_elided_var("jank::runtime::lte(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == ">") + else if(sym == ">") { format_elided_var("jank::runtime::lt(", ")", ret_tmp.str(false), { expr->arg_exprs.rbegin(), expr->arg_exprs.rend() }, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == ">=") + else if(sym == ">=") { format_elided_var("jank::runtime::lte(", ")", ret_tmp.str(false), { expr->arg_exprs.rbegin(), expr->arg_exprs.rend() }, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "min") + else if(sym == "min") { format_elided_var("jank::runtime::min(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "max") + else if(sym == "max") { format_elided_var("jank::runtime::max(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "pow") + else if(sym == "pow") { format_elided_var("jank::runtime::pow(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - false, - box_needed); + true); elided = true; - ret_tmp = { ret_tmp.unboxed_name, box_needed }; } - else if(name == "conj") + else if(sym == "conj") { format_elided_var("jank::runtime::conj(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } } else if(expr->arg_exprs.size() == 3) { - if(name == "assoc") + if(sym == "assoc") { format_elided_var("jank::runtime::assoc(", ")", ret_tmp.str(false), expr->arg_exprs, fn_arity, - true, false); elided = true; } @@ -1006,30 +1035,26 @@ namespace jank::codegen } if(!variadic) { - auto const &source_tmp(gen(expr->source_expr, fn_arity, false)); + auto const &source_tmp(gen(expr->source_expr, fn_arity)); format_direct_call(source_tmp.unwrap().str(false), ret_tmp.str(true), expr->arg_exprs, - fn_arity, - true); + fn_arity); elided = true; } } if(!elided) { - auto const &source_tmp(gen(expr->source_expr, fn_arity, false)); + auto const &source_tmp(gen(expr->source_expr, fn_arity)); format_dynamic_call(source_tmp.unwrap().str(true), ret_tmp.str(true), expr->arg_exprs, - fn_arity, - true); + fn_arity); } if(expr->position == analyze::expression_position::tail) { - /* TODO: Box here, not in the calls above. Using false when we mean true is not good. */ - /* No need for extra boxing on this, since the boxing was done on the call above. */ util::format_to(body_buffer, "return {};", ret_tmp.str(false)); return none; } @@ -1038,45 +1063,81 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::primitive_literal_ref const expr, - analyze::expr::function_arity const &, - bool const) + analyze::expr::function_arity const &) { - auto const &constant(expr->frame->find_lifted_constant(expr->data).unwrap().get()); - - handle ret{ runtime::munge(constant.native_name) }; - if(constant.unboxed_native_name.is_some()) + handle ret; + if(expr->data->type == runtime::object_type::nil) + { + ret = handle{ "jank::runtime::jank_nil()" }; + } + else if(expr->data->type == runtime::object_type::boolean) + { + ret = handle{ runtime::truthy(expr->data) ? "jank::runtime::jank_true" + : "jank::runtime::jank_false" }; + } + else { - ret = { runtime::munge(constant.native_name), - runtime::munge(constant.unboxed_native_name.unwrap()) }; + ret = detail::lift_constant(lifted_constants, expr->data); } switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: - { - return ret; - } + return ret; case analyze::expression_position::tail: - { - util::format_to(body_buffer, "return {};", ret.str(expr->needs_box)); - return none; - } + util::format_to(body_buffer, "return {};", ret.str(expr->needs_box)); + return none; + } + } + + jtl::option + processor::gen(analyze::expr::list_ref const expr, analyze::expr::function_arity const &fn_arity) + { + native_vector data_tmps; + data_tmps.reserve(expr->data_exprs.size()); + for(auto const &data_expr : expr->data_exprs) + { + data_tmps.emplace_back(gen(data_expr, fn_arity).unwrap()); + } + + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("list"))); + util::format_to(body_buffer, + "auto const {}(jank::runtime::make_box(", + ret_tmp); + if(expr->meta.is_some()) + { + detail::gen_constant(expr->meta.unwrap(), body_buffer, true); + util::format_to(body_buffer, ", "); + } + util::format_to(body_buffer, "std::in_place "); + for(auto const &tmp : data_tmps) + { + util::format_to(body_buffer, ", "); + util::format_to(body_buffer, "{}", tmp.str(true)); } + util::format_to(body_buffer, "));"); + + if(expr->position == analyze::expression_position::tail) + { + util::format_to(body_buffer, "return {};", ret_tmp); + return none; + } + + return ret_tmp; } jtl::option processor::gen(analyze::expr::vector_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + analyze::expr::function_arity const &fn_arity) { native_vector data_tmps; data_tmps.reserve(expr->data_exprs.size()); for(auto const &data_expr : expr->data_exprs) { - data_tmps.emplace_back(gen(data_expr, fn_arity, true).unwrap()); + data_tmps.emplace_back(gen(data_expr, fn_arity).unwrap()); } - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("vec"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("vec"))); util::format_to(body_buffer, "auto const {}(jank::runtime::make_box(", ret_tmp); @@ -1102,19 +1163,18 @@ namespace jank::codegen return ret_tmp; } - jtl::option processor::gen(analyze::expr::map_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::map_ref const expr, analyze::expr::function_arity const &fn_arity) { native_vector> data_tmps; data_tmps.reserve(expr->data_exprs.size()); for(auto const &data_expr : expr->data_exprs) { - data_tmps.emplace_back(gen(data_expr.first, fn_arity, true).unwrap(), - gen(data_expr.second, fn_arity, true).unwrap()); + data_tmps.emplace_back(gen(data_expr.first, fn_arity).unwrap(), + gen(data_expr.second, fn_arity).unwrap()); } - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("map"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("map"))); /* Jump right to a hash map, if we have enough values. */ if(expr->data_exprs.size() <= runtime::obj::persistent_array_map::max_size) @@ -1182,18 +1242,17 @@ namespace jank::codegen return ret_tmp; } - jtl::option processor::gen(analyze::expr::set_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::set_ref const expr, analyze::expr::function_arity const &fn_arity) { native_vector data_tmps; data_tmps.reserve(expr->data_exprs.size()); for(auto const &data_expr : expr->data_exprs) { - data_tmps.emplace_back(gen(data_expr, fn_arity, true).unwrap()); + data_tmps.emplace_back(gen(data_expr, fn_arity).unwrap()); } - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("set"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("set"))); util::format_to( body_buffer, "auto const {}(jank::runtime::make_box(", @@ -1221,94 +1280,105 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::local_reference_ref const expr, - analyze::expr::function_arity const &, - bool const) + analyze::expr::function_arity const &) { - auto const munged_name(runtime::munge(expr->binding->native_name)); - - handle ret; - if(expr->binding->needs_box) - { - ret = munged_name; - } - else - { - ret = handle{ detail::boxed_local_name(munged_name), munged_name }; - } + auto ret(runtime::munge(expr->binding->native_name)); switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: - { - return ret; - } + return ret; case analyze::expression_position::tail: - { - util::format_to(body_buffer, "return {};", ret.str(expr->needs_box)); - return none; - } + util::format_to(body_buffer, "return {};", ret); + return none; } } - jtl::option processor::gen(analyze::expr::function_ref const expr, - analyze::expr::function_arity const &, - bool const box_needed) + jtl::option + processor::gen(analyze::expr::function_ref const expr, analyze::expr::function_arity const &) { - auto const compiling(truthy(__rt_ctx->compile_files_var->deref())); + auto const fn_target((target == compilation_target::eval) ? compilation_target::eval + : compilation_target::function); /* Since each codegen proc handles one callable struct, we create a new one for this fn. */ - processor prc{ expr, - module, - //runtime::module::nest_module(module, runtime::munge(expr->unique_name)), - compiling ? compilation_target::function : compilation_target::eval }; + processor prc{ expr, module, fn_target }; - /* If we're compiling, we'll create a separate file for this. */ - //if(target != compilation_target::module) + if(fn_target == compilation_target::function) { - util::format_to(deps_buffer, "{}", prc.declaration_str()); + /* TODO: Share a context instead. */ + prc.lifted_vars = lifted_vars; + prc.lifted_constants = lifted_constants; + + prc.build_body(); + + lifted_vars = jtl::move(prc.lifted_vars); + lifted_constants = jtl::move(prc.lifted_constants); + prc.lifted_vars.clear(); + prc.lifted_constants.clear(); } + util::format_to(deps_buffer, "{}", prc.declaration_str()); + switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: - /* TODO: Return a handle. */ - { - return prc.expression_str(box_needed); - } + return prc.expression_str(); case analyze::expression_position::tail: - { - util::format_to(body_buffer, "return {};", prc.expression_str(box_needed)); - return none; - } + util::format_to(body_buffer, "return {};", prc.expression_str()); + return none; } } - jtl::option processor::gen(analyze::expr::recur_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::recur_ref const expr, analyze::expr::function_arity const &fn_arity) { native_vector arg_tmps; arg_tmps.reserve(expr->arg_exprs.size()); for(auto const &arg_expr : expr->arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, fn_arity, true).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, fn_arity).unwrap()); } auto arg_tmp_it(arg_tmps.begin()); - for(auto const ¶m : fn_arity.params) + if(expr->loop_target.is_some()) + { + auto const let{ expr->loop_target.unwrap() }; + for(usize i{}; i < expr->arg_exprs.size(); ++i) + { + auto const &pair{ let->pairs[i] }; + auto const local(expr->frame->find_local_or_capture(pair.first)); + auto const &local_name(runtime::munge(local.unwrap().binding->native_name)); + auto const &val_name(arg_tmp_it->str(true)); + + if(local_name != val_name) + { + util::format_to(body_buffer, "{} = {};", local_name, val_name); + } + ++arg_tmp_it; + } + + util::format_to(body_buffer, "continue;"); + } + else { - util::format_to(body_buffer, "{} = {};", runtime::munge(param->name), arg_tmp_it->str(true)); - ++arg_tmp_it; + for(auto const ¶m : fn_arity.params) + { + util::format_to(body_buffer, + "{} = {};", + runtime::munge(param->name), + arg_tmp_it->str(true)); + ++arg_tmp_it; + } + util::format_to(body_buffer, "continue;"); } - util::format_to(body_buffer, "continue;"); + return none; } /* NOLINTNEXTLINE(readability-make-member-function-const): Can't be const, due to overload resolution. */ jtl::option processor::gen(analyze::expr::recursion_reference_ref const expr, - analyze::expr::function_arity const &, - bool const) + analyze::expr::function_arity const &) { if(expr->position == analyze::expression_position::tail) { @@ -1319,18 +1389,16 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::named_recursion_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + analyze::expr::function_arity const &fn_arity) { - handle ret_tmp{ runtime::munge(__rt_ctx->unique_namespaced_string("named_recursion")) }; + handle ret_tmp{ runtime::munge(__rt_ctx->unique_string("named_recursion")) }; auto const &source_tmp( - gen(jtl::ref{ &expr->recursion_ref }, fn_arity, false)); + gen(jtl::ref{ &expr->recursion_ref }, fn_arity)); format_dynamic_call(source_tmp.unwrap().str(true), ret_tmp.str(true), expr->arg_exprs, - fn_arity, - true); + fn_arity); if(expr->position == analyze::expression_position::tail) { @@ -1341,98 +1409,96 @@ namespace jank::codegen return ret_tmp; } - jtl::option processor::gen(analyze::expr::let_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::let_ref const expr, analyze::expr::function_arity const &fn_arity) { - handle const ret_tmp{ runtime::munge(__rt_ctx->unique_namespaced_string("let")), - expr->needs_box }; + auto const &ret_tmp{ runtime::munge(__rt_ctx->unique_string("let")) }; bool used_option{}; - if(expr->needs_box) - { - /* TODO: The type may not be default constructible so this may fail. We likely - * want an array the same size as the desired type. When we have the last expression, - * we can then do a placement new with the move ctor. - * - * Also add a test for this. */ - auto const last_expr_type{ cpp_util::expression_type( - expr->body->values[expr->body->values.size() - 1]) }; + auto const last_expr_type{ cpp_util::expression_type( + expr->body->values[expr->body->values.size() - 1]) }; - jtl::immutable_string type_name; - /* In analysis, we treat untyped objects as object*, since that's easier for IR. - * However, for C++, we want to normalize that to object_ref to take full advantage - * of richer types. */ - if(cpp_util::is_untyped_object(last_expr_type)) - { - type_name = "object_ref"; - util::format_to(body_buffer, "{} {}{ }; {", type_name, ret_tmp.str(expr->needs_box)); - } - else - { - used_option = true; - type_name = Cpp::GetTypeAsString(Cpp::GetNonReferenceType(last_expr_type)); - /* TODO: Test for this with something non-default constructible. */ - util::format_to(body_buffer, - "jtl::option<{}> {}{ }; {", - type_name, - ret_tmp.str(expr->needs_box)); - } + auto const &type_name{ cpp_util::get_qualified_type_name( + Cpp::GetNonReferenceType(last_expr_type)) }; + if(cpp_util::is_any_object(last_expr_type)) + { + util::format_to(body_buffer, "{} {}{ }; {", type_name, ret_tmp); } else { - util::format_to(body_buffer, - "auto const {}([&](){}{", - ret_tmp.str(expr->needs_box), - (expr->needs_box ? "-> object_ref" : "")); + used_option = true; + util::format_to(body_buffer, "jtl::option<{}> {}{ }; {", type_name, ret_tmp); } for(auto const &pair : expr->pairs) { auto const local(expr->frame->find_local_or_capture(pair.first)); - if(local.is_none()) - { - throw std::runtime_error{ util::format("ICE: unable to find local: {}", - pair.first->to_string()) }; - } - - auto const &val_tmp(gen(pair.second, fn_arity, pair.second->needs_box)); + auto const local_type{ cpp_util::expression_type(pair.second) }; + auto const &val_tmp(gen(pair.second, fn_arity)); auto const &munged_name(runtime::munge(local.unwrap().binding->native_name)); + /* Every binding is wrapped in its own scope, to allow shadowing. * * Also, bindings are references to their value expression, rather than a copy. * This is important for C++ interop, since the we don't want to, and we may not - * be able to, just copy stack-allocated C++ objects around willy nillly. */ - util::format_to(body_buffer, "{ auto &&{}({}); ", munged_name, val_tmp.unwrap().str(false)); - - auto const binding(local.unwrap().binding); - if(!binding->needs_box && binding->has_boxed_usage) + * be able to, just copy stack-allocated C++ objects around willy nilly. */ + if(expr->is_loop) { - util::format_to(body_buffer, - "auto const {}({});", - detail::boxed_local_name(munged_name), - val_tmp.unwrap().str(true)); + if(cpp_util::is_any_object(local_type)) + { + util::format_to(body_buffer, + "{ jank::runtime::object_ref {}({}); ", + munged_name, + val_tmp.unwrap().str(true)); + } + else + { + util::format_to(body_buffer, "{ auto {}({}); ", munged_name, val_tmp.unwrap().str(true)); + } + } + else + { + /* Local array refs should be turned into pointers so we can work with them more easily. */ + if(Cpp::IsArrayType(Cpp::GetNonReferenceType(local_type))) + { + util::format_to(body_buffer, + "{ {} {}({}); ", + cpp_util::get_qualified_type_name(Cpp::GetPointerType( + Cpp::GetArrayElementType(Cpp::GetNonReferenceType(local_type)))), + munged_name, + val_tmp.unwrap().str(false)); + } + else + { + util::format_to(body_buffer, + "{ auto &&{}({}); ", + munged_name, + val_tmp.unwrap().str(false)); + } } } + if(expr->is_loop) + { + util::format_to(body_buffer, "while(true){"); + } + for(auto it(expr->body->values.begin()); it != expr->body->values.end();) { - auto const &val_tmp(gen(*it, fn_arity, true)); + auto const &val_tmp(gen(*it, fn_arity)); /* We ignore all values but the last. */ if(++it == expr->body->values.end() && val_tmp.is_some()) { - if(expr->needs_box) - { - /* The last expression tmp needs to be movable. */ - util::format_to(body_buffer, - "{} = std::move({});", - ret_tmp.str(true), - val_tmp.unwrap().str(expr->needs_box)); - } - else + /* The last expression tmp needs to be movable. */ + util::format_to(body_buffer, + "{} = std::move({});", + ret_tmp, + val_tmp.unwrap().str(expr->needs_box)); + + if(expr->is_loop) { - util::format_to(body_buffer, "return {};", val_tmp.unwrap().str(expr->needs_box)); + util::format_to(body_buffer, " break;"); } } } @@ -1442,77 +1508,168 @@ namespace jank::codegen util::format_to(body_buffer, "}"); } - if(expr->needs_box) + if(expr->is_loop) { util::format_to(body_buffer, "}"); } - else - { - util::format_to(body_buffer, "}());"); - } + + util::format_to(body_buffer, "}"); if(expr->position == analyze::expression_position::tail) { - util::format_to(body_buffer, - "return {}{};", - ret_tmp.str(expr->needs_box), - (used_option ? ".unwrap()" : "")); + util::format_to(body_buffer, "return {}{};", ret_tmp, (used_option ? ".unwrap()" : "")); return none; } - return util::format("{}{}", ret_tmp.str(expr->needs_box), (used_option ? ".unwrap()" : "")); + return util::format("{}{}", ret_tmp, (used_option ? ".unwrap()" : "")); } jtl::option - processor::gen(analyze::expr::letfn_ref const, analyze::expr::function_arity const &, bool const) + processor::gen(analyze::expr::letfn_ref const expr, analyze::expr::function_arity const &fn_arity) { - return none; + auto const &ret_tmp{ runtime::munge(__rt_ctx->unique_string("letfn")) }; + bool used_option{}; + + auto const last_expr_type{ cpp_util::expression_type( + expr->body->values[expr->body->values.size() - 1]) }; + + auto const &type_name{ cpp_util::get_qualified_type_name( + Cpp::GetNonReferenceType(last_expr_type)) }; + if(cpp_util::is_any_object(last_expr_type)) + { + util::format_to(body_buffer, "{} {}{ }; {", type_name, ret_tmp); + } + else + { + used_option = true; + util::format_to(body_buffer, "jtl::option<{}> {}{ }; {", type_name, ret_tmp); + } + + /* We don't handle shadowed bindings very well, so we can run into problems where our + * codegen doesn't work. For letfn, we detect shadowed bindings and get around potential + * assignment issues by just using an object_ref. This can be removed once we + * properly give shadowed bindings individual local_binding entries or we have some other + * mechanism for tracking them. */ + bool has_shadowed_bindings{}; + native_set seen_names; + for(auto const &pair : expr->pairs) + { + auto const local(expr->frame->find_local_or_capture(pair.first)); + auto const &name{ local.unwrap().binding->native_name }; + if(seen_names.contains(name)) + { + has_shadowed_bindings = true; + break; + } + seen_names.emplace(name); + } + + for(auto const &pair : expr->pairs) + { + auto const local(expr->frame->find_local_or_capture(pair.first)); + auto const val_expr(llvm::cast(pair.second.data)); + auto const &munged_name(runtime::munge(local.unwrap().binding->native_name)); + auto const type_name{ ( + has_shadowed_bindings + ? "jank::runtime::object_ref" + : util::format("jank::runtime::oref<{}>", runtime::munge(val_expr->unique_name))) }; + util::format_to(body_buffer, "{ {} {};", type_name, munged_name); + } + + for(auto const &pair : expr->pairs) + { + auto const local(expr->frame->find_local_or_capture(pair.first)); + auto const &val_tmp(gen(pair.second, fn_arity)); + auto const &munged_name(runtime::munge(local.unwrap().binding->native_name)); + + util::format_to(body_buffer, "{} = {}; ", munged_name, val_tmp.unwrap().str(false)); + } + + for(auto const &pair : expr->pairs) + { + auto const local(expr->frame->find_local_or_capture(pair.first)); + + auto const &munged_name(runtime::munge(local.unwrap().binding->native_name)); + auto const val_expr(llvm::cast(pair.second.data)); + for(auto const &capture_pair : val_expr->captures()) + { + auto const &capture_name(runtime::munge(capture_pair.second->native_name)); + util::format_to(body_buffer, "{}->{} = {}; ", munged_name, capture_name, capture_name); + } + } + + for(auto it(expr->body->values.begin()); it != expr->body->values.end();) + { + auto const &val_tmp(gen(*it, fn_arity)); + + /* We ignore all values but the last. */ + if(++it == expr->body->values.end() && val_tmp.is_some()) + { + /* The last expression tmp needs to be movable. */ + util::format_to(body_buffer, + "{} = std::move({});", + ret_tmp, + val_tmp.unwrap().str(expr->needs_box)); + } + } + for(auto const &_ : expr->pairs) + { + static_cast(_); + util::format_to(body_buffer, "}"); + } + + util::format_to(body_buffer, "}"); + + if(expr->position == analyze::expression_position::tail) + { + util::format_to(body_buffer, "return {}{};", ret_tmp, (used_option ? ".unwrap()" : "")); + return none; + } + + return util::format("{}{}", ret_tmp, (used_option ? ".unwrap()" : "")); } - jtl::option processor::gen(analyze::expr::do_ref const expr, - analyze::expr::function_arity const &arity, - bool const) + jtl::option + processor::gen(analyze::expr::do_ref const expr, analyze::expr::function_arity const &arity) { jtl::option last; for(auto const &form : expr->values) { - last = gen(form, arity, true); + last = gen(form, arity); } switch(expr->position) { case analyze::expression_position::statement: case analyze::expression_position::value: + return last; + case analyze::expression_position::tail: + if(last.is_none()) { - return last; + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); } - case analyze::expression_position::tail: + else { - if(last.is_none()) - { - util::format_to(body_buffer, "return jank::runtime::jank_nil;"); - } - else - { - util::format_to(body_buffer, "return {};", last.unwrap().str(expr->needs_box)); - } - return none; + util::format_to(body_buffer, "return {};", last.unwrap().str(expr->needs_box)); } + return none; } } - jtl::option processor::gen(analyze::expr::if_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::if_ref const expr, analyze::expr::function_arity const &fn_arity) { - /* TODO: Handle unboxed results! */ - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("if"))); - util::format_to(body_buffer, "object_ref {}{ };", ret_tmp); - auto const &condition_tmp(gen(expr->condition, fn_arity, false)); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("if"))); + auto const expr_type{ cpp_util::expression_type(expr->then) }; + util::format_to(body_buffer, + "{} {}{ };", + cpp_util::get_qualified_type_name(expr_type), + ret_tmp); + auto const &condition_tmp(gen(expr->condition, fn_arity)); util::format_to(body_buffer, "if(jank::runtime::truthy({})) {", condition_tmp.unwrap().str(false)); - auto const &then_tmp(gen(expr->then, fn_arity, true)); + auto const &then_tmp(gen(expr->then, fn_arity)); if(then_tmp.is_some()) { util::format_to(body_buffer, "{} = {}; }", ret_tmp, then_tmp.unwrap().str(expr->needs_box)); @@ -1525,7 +1682,7 @@ namespace jank::codegen if(expr->else_.is_some()) { util::format_to(body_buffer, "else {"); - auto const &else_tmp(gen(expr->else_.unwrap(), fn_arity, true)); + auto const &else_tmp(gen(expr->else_.unwrap(), fn_arity)); if(else_tmp.is_some()) { util::format_to(body_buffer, "{} = {}; }", ret_tmp, else_tmp.unwrap().str(expr->needs_box)); @@ -1545,43 +1702,47 @@ namespace jank::codegen return ret_tmp; } - jtl::option processor::gen(analyze::expr::throw_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const) + jtl::option + processor::gen(analyze::expr::throw_ref const expr, analyze::expr::function_arity const &fn_arity) { - auto const &value_tmp(gen(expr->value, fn_arity, true)); + auto const &value_tmp(gen(expr->value, fn_arity)); /* We static_cast to object_ref here, since we'll be trying to catch an object_ref in any * try/catch forms. This loses us our type info, but C++ doesn't do implicit conversions * when catching and we're not using inheritance. */ util::format_to(body_buffer, "throw static_cast({});", value_tmp.unwrap().str(true)); - return none; + + if(expr->position == analyze::expression_position::tail) + { + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); + } + + return "jank::runtime::jank_nil()"; } - jtl::option processor::gen(analyze::expr::try_ref const expr, - analyze::expr::function_arity const &fn_arity, - bool const box_needed) + jtl::option + processor::gen(analyze::expr::try_ref const expr, analyze::expr::function_arity const &fn_arity) { auto const has_catch{ expr->catch_body.is_some() }; - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("try"))); - util::format_to(body_buffer, "object_ref {}{ };", ret_tmp); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("try"))); + util::format_to(body_buffer, "jank::runtime::object_ref {}{ };", ret_tmp); util::format_to(body_buffer, "{"); if(expr->finally_body.is_some()) { util::format_to(body_buffer, "jank::util::scope_exit const finally{ [&](){ "); - gen(expr->finally_body.unwrap(), fn_arity, box_needed); + gen(expr->finally_body.unwrap(), fn_arity); util::format_to(body_buffer, "} };"); } if(has_catch) { util::format_to(body_buffer, "try {"); - auto const &body_tmp(gen(expr->body, fn_arity, box_needed)); + auto const &body_tmp(gen(expr->body, fn_arity)); if(body_tmp.is_some()) { - util::format_to(body_buffer, "{} = {};", ret_tmp, body_tmp.unwrap().str(box_needed)); + util::format_to(body_buffer, "{} = {};", ret_tmp, body_tmp.unwrap().str(true)); } if(expr->position == analyze::expression_position::tail) { @@ -1590,20 +1751,20 @@ namespace jank::codegen util::format_to(body_buffer, "}"); /* There's a gotcha here, tied to how we throw exceptions. We're catching an object_ref, which - * means we need to be throwing an object_ref. Since we're not using inheritance, we can't - * rely on a catch-all and C++ doesn't do implicit conversions into catch types. So, if we - * throw a persistent_string_ref, for example, it will not be caught as an object_ref. - * - * We mitigate this by ensuring during the codegen for throw that we type-erase to - * an object_ref. - */ + * means we need to be throwing an object_ref. Since we're not using inheritance, we can't + * rely on a catch-all and C++ doesn't do implicit conversions into catch types. So, if we + * throw a persistent_string_ref, for example, it will not be caught as an object_ref. + * + * We mitigate this by ensuring during the codegen for throw that we type-erase to + * an object_ref. + */ util::format_to(body_buffer, "catch(jank::runtime::object_ref const {}) {", runtime::munge(expr->catch_body.unwrap().sym->name)); - auto const &catch_tmp(gen(expr->catch_body.unwrap().body, fn_arity, box_needed)); + auto const &catch_tmp(gen(expr->catch_body.unwrap().body, fn_arity)); if(catch_tmp.is_some()) { - util::format_to(body_buffer, "{} = {};", ret_tmp, catch_tmp.unwrap().str(box_needed)); + util::format_to(body_buffer, "{} = {};", ret_tmp, catch_tmp.unwrap().str(true)); } if(expr->position == analyze::expression_position::tail) { @@ -1613,10 +1774,10 @@ namespace jank::codegen } else { - auto const &body_tmp(gen(expr->body, fn_arity, box_needed)); + auto const &body_tmp(gen(expr->body, fn_arity)); if(body_tmp.is_some()) { - util::format_to(body_buffer, "{} = {};", ret_tmp, body_tmp.unwrap().str(box_needed)); + util::format_to(body_buffer, "{} = {};", ret_tmp, body_tmp.unwrap().str(true)); } if(expr->position == analyze::expression_position::tail) { @@ -1630,33 +1791,73 @@ namespace jank::codegen } jtl::option - processor::gen(analyze::expr::case_ref const, analyze::expr::function_arity const &, bool) + processor::gen(analyze::expr::case_ref const expr, analyze::expr::function_arity const &fn_arity) { - return none; + auto const is_tail{ expr->position == analyze::expression_position::tail }; + auto const &ret_tmp{ runtime::munge(__rt_ctx->unique_string("case")) }; + + util::format_to(body_buffer, "jank::runtime::object_ref {}{ };", ret_tmp); + + auto const &value_tmp{ gen(expr->value_expr, fn_arity) }; + + util::format_to(body_buffer, + "switch(jank_shift_mask_case_integer({}.get(), {}, {})) {", + value_tmp.unwrap().str(true), + expr->shift, + expr->mask); + + jank_debug_assert(expr->keys.size() == expr->exprs.size()); + for(usize i{}; i < expr->keys.size(); ++i) + { + util::format_to(body_buffer, "case {}: {", expr->keys[i]); + + auto const &case_tmp{ gen(expr->exprs[i], fn_arity) }; + if(!is_tail) + { + util::format_to(body_buffer, "{} = {};", ret_tmp, case_tmp.unwrap().str(true)); + } + util::format_to(body_buffer, "break; }"); + } + + util::format_to(body_buffer, "default: {"); + + auto const &default_tmp{ gen(expr->default_expr, fn_arity) }; + if(!is_tail) + { + util::format_to(body_buffer, "{} = {};", ret_tmp, default_tmp.unwrap().str(true)); + } + + util::format_to(body_buffer, "} }"); + + if(is_tail) + { + util::format_to(body_buffer, "return {};", ret_tmp); + return none; + } + + return ret_tmp; } - jtl::option - processor::gen(expr::cpp_raw_ref const expr, expr::function_arity const &, bool) + jtl::option processor::gen(expr::cpp_raw_ref const expr, expr::function_arity const &) { - util::format_to(deps_buffer, "{}", expr->code); + util::format_to(cpp_raw_buffer, "\n{}\n", expr->code); if(expr->position == analyze::expression_position::tail) { - util::format_to(body_buffer, "return jank::runtime::jank_nil;"); + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); return none; } return none; } jtl::option - processor::gen(analyze::expr::cpp_type_ref const, analyze::expr::function_arity const &, bool) + processor::gen(analyze::expr::cpp_type_ref const, analyze::expr::function_arity const &) { throw std::runtime_error{ "cpp_type has no codegen" }; } - jtl::option processor::gen(analyze::expr::cpp_value_ref const expr, - analyze::expr::function_arity const &, - bool) + jtl::option + processor::gen(analyze::expr::cpp_value_ref const expr, analyze::expr::function_arity const &) { if(expr->val_kind == expr::cpp_value::value_kind::null) { @@ -1690,18 +1891,43 @@ namespace jank::codegen return tmp; } - jtl::option processor::gen(analyze::expr::cpp_cast_ref const expr, - analyze::expr::function_arity const &arity, - bool const box_needed) + jtl::option + processor::gen(analyze::expr::cpp_cast_ref const expr, analyze::expr::function_arity const &arity) { - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("cpp_cast"))); - auto const value_tmp{ gen(expr->value_expr, arity, box_needed) }; + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("cpp_cast"))); + auto const value_tmp{ gen(expr->value_expr, arity) }; + + /* There's no need to do a conversion for void, since we always just + * want nil. There's no need for generating a tmp for it either, since + * we have a global nil constant. */ + if(Cpp::IsVoid(expr->conversion_type)) + { + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); + return none; + } + return "jank::runtime::jank_nil()"; + } + + /* We can rely on the C++ type system to handle conversion from typed objects + * to untype objects. */ + if(cpp_util::is_untyped_object(expr->type) && cpp_util::is_any_object(expr->conversion_type)) + { + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return {};", value_tmp.unwrap().str(true)); + return none; + } + return value_tmp.unwrap().str(true); + } util::format_to( body_buffer, "auto const {}{ jank::runtime::convert<{}>::{}({}) };", ret_tmp, - Cpp::GetTypeAsString(expr->conversion_type), + cpp_util::get_qualified_type_name(Cpp::GetCanonicalType( + Cpp::GetTypeWithoutCv(Cpp::GetNonReferenceType(expr->conversion_type)))), (expr->policy == conversion_policy::into_object ? "into_object" : "from_object"), value_tmp.unwrap().str(true)); @@ -1711,29 +1937,107 @@ namespace jank::codegen return none; } - return ret_tmp; - } + return ret_tmp; + } + + jtl::option + processor::gen(analyze::expr::cpp_call_ref const expr, analyze::expr::function_arity const &arity) + { + if((target == compilation_target::module || target == compilation_target::function) + && !expr->function_code.empty()) + { + util::format_to(cpp_raw_buffer, "\n{}\n", expr->function_code); + } + + if(expr->source_expr->kind == expression_kind::cpp_value) + { + auto const source{ static_cast(expr->source_expr.data) }; + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("cpp_call"))); + + native_vector arg_tmps; + arg_tmps.reserve(expr->arg_exprs.size()); + for(auto const &arg_expr : expr->arg_exprs) + { + arg_tmps.emplace_back(gen(arg_expr, arity).unwrap()); + } + + auto const is_void{ Cpp::IsVoid(Cpp::GetFunctionReturnType(source->scope)) }; + + if(is_void) + { + util::format_to(body_buffer, "jank::runtime::object_ref const {};", ret_tmp); + } + else + { + util::format_to(body_buffer, "auto &&{}{ ", ret_tmp); + } + + util::format_to(body_buffer, "{}(", Cpp::GetQualifiedCompleteName(source->scope)); + + bool need_comma{}; + for(usize arg_idx{}; arg_idx < expr->arg_exprs.size(); ++arg_idx) + { + auto const arg_expr{ expr->arg_exprs[arg_idx] }; + auto const arg_type{ cpp_util::expression_type(arg_expr) }; + auto const param_type{ Cpp::GetFunctionArgType(source->scope, arg_idx) }; + auto const &arg_tmp{ arg_tmps[arg_idx] }; + + if(need_comma) + { + util::format_to(body_buffer, ", "); + } + util::format_to(body_buffer, "{}", arg_tmp.str(true)); + if(param_type && Cpp::IsPointerType(param_type) && cpp_util::is_any_object(arg_type)) + { + util::format_to(body_buffer, ".get()"); + } + need_comma = true; + } + + util::format_to(body_buffer, ")"); + + if(!is_void) + { + util::format_to(body_buffer, "};"); + } + else + { + util::format_to(body_buffer, ";"); + } + + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return {};", ret_tmp); + return none; + } - jtl::option processor::gen(analyze::expr::cpp_call_ref const expr, - analyze::expr::function_arity const &arity, - bool const) - { - if(expr->source_expr->kind == expression_kind::cpp_value) + return ret_tmp; + } + else { - auto const source{ static_cast(expr->source_expr.data) }; - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("cpp_call"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("cpp_call"))); + + auto const source_tmp{ gen(expr->source_expr, arity).unwrap() }; native_vector arg_tmps; arg_tmps.reserve(expr->arg_exprs.size()); for(auto const &arg_expr : expr->arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, arity, false).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, arity).unwrap()); } - util::format_to(body_buffer, - "auto const {}{ {}(", - ret_tmp, - Cpp::GetQualifiedCompleteName(source->scope)); + auto const is_void{ Cpp::IsVoid(expr->type) }; + + if(is_void) + { + util::format_to(body_buffer, "jank::runtime::object_ref const {};", ret_tmp); + } + else + { + util::format_to(body_buffer, "auto &&{}{ ", ret_tmp); + } + + util::format_to(body_buffer, "{}(", source_tmp.str(true)); bool need_comma{}; for(auto const &arg_tmp : arg_tmps) @@ -1742,11 +2046,20 @@ namespace jank::codegen { util::format_to(body_buffer, ", "); } - util::format_to(body_buffer, "{}", arg_tmp.str(false)); + util::format_to(body_buffer, "{}", arg_tmp.str(true)); need_comma = true; } - util::format_to(body_buffer, ") };"); + util::format_to(body_buffer, ")"); + + if(!is_void) + { + util::format_to(body_buffer, "};"); + } + else + { + util::format_to(body_buffer, ";"); + } if(expr->position == expression_position::tail) { @@ -1756,46 +2069,84 @@ namespace jank::codegen return ret_tmp; } - else - { - jank_debug_assert(false); - return none; - } } jtl::option processor::gen(analyze::expr::cpp_constructor_call_ref const expr, - analyze::expr::function_arity const &arity, - bool const) + analyze::expr::function_arity const &arity) { - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("cpp_ctor"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("cpp_ctor"))); native_vector arg_tmps; arg_tmps.reserve(expr->arg_exprs.size()); for(auto const &arg_expr : expr->arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, arity, false).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, arity).unwrap()); } if(expr->arg_exprs.empty()) { - util::format_to(body_buffer, "{} {}{ };", Cpp::GetTypeAsString(expr->type), ret_tmp); + util::format_to(body_buffer, + "{} {}{ };", + cpp_util::get_qualified_type_name(expr->type), + ret_tmp); return ret_tmp; } - util::format_to(body_buffer, "{} {}( ", Cpp::GetTypeAsString(expr->type), ret_tmp); + util::format_to(body_buffer, "{} {}{ ", cpp_util::get_qualified_type_name(expr->type), ret_tmp); - bool need_comma{}; - for(auto const &arg_tmp : arg_tmps) + if(!expr->arg_exprs.empty()) { - if(need_comma) + auto const arg_type{ cpp_util::expression_type(expr->arg_exprs[0]) }; + bool needs_conversion{}; + jtl::immutable_string conversion_type; + if(cpp_util::is_any_object(expr->type) && !cpp_util::is_any_object(arg_type)) { - util::format_to(body_buffer, ", "); + needs_conversion = true; + conversion_type = "into_object"; + } + else if(!cpp_util::is_any_object(expr->type) && cpp_util::is_any_object(arg_type)) + { + needs_conversion = true; + conversion_type = "from_object"; + } + + if(needs_conversion) + { + util::format_to(body_buffer, + "jank::runtime::convert<{}>::{}({}.get())", + cpp_util::get_qualified_type_name(expr->type), + conversion_type, + arg_tmps[0].str(false)); + } + else + { + auto const needs_static_cast{ expr->type != arg_type && expr->arg_exprs.size() == 1 }; + if(needs_static_cast) + { + util::format_to(body_buffer, + "static_cast<{}>(", + cpp_util::get_qualified_type_name(expr->type)); + } + + bool need_comma{}; + for(auto const &arg_tmp : arg_tmps) + { + if(need_comma) + { + util::format_to(body_buffer, ", "); + } + util::format_to(body_buffer, "{}", arg_tmp.str(false)); + need_comma = true; + } + + if(needs_static_cast) + { + util::format_to(body_buffer, ")"); + } } - util::format_to(body_buffer, "{}", arg_tmp.str(false)); - need_comma = true; } - util::format_to(body_buffer, " );"); + util::format_to(body_buffer, " };"); if(expr->position == expression_position::tail) { @@ -1806,26 +2157,40 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::cpp_member_call_ref const expr, - analyze::expr::function_arity const &arity, - bool) + analyze::expr::function_arity const &arity) { auto const fn_name{ Cpp::GetName(expr->fn) }; - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string(fn_name))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string(fn_name))); native_vector arg_tmps; arg_tmps.reserve(expr->arg_exprs.size()); for(auto const &arg_expr : expr->arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, arity, false).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, arity).unwrap()); } - util::format_to( - body_buffer, - "auto &&{}{ {}{}{}(", - ret_tmp, - arg_tmps[0].str(false), - (Cpp::IsPointerType(cpp_util::expression_type(expr->arg_exprs[0])) ? "->" : "."), - fn_name); + auto const is_void{ Cpp::IsVoid(Cpp::GetFunctionReturnType(expr->fn)) }; + + if(is_void) + { + util::format_to(body_buffer, "jank::runtime::object_ref {}{ };", ret_tmp); + util::format_to( + body_buffer, + "{}{}{}(", + arg_tmps[0].str(false), + (Cpp::IsPointerType(cpp_util::expression_type(expr->arg_exprs[0])) ? "->" : "."), + fn_name); + } + else + { + util::format_to( + body_buffer, + "auto &&{}{ {}{}{}(", + ret_tmp, + arg_tmps[0].str(false), + (Cpp::IsPointerType(cpp_util::expression_type(expr->arg_exprs[0])) ? "->" : "."), + fn_name); + } bool need_comma{}; for(auto it{ arg_tmps.begin() + 1 }; it != arg_tmps.end(); ++it) @@ -1838,7 +2203,14 @@ namespace jank::codegen need_comma = true; } - util::format_to(body_buffer, ") };"); + if(is_void) + { + util::format_to(body_buffer, ");"); + } + else + { + util::format_to(body_buffer, ") };"); + } if(expr->position == expression_position::tail) { @@ -1850,11 +2222,10 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::cpp_member_access_ref const expr, - analyze::expr::function_arity const &arity, - bool) + analyze::expr::function_arity const &arity) { - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string(expr->name))); - auto obj_tmp(gen(expr->obj_expr, arity, false)); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string(expr->name))); + auto obj_tmp(gen(expr->obj_expr, arity)); util::format_to(body_buffer, "auto &&{}{ {}{}{} };", @@ -1873,33 +2244,38 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::cpp_builtin_operator_call_ref const expr, - analyze::expr::function_arity const &arity, - bool) + analyze::expr::function_arity const &arity) { - auto ret_tmp(runtime::munge(__rt_ctx->unique_namespaced_string("cpp_operator"))); + auto ret_tmp(runtime::munge(__rt_ctx->unique_string("cpp_operator"))); native_vector arg_tmps; arg_tmps.reserve(expr->arg_exprs.size()); for(auto const &arg_expr : expr->arg_exprs) { - arg_tmps.emplace_back(gen(arg_expr, arity, false).unwrap()); + arg_tmps.emplace_back(gen(arg_expr, arity).unwrap()); } + auto const op_name{ cpp_util::operator_name(static_cast(expr->op)).unwrap() }; + if(expr->arg_exprs.size() == 1) + { + util::format_to(body_buffer, "auto &&{}( {}{} );", ret_tmp, op_name, arg_tmps[0].str(false)); + } + else if(op_name == "aget") { util::format_to(body_buffer, - "auto {}( {}{} );", + "auto &&{}( {}[{}] );", ret_tmp, - cpp_util::operator_name(static_cast(expr->op)).unwrap(), - arg_tmps[0].str(false)); + arg_tmps[0].str(false), + arg_tmps[1].str(false)); } else { util::format_to(body_buffer, - "auto {}( {} {} {} );", + "auto &&{}( {} {} {} );", ret_tmp, arg_tmps[0].str(false), - cpp_util::operator_name(static_cast(expr->op)).unwrap(), + op_name, arg_tmps[1].str(false)); } @@ -1912,17 +2288,27 @@ namespace jank::codegen return ret_tmp; } - jtl::option processor::gen(analyze::expr::cpp_box_ref const expr, - analyze::expr::function_arity const &arity, - bool) + jtl::option + processor::gen(analyze::expr::cpp_box_ref const expr, analyze::expr::function_arity const &arity) { - auto ret_tmp{ runtime::munge(__rt_ctx->unique_namespaced_string("cpp_box")) }; - auto value_tmp{ gen(expr->value_expr, arity, false) }; + auto ret_tmp{ runtime::munge(__rt_ctx->unique_string("cpp_box")) }; + auto value_tmp{ gen(expr->value_expr, arity) }; + auto const value_expr_type{ cpp_util::expression_type(expr->value_expr) }; + auto const type_str{ Cpp::GetTypeAsString( + Cpp::GetCanonicalType(Cpp::GetNonReferenceType(value_expr_type))) }; + + util::format_to( + body_buffer, + "auto {}{ jank::runtime::make_box({}, \"{}\") };\n", + ret_tmp, + value_tmp.unwrap().str(false), + type_str); + auto const meta{ runtime::source_to_meta(expr->source) }; util::format_to(body_buffer, - "auto {}{ jank::runtime::make_box({}) };", + "jank::runtime::reset_meta({}, jank::runtime::__rt_ctx->read_string(\"{}\"));", ret_tmp, - value_tmp.unwrap().str(false)); + util::escape(runtime::to_code_string(meta))); if(expr->position == expression_position::tail) { @@ -1934,18 +2320,60 @@ namespace jank::codegen } jtl::option processor::gen(analyze::expr::cpp_unbox_ref const expr, - analyze::expr::function_arity const &arity, - bool) + analyze::expr::function_arity const &arity) + { + auto ret_tmp{ runtime::munge(__rt_ctx->unique_string("cpp_unbox")) }; + auto value_tmp{ gen(expr->value_expr, arity) }; + auto const type_name{ cpp_util::get_qualified_type_name(expr->type) }; + auto const meta{ detail::lift_constant(lifted_constants, + runtime::source_to_meta(expr->source)) }; + + util::format_to(body_buffer, + "auto {}{ " + "static_cast<{}>(jank_unbox_with_source(\"{}\", {}.data, {}.data)) };", + ret_tmp, + type_name, + type_name, + value_tmp.unwrap().str(false), + meta); + + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return {};", ret_tmp); + return none; + } + + return ret_tmp; + } + + jtl::option + processor::gen(analyze::expr::cpp_new_ref const expr, analyze::expr::function_arity const &arity) { - auto ret_tmp{ runtime::munge(__rt_ctx->unique_namespaced_string("cpp_unbox")) }; - auto value_tmp{ gen(expr->value_expr, arity, false) }; + auto ret_tmp{ runtime::munge(__rt_ctx->unique_string("cpp_new")) }; + auto finalizer_tmp{ runtime::munge(__rt_ctx->unique_string("finalizer")) }; + auto value_tmp{ gen(expr->value_expr, arity) }; + auto const type_name{ cpp_util::get_qualified_type_name(expr->type) }; + auto const needs_finalizer{ !Cpp::IsTriviallyDestructible(expr->type) }; + + if(needs_finalizer) + { + util::format_to(body_buffer, + "using T = {};\n" + "static auto const {}{ " + "[](void * const obj, void *){" + "reinterpret_cast(obj)->~T();" + "} };", + type_name, + finalizer_tmp); + } util::format_to(body_buffer, "auto {}{ " - "static_cast<{}>(jank::runtime::try_object({})-" - ">data.data) };", + "new (GC{}) {}{ {} }" + " };", ret_tmp, - Cpp::GetTypeAsString(expr->type), + (needs_finalizer ? ", " + finalizer_tmp : ""), + type_name, value_tmp.unwrap().str(false)); if(expr->position == expression_position::tail) @@ -1957,38 +2385,90 @@ namespace jank::codegen return ret_tmp; } + jtl::option processor::gen(analyze::expr::cpp_delete_ref const expr, + analyze::expr::function_arity const &arity) + { + auto value_tmp{ gen(expr->value_expr, arity).unwrap() }; + auto const value_type{ Cpp::GetPointeeType(cpp_util::expression_type(expr->value_expr)) }; + auto const type_name{ cpp_util::get_qualified_type_name(value_type) }; + auto const needs_finalizer{ !Cpp::IsTriviallyDestructible(value_type) }; + + /* Calling GC_free won't trigger the finalizer. Not sure why, but it's explicitly + * documented in bdwgc. So, we'll invoke it manually if needed, prior to GC_free. */ + if(needs_finalizer) + { + util::format_to(body_buffer, + "using T = {};\n" + "{}->~T();", + type_name, + value_tmp.str(false)); + } + + util::format_to(body_buffer, "GC_free({});", value_tmp.str(false)); + + if(expr->position == expression_position::tail) + { + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); + return none; + } + + return "jank::runtime::jank_nil()"; + } + jtl::immutable_string processor::declaration_str() { if(!generated_declaration) { - build_header(); + profile::timer const timer{ util::format("cpp gen {}", root_fn->name) }; + + /* Module targeting works in a special way, with the goal of + * cutting down the generated code size. Instead of each function + * having its own lifted vars/constants, we have one namespace for + * the module with the lifted globals there, at namespace level. + * Then every function within that module can share the same globals. + * This also makes creating functions cheaper. However, it requires + * some special tracking. */ + if(target == compilation_target::module) + { + util::format_to(module_header_buffer, + "namespace {} {", + runtime::module::module_to_native_ns(module)); + } + + + /* We generate the body first so that we know what we need for the header. This is + * necessary since we end up lifting vars and constants while building the body. */ build_body(); + build_header(); build_footer(); + + if(target == compilation_target::module) + { + /* Namespace. */ + util::format_to(module_footer_buffer, "}"); + } + generated_declaration = true; } native_transient_string ret; - ret.reserve(deps_buffer.size() + header_buffer.size() + body_buffer.size() + ret.reserve(cpp_raw_buffer.size() + module_header_buffer.size() + module_footer_buffer.size() + + deps_buffer.size() + header_buffer.size() + body_buffer.size() + footer_buffer.size()); + ret += jtl::immutable_string_view{ cpp_raw_buffer.data(), cpp_raw_buffer.size() }; + ret += jtl::immutable_string_view{ module_header_buffer.data(), module_header_buffer.size() }; ret += jtl::immutable_string_view{ deps_buffer.data(), deps_buffer.size() }; + ret += jtl::immutable_string_view{ module_footer_buffer.data(), module_footer_buffer.size() }; ret += jtl::immutable_string_view{ header_buffer.data(), header_buffer.size() }; ret += jtl::immutable_string_view{ body_buffer.data(), body_buffer.size() }; ret += jtl::immutable_string_view{ footer_buffer.data(), footer_buffer.size() }; - //ret = util::format_cpp_source(ret).expect_ok(); - - //util::println("codegen declaration {}", ret); return ret; } void processor::build_header() { - /* TODO: We don't want this for nested modules, but we do if they're in their own file. - * Do we need three module compilation targets? Top-level, nested, local? - * - * Local fns are within a struct already, so we can't enter the ns again. */ - //if(!runtime::module::is_nested_module(module)) - //if(target == compilation_target::module) + if(target != compilation_target::function) { util::format_to(header_buffer, "namespace {} {", @@ -2000,80 +2480,68 @@ namespace jank::codegen struct {} : jank::runtime::obj::jit_function { )", - runtime::munge(struct_name.name)); + struct_name); { - /* TODO: Constants and vars are not shared across arities. We'd need stable names. */ - native_set used_vars, used_constants, used_captures; + native_set used_captures; for(auto const &arity : root_fn->arities) { - for(auto const &v : arity.frame->lifted_vars) + /* TODO: More useful types here. */ + for(auto const &v : arity.frame->captures) { - if(used_vars.contains(v.second.native_name.to_hash())) + auto const hash{ v.first->to_hash() }; + if(used_captures.contains(hash)) { continue; } - used_vars.emplace(v.second.native_name.to_hash()); + used_captures.emplace(hash); + /* Captures aren't const since they could be late-assigned, in the case of a letfn. */ util::format_to(header_buffer, - "jank::runtime::var_ref const {};", + "jank::runtime::object_ref {};", runtime::munge(v.second.native_name)); } + } - for(auto const &v : arity.frame->lifted_constants) - { - if(used_constants.contains(v.second.native_name.to_hash())) - { - continue; - } - used_constants.emplace(v.second.native_name.to_hash()); - - util::format_to(header_buffer, - "{} const {};", - detail::gen_constant_type(v.second.data, true), - runtime::munge(v.second.native_name)); + auto &lifted_buffer{ (target == compilation_target::module) ? module_header_buffer + : header_buffer }; + auto const lifted_const{ (target == compilation_target::module) ? "" : "const" }; - if(v.second.unboxed_native_name.is_some()) - { - util::format_to(header_buffer, - "static constexpr {} const {}{ ", - detail::gen_constant_type(v.second.data, false), - runtime::munge(v.second.unboxed_native_name.unwrap())); - detail::gen_constant(v.second.data, header_buffer, false); - util::format_to(header_buffer, "};"); - } - } + for(auto const &v : lifted_vars) + { + util::format_to(lifted_buffer, + "jank::runtime::var_ref {} {};", + lifted_const, + v.second.native_name); + } - /* TODO: More useful types here. */ - for(auto const &v : arity.frame->captures) - { - if(used_captures.contains(v.first->to_hash())) - { - continue; - } - used_captures.emplace(v.first->to_hash()); - util::format_to(header_buffer, - "jank::runtime::object_ref const {};", - runtime::munge(v.second.native_name)); - } + for(auto const &v : lifted_constants) + { + /* TODO: Typed lifted constants (in analysis). */ + util::format_to(lifted_buffer, + "{} {} {};", + detail::gen_constant_type(v.first, true), + lifted_const, + v.second); } } { - native_set used_captures; - util::format_to(header_buffer, "{}(", runtime::munge(struct_name.name)); + native_set used_captures; + util::format_to(header_buffer, "{}(", struct_name); bool need_comma{}; for(auto const &arity : root_fn->arities) { for(auto const &v : arity.frame->captures) { - if(used_captures.contains(v.first->to_hash())) + auto const hash{ v.first->to_hash() }; + if(used_captures.contains(hash)) { continue; } - used_captures.emplace(v.first->to_hash()); + used_captures.emplace(hash); /* TODO: More useful types here. */ util::format_to(header_buffer, @@ -2086,7 +2554,7 @@ namespace jank::codegen } { - native_set used_vars, used_constants, used_captures; + native_set used_captures; util::format_to(header_buffer, ") : jank::runtime::obj::jit_function{ "); /* TODO: All of the meta in clojure.core alone costs 2s to JIT compile at run-time. * How can this be faster? */ @@ -2095,44 +2563,47 @@ namespace jank::codegen for(auto const &arity : root_fn->arities) { - for(auto const &v : arity.frame->lifted_vars) + for(auto const &v : arity.frame->captures) { - if(used_vars.contains(v.second.native_name.to_hash())) + auto const hash{ v.first->to_hash() }; + if(used_captures.contains(hash)) { continue; } - used_vars.emplace(v.second.native_name.to_hash()); + used_captures.emplace(hash); - util::format_to(header_buffer, - R"(, {}{ jank::runtime::__rt_ctx->intern_var("{}", "{}").expect_ok() })", - runtime::munge(v.second.native_name), - v.second.var_name->ns, - v.second.var_name->name); + auto const name{ runtime::munge(v.second.native_name) }; + util::format_to(header_buffer, ", {}{ {} }", name, name); } + } - for(auto const &v : arity.frame->lifted_constants) + if(target == compilation_target::eval) + { + for(auto const &v : lifted_vars) { - if(used_constants.contains(v.second.native_name.to_hash())) + if(v.second.owned) { - continue; + util::format_to( + header_buffer, + R"(, {}{ jank::runtime::__rt_ctx->intern_owned_var("{}").expect_ok() })", + v.second.native_name, + v.first); } - used_constants.emplace(v.second.native_name.to_hash()); - - util::format_to(header_buffer, ", {}{", runtime::munge(v.second.native_name)); - detail::gen_constant(v.second.data, header_buffer, true); - util::format_to(header_buffer, "}"); - } - - for(auto const &v : arity.frame->captures) - { - if(used_captures.contains(v.first->to_hash())) + else { - continue; + util::format_to(header_buffer, + R"(, {}{ jank::runtime::__rt_ctx->intern_var("{}").expect_ok() })", + v.second.native_name, + v.first); } - used_captures.emplace(v.first->to_hash()); + } - auto const name{ runtime::munge(v.second.native_name) }; - util::format_to(header_buffer, ", {}{ {} }", name, name); + + for(auto const &v : lifted_constants) + { + util::format_to(header_buffer, ", {}{", v.second); + detail::gen_constant(v.first, header_buffer, true); + util::format_to(header_buffer, "}"); } } } @@ -2142,6 +2613,11 @@ namespace jank::codegen void processor::build_body() { + if(!body_buffer.empty()) + { + return; + } + analyze::expr::function_arity const *variadic_arity{}; analyze::expr::function_arity const *highest_fixed_arity{}; for(auto const &arity : root_fn->arities) @@ -2157,7 +2633,7 @@ namespace jank::codegen } jtl::immutable_string recur_suffix; - if(arity.fn_ctx->is_tail_recursive) + if(arity.fn_ctx->is_recur_recursive) { recur_suffix = detail::recur_suffix; } @@ -2176,21 +2652,18 @@ namespace jank::codegen param_shadows_fn |= param->name == root_fn->name; } - util::format_to(body_buffer, - R"( - ) final { - using namespace jank; - using namespace jank::runtime; - )"); + util::format_to(body_buffer, ") final {"); //util::format_to(body_buffer, "jank::profile::timer __timer{ \"{}\" };", root_fn->name); - if(!param_shadows_fn) + if(!param_shadows_fn && arity.fn_ctx->is_named_recursive) { - util::format_to(body_buffer, "object_ref const {}{ this };", runtime::munge(root_fn->name)); + util::format_to(body_buffer, + "jank::runtime::object_ref const {}{ this };", + runtime::munge(root_fn->name)); } - if(arity.fn_ctx->is_tail_recursive) + if(arity.fn_ctx->is_recur_recursive) { util::format_to(body_buffer, "{"); @@ -2209,15 +2682,15 @@ namespace jank::codegen for(auto const &form : arity.body->values) { - gen(form, arity, true); + gen(form, arity); } if(arity.body->values.empty()) { - util::format_to(body_buffer, "return jank::runtime::jank_nil;"); + util::format_to(body_buffer, "return jank::runtime::jank_nil();"); } - if(arity.fn_ctx->is_tail_recursive) + if(arity.fn_ctx->is_recur_recursive) { util::format_to(body_buffer, "} }"); } @@ -2233,8 +2706,8 @@ namespace jank::codegen util::format_to(body_buffer, R"( - jank::runtime::behavior::callable::arity_flag_t get_arity_flags() const final - { return jank::runtime::behavior::callable::build_arity_flags({}, true, {}); } + callable::arity_flag_t get_arity_flags() const final + { return callable::build_arity_flags({}, true, {}); } )", variadic_arity->fn_ctx->param_count - 1, variadic_ambiguous); @@ -2247,8 +2720,7 @@ namespace jank::codegen util::format_to(footer_buffer, "};"); /* Namespace. */ - //if(!runtime::module::is_nested_module(module)) - //if(target == compilation_target::module) + if(target != compilation_target::function) { util::format_to(footer_buffer, "}"); } @@ -2256,38 +2728,84 @@ namespace jank::codegen if(target == compilation_target::module) { util::format_to(footer_buffer, - "extern \"C\" void* {}(){", + "extern \"C\" void {}(){", runtime::module::module_to_load_function(module)); + + auto const ns{ runtime::module::module_to_native_ns(module) }; + + /* First thing we do when loading this module is to intern our ns. Everything else will + * build on that. */ + util::format_to(footer_buffer, "jank_ns_intern_c(\"{}\");", module); + + /* This dance is performed to keep symbol names unique across all the modules. + * Considering LLVM JIT symbols to be global, we need to define them with + * unique names to avoid conflicts during JIT recompilation/reloading. + * + * The approach, right now, is for each namespace, we will keep a counter + * and will increase it every time we define a new symbol. When we JIT reload + * the same namespace again, we will define new symbols. + * + * This IR codegen for calling `jank_ns_set_symbol_counter`, is to set the counter + * on an initial load. + */ + auto const current_ns{ __rt_ctx->current_ns() }; util::format_to(footer_buffer, - "return {}::{}{ }.call().erase();", - runtime::module::module_to_native_ns(module), - runtime::munge(struct_name.name)); + "jank_ns_set_symbol_counter(\"{}\", {});", + current_ns->name->get_name(), + current_ns->symbol_counter.load()); + + for(auto const &v : lifted_vars) + { + /* Since global ctors don't run when loading object files, we + * need to manually initialize these. We use placement new to + * properly run ctors, just like what would happen normally. */ + if(v.second.owned) + { + util::format_to( + footer_buffer, + R"(new (&{}::{}) jank::runtime::var_ref(jank::runtime::__rt_ctx->intern_owned_var("{}").expect_ok());)", + ns, + v.second.native_name, + v.first); + } + else + { + util::format_to( + footer_buffer, + R"(new (&{}::{}) jank::runtime::var_ref(jank::runtime::__rt_ctx->intern_var("{}").expect_ok());)", + ns, + v.second.native_name, + v.first); + } + } + + + for(auto const &v : lifted_constants) + { + util::format_to(footer_buffer, + "new (&{}::{}) {}(", + ns, + v.second, + detail::gen_constant_type(v.first, true)); + detail::gen_constant(v.first, footer_buffer, true); + util::format_to(footer_buffer, ");"); + } + + util::format_to(footer_buffer, "{}::{}{ }.call();", ns, struct_name); + util::format_to(footer_buffer, "}"); } } - jtl::immutable_string processor::expression_str(bool const box_needed) + jtl::immutable_string processor::expression_str() { auto const module_ns(runtime::module::module_to_native_ns(module)); if(!generated_expression) { - jtl::immutable_string close = ")"; - if(box_needed) - { - util::format_to( - expression_buffer, - "jank::runtime::make_box<{}>(", - runtime::module::nest_native_ns(module_ns, runtime::munge(struct_name.name))); - } - else - { - util::format_to( - expression_buffer, - "{}{ ", - runtime::module::nest_native_ns(module_ns, runtime::munge(struct_name.name))); - close = "}"; - } + util::format_to(expression_buffer, + "jank::runtime::make_box<{}>(", + runtime::module::nest_native_ns(module_ns, struct_name)); native_set used_captures; bool need_comma{}; @@ -2319,70 +2837,31 @@ namespace jank::codegen { auto const originating_local(root_fn->frame->find_local_or_capture(v.first)); handle const h{ originating_local.unwrap().binding }; - util::format_to(expression_buffer, - "{} {}", - (need_comma ? "," : ""), - h.str(true), - originating_local.unwrap().binding->name->to_code_string(), - originating_local.unwrap().binding->native_name); + auto const local_type{ originating_local.unwrap().binding->type }; + auto const needs_conversion{ !cpp_util::is_any_object(local_type) }; + + if(needs_conversion) + { + util::format_to(expression_buffer, + "{} jank::runtime::convert<{}>::{}({})", + (need_comma ? "," : ""), + cpp_util::get_qualified_type_name(local_type), + "into_object", + h.str(true)); + } + else + { + util::format_to(expression_buffer, "{} {}", (need_comma ? "," : ""), h.str(true)); + } } need_comma = true; } } - util::format_to(expression_buffer, "{}", close); + util::format_to(expression_buffer, ")"); generated_expression = true; } return { expression_buffer.data(), expression_buffer.size() }; } - - /* TODO: Not sure if we want any of this. The module dependency loading feels wrong, - * since it should be tied to calls to require instead. */ - jtl::immutable_string processor::module_init_str(jtl::immutable_string const &module) - { - jtl::string_builder module_buffer; - - util::format_to(module_buffer, "namespace {} {", runtime::module::module_to_native_ns(module)); - - util::format_to(module_buffer, - R"( - struct __ns__init - { - )"); - - util::format_to(module_buffer, "static void __init(){"); - //util::format_to(module_buffer, "jank::profile::timer __timer{ \"ns __init\" };"); - util::format_to(module_buffer, - "constexpr auto const deps(jank::util::make_array("); - bool needs_comma{}; - for(auto const &dep : __rt_ctx->module_dependencies[module]) - { - if(needs_comma) - { - util::format_to(module_buffer, ", "); - } - util::format_to(module_buffer, "\"/{}\"", dep); - needs_comma = true; - } - util::format_to(module_buffer, "));"); - - util::format_to(module_buffer, "for(auto const &dep : deps){"); - util::format_to(module_buffer, "jank::runtime::__rt_ctx->load_module(dep).expect_ok();"); - util::format_to(module_buffer, "}"); - - /* __init fn */ - util::format_to(module_buffer, "}"); - - /* Struct */ - util::format_to(module_buffer, "};"); - - /* Namespace */ - util::format_to(module_buffer, "}"); - - native_transient_string ret; - ret.reserve(module_buffer.size()); - ret += jtl::immutable_string_view{ module_buffer.data(), module_buffer.size() }; - return ret; - } } diff --git a/compiler+runtime/src/cpp/jank/compiler_native.cpp b/compiler+runtime/src/cpp/jank/compiler_native.cpp index 0f8bcbfbe..c0ee4680d 100644 --- a/compiler+runtime/src/cpp/jank/compiler_native.cpp +++ b/compiler+runtime/src/cpp/jank/compiler_native.cpp @@ -46,11 +46,11 @@ namespace jank::compiler_native util::println("{}\n", util::format_cpp_source(cg_prc.declaration_str()).expect_ok()); } - return jank_nil; + return jank_nil(); } } -extern "C" jank_object_ref jank_load_jank_compiler_native() +extern "C" void jank_load_jank_compiler_native() { using namespace jank; using namespace jank::runtime; @@ -65,6 +65,4 @@ extern "C" jank_object_ref jank_load_jank_compiler_native() make_box(obj::symbol{ __rt_ctx->current_ns()->to_string(), name }.to_string()))))); }); intern_fn("native-source", &compiler_native::native_source); - - return jank_nil.erase(); } diff --git a/compiler+runtime/src/cpp/jank/environment/check_health.cpp b/compiler+runtime/src/cpp/jank/environment/check_health.cpp index 6f2cbe44a..1bd126e8e 100644 --- a/compiler+runtime/src/cpp/jank/environment/check_health.cpp +++ b/compiler+runtime/src/cpp/jank/environment/check_health.cpp @@ -25,7 +25,7 @@ #include #ifdef JANK_PHASE_2 -extern "C" jank_object_ref jank_load_clojure_core(); +extern "C" void jank_load_clojure_core(); #endif namespace jank::environment @@ -322,6 +322,8 @@ namespace jank::environment terminal_style::reset); } + /* This is disabled until IR gen supports ref counting OR we switch back to using a GC. */ + [[maybe_unused]] static jtl::immutable_string check_ir_jit() { bool error{}; @@ -384,6 +386,7 @@ namespace jank::environment auto const saved_opts{ util::cli::opts }; util::cli::opts.target_module = "health"; + util::cli::opts.output_target = util::cli::compilation_target::object; util::cli::opts.output_filename = exe_output; util::cli::opts.module_path = path_tmp; util::scope_exit const finally{ /* NOLINTNEXTLINE(bugprone-exception-escape) */ @@ -400,7 +403,7 @@ namespace jank::environment runtime::__rt_ctx->compile_module(util::cli::opts.target_module).expect_ok(); jank::aot::processor const aot_prc{}; - aot_prc.compile(util::cli::opts.target_module).expect_ok(); + aot_prc.build_executable(util::cli::opts.target_module).expect_ok(); auto const stdout_file{ std::filesystem::path{ path_tmp } / "stdout" }; auto const proc_code{ llvm::sys::ExecuteAndWait( @@ -500,7 +503,7 @@ namespace jank::environment terminal_style::reset); util::println("{}", pch_location()); util::println("{}", check_cpp_jit()); - util::println("{}", check_ir_jit()); + //util::println("{}", check_ir_jit()); util::println("{}", check_aot()); util::println(""); diff --git a/compiler+runtime/src/cpp/jank/error.cpp b/compiler+runtime/src/cpp/jank/error.cpp index 732e4d384..ab54ddba8 100644 --- a/compiler+runtime/src/cpp/jank/error.cpp +++ b/compiler+runtime/src/cpp/jank/error.cpp @@ -184,6 +184,8 @@ namespace jank::error return "Invalid C++ delete."; case kind::analyze_invalid_cpp_member_access: return "Invalid C++ member access."; + case kind::analyze_known_issue: + return "Known issue."; case kind::internal_analyze_failure: return "Internal analysis failure."; @@ -449,11 +451,11 @@ namespace jank::error * begin with. In that case, we update the existing note rather than adding a new one. */ jtl::ref base::add_usage(read::source const &usage_source) { - if(usage_source == read::source::unknown || usage_source.overlaps(source)) + if(usage_source == read::source::unknown() || usage_source.overlaps(source)) { return this; } - else if(source == read::source::unknown) + else if(source == read::source::unknown()) { source = usage_source; notes[0].source = usage_source; @@ -469,4 +471,16 @@ namespace jank::error { return os << "error(" << kind_str(e.kind) << " - " << e.source << ", \"" << e.message << "\")"; } + + error_ref internal_failure(jtl::immutable_string const &message) + { + auto const e{ make_error(kind::internal_failure, message, read::source::unknown()) }; + e->trace = std::make_unique(cpptrace::generate_trace()); + return e; + } + + void throw_internal_failure(jtl::immutable_string const &message) + { + throw internal_failure(message); + } } diff --git a/compiler+runtime/src/cpp/jank/error/analyze.cpp b/compiler+runtime/src/cpp/jank/error/analyze.cpp index 53c0ae82c..2d04d1d02 100644 --- a/compiler+runtime/src/cpp/jank/error/analyze.cpp +++ b/compiler+runtime/src/cpp/jank/error/analyze.cpp @@ -153,7 +153,7 @@ namespace jank::error note &&extra, runtime::object_ref const expansion) { - return make_error(kind::analyze_invalid_try, message, source, std::move(extra), expansion); + return make_error(kind::analyze_invalid_try, message, source, jtl::move(extra), expansion); } error_ref analyze_unresolved_var(jtl::immutable_string const &message, @@ -224,33 +224,33 @@ namespace jank::error error_ref analyze_invalid_conversion(jtl::immutable_string const &message) { - return make_error(kind::analyze_invalid_conversion, message, read::source::unknown); + return make_error(kind::analyze_invalid_conversion, message, read::source::unknown()); } error_ref analyze_invalid_cpp_operator_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_operator_call, message, source, expansion); } error_ref analyze_invalid_cpp_constructor_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_constructor_call, message, source, expansion); } error_ref analyze_invalid_cpp_member_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_member_call, message, source, expansion); } error_ref analyze_invalid_cpp_capture(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_capture, message, @@ -261,113 +261,120 @@ namespace jank::error error_ref analyze_mismatched_if_types(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_mismatched_if_types, message, source, expansion); } error_ref analyze_invalid_cpp_function_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_function_call, message, source, expansion); } error_ref analyze_invalid_cpp_call(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_call, message, source, expansion); } error_ref analyze_invalid_cpp_conversion(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_conversion, message, source, expansion); } error_ref analyze_invalid_cpp_symbol(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_symbol, message, source, expansion); } error_ref analyze_unresolved_cpp_symbol(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_unresolved_cpp_symbol, message, source, expansion); } error_ref analyze_invalid_cpp_raw(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_raw, message, source, expansion); } error_ref analyze_invalid_cpp_type(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_type, message, source, expansion); } error_ref analyze_invalid_cpp_value(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_value, message, source, expansion); } error_ref analyze_invalid_cpp_cast(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_cast, message, source, expansion); } error_ref analyze_invalid_cpp_box(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_box, message, source, expansion); } error_ref analyze_invalid_cpp_unbox(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_unbox, message, source, expansion); } error_ref analyze_invalid_cpp_new(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_new, message, source, expansion); } error_ref analyze_invalid_cpp_delete(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_delete, message, source, expansion); } error_ref analyze_invalid_cpp_member_access(jtl::immutable_string const &message, read::source const &source, - runtime::object_ref expansion) + runtime::object_ref const expansion) { return make_error(kind::analyze_invalid_cpp_member_access, message, source, expansion); } + error_ref analyze_known_issue(jtl::immutable_string const &message, + read::source const &source, + runtime::object_ref const expansion) + { + return make_error(kind::analyze_known_issue, message, source, expansion); + } + error_ref internal_analyze_failure(jtl::immutable_string const &message, runtime::object_ref const expansion) { - return make_error(kind::internal_analyze_failure, message, read::source::unknown, expansion); + return make_error(kind::internal_analyze_failure, message, read::source::unknown(), expansion); } error_ref internal_analyze_failure(jtl::immutable_string const &message, diff --git a/compiler+runtime/src/cpp/jank/error/aot.cpp b/compiler+runtime/src/cpp/jank/error/aot.cpp index d06a468d5..754faf169 100644 --- a/compiler+runtime/src/cpp/jank/error/aot.cpp +++ b/compiler+runtime/src/cpp/jank/error/aot.cpp @@ -6,16 +6,16 @@ namespace jank::error { error_ref aot_unresolved_main(jtl::immutable_string const &message) { - return make_error(kind::aot_unresolved_main, message, read::source::unknown); + return make_error(kind::aot_unresolved_main, message, read::source::unknown()); } error_ref aot_compilation_failure() { - return make_error(kind::aot_compilation_failure, read::source::unknown); + return make_error(kind::aot_compilation_failure, read::source::unknown()); } error_ref internal_aot_failure(jtl::immutable_string const &message) { - return make_error(kind::internal_aot_failure, message, read::source::unknown); + return make_error(kind::internal_aot_failure, message, read::source::unknown()); } } diff --git a/compiler+runtime/src/cpp/jank/error/codegen.cpp b/compiler+runtime/src/cpp/jank/error/codegen.cpp index 19d89eacc..2cb851c63 100644 --- a/compiler+runtime/src/cpp/jank/error/codegen.cpp +++ b/compiler+runtime/src/cpp/jank/error/codegen.cpp @@ -4,6 +4,6 @@ namespace jank::error { error_ref internal_codegen_failure(jtl::immutable_string const &message) { - return make_error(kind::internal_codegen_failure, message, read::source::unknown); + return make_error(kind::internal_codegen_failure, message, read::source::unknown()); } } diff --git a/compiler+runtime/src/cpp/jank/error/parse.cpp b/compiler+runtime/src/cpp/jank/error/parse.cpp index 9caa39708..f022b822f 100644 --- a/compiler+runtime/src/cpp/jank/error/parse.cpp +++ b/compiler+runtime/src/cpp/jank/error/parse.cpp @@ -269,6 +269,6 @@ namespace jank::error error_ref internal_parse_failure(jtl::immutable_string const &message) { - return make_error(kind::internal_parse_failure, message, read::source::unknown); + return make_error(kind::internal_parse_failure, message, read::source::unknown()); } } diff --git a/compiler+runtime/src/cpp/jank/error/report.cpp b/compiler+runtime/src/cpp/jank/error/report.cpp index a75d74538..b34b8707b 100644 --- a/compiler+runtime/src/cpp/jank/error/report.cpp +++ b/compiler+runtime/src/cpp/jank/error/report.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include #include @@ -354,7 +356,7 @@ namespace jank::error void plan::add(read::source const &body_source, note const &n) { - if(n.source == read::source::unknown) + if(n.source == read::source::unknown()) { return; } @@ -592,4 +594,13 @@ namespace jank::error report(e->cause.as_ref()); } } + + void warn(jtl::immutable_string const &msg) + { + util::println(stderr, + "{}warning:{} {}", + jtl::terminal_style::yellow, + jtl::terminal_style::reset, + msg); + } } diff --git a/compiler+runtime/src/cpp/jank/error/runtime.cpp b/compiler+runtime/src/cpp/jank/error/runtime.cpp index f84a5327f..4898dbdff 100644 --- a/compiler+runtime/src/cpp/jank/error/runtime.cpp +++ b/compiler+runtime/src/cpp/jank/error/runtime.cpp @@ -6,32 +6,39 @@ namespace jank::error { error_ref runtime_module_not_found(jtl::immutable_string const &message) { - return make_error(kind::runtime_module_not_found, message, read::source::unknown); + return make_error(kind::runtime_module_not_found, message, read::source::unknown()); } error_ref runtime_module_binary_without_source(jtl::immutable_string const &message) { - return make_error(kind::runtime_module_binary_without_source, message, read::source::unknown); + return make_error(kind::runtime_module_binary_without_source, message, read::source::unknown()); } error_ref runtime_unable_to_open_file(jtl::immutable_string const &message) { - return make_error(kind::runtime_unable_to_open_file, message, read::source::unknown); + return make_error(kind::runtime_unable_to_open_file, message, read::source::unknown()); } error_ref runtime_invalid_cpp_eval() { - return make_error(kind::runtime_invalid_cpp_eval, read::source::unknown); + return make_error(kind::runtime_invalid_cpp_eval, read::source::unknown()); } error_ref runtime_unable_to_load_module(jtl::immutable_string const &message) { - return make_error(kind::runtime_unable_to_load_module, message, read::source::unknown); + return make_error(kind::runtime_unable_to_load_module, message, read::source::unknown()); + } + + error_ref runtime_unable_to_load_module(error_ref const cause) + { + auto const e{ make_error(kind::runtime_unable_to_load_module, read::source::unknown()) }; + e->cause = cause; + return e; } error_ref internal_runtime_failure(jtl::immutable_string const &message) { - return make_error(kind::internal_runtime_failure, message, read::source::unknown); + return make_error(kind::internal_runtime_failure, message, read::source::unknown()); } error_ref diff --git a/compiler+runtime/src/cpp/jank/error/system.cpp b/compiler+runtime/src/cpp/jank/error/system.cpp index 5564690bd..780d4621a 100644 --- a/compiler+runtime/src/cpp/jank/error/system.cpp +++ b/compiler+runtime/src/cpp/jank/error/system.cpp @@ -5,11 +5,11 @@ namespace jank::error { error_ref system_clang_executable_not_found() { - return make_error(kind::system_clang_executable_not_found, read::source::unknown); + return make_error(kind::system_clang_executable_not_found, read::source::unknown()); } error_ref system_failure(jtl::immutable_string const &message) { - return make_error(kind::system_failure, message, read::source::unknown); + return make_error(kind::system_failure, message, read::source::unknown()); } } diff --git a/compiler+runtime/src/cpp/jank/evaluate.cpp b/compiler+runtime/src/cpp/jank/evaluate.cpp index cfe9c7b9c..ba79af473 100644 --- a/compiler+runtime/src/cpp/jank/evaluate.cpp +++ b/compiler+runtime/src/cpp/jank/evaluate.cpp @@ -20,7 +20,6 @@ #include #include #include -#include namespace jank::evaluate { @@ -130,12 +129,7 @@ namespace jank::evaluate } /* Some expressions don't make sense to eval outright and aren't fns that can be JIT compiled. - * For those, we wrap them in a fn expression and then JIT compile and call them. - * - * There's an oddity here, since that expr wouldn't've been analyzed within a fn frame, so - * its lifted vars/constants, for example, aren't in a fn frame. Instead, they're put in the - * root frame. So, when wrapping this expr, we give the fn the root frame, but change its - * type to a fn frame. */ + * For those, we wrap them in a fn expression and then JIT compile and call them. */ template static expr::function_ref wrap_expression(jtl::ref const orig_expr, jtl::immutable_string const &name, @@ -148,8 +142,6 @@ namespace jank::evaluate ret->unique_name = __rt_ctx->unique_namespaced_string(ret->name); ret->meta = obj::persistent_hash_map::empty(); - auto const &closest_fn_frame(local_frame::find_closest_fn_frame(*expr->frame)); - auto const frame{ jtl::make_ref(local_frame::frame_type::fn, expr->frame->parent) }; auto const fn_ctx{ jtl::make_ref() }; @@ -159,18 +151,14 @@ namespace jank::evaluate fn_ctx }; expr->frame->parent = arity.frame; ret->frame = arity.frame->parent.unwrap_or(arity.frame); - ret->frame->lift_constant(ret->meta); fn_ctx->name = ret->name; fn_ctx->unique_name = ret->unique_name; fn_ctx->fn = ret; arity.frame->fn_ctx = fn_ctx; arity.fn_ctx = fn_ctx; - arity.frame->lifted_vars = closest_fn_frame.lifted_vars; - arity.frame->lifted_constants = closest_fn_frame.lifted_constants; - arity.fn_ctx->param_count = arity.params.size(); - for(auto const sym : arity.params) + for(auto const &sym : arity.params) { arity.frame->locals.emplace(sym, local_binding{ sym, sym->name, none, arity.frame }); } @@ -226,7 +214,7 @@ namespace jank::evaluate return wrap_expression(jtl::make_ref(expression_position::tail, an_prc.root_frame, true, - jank_nil), + jank_nil()), name, {}); } @@ -267,7 +255,8 @@ namespace jank::evaluate object_ref eval(expression_ref const ex) { - profile::timer const timer{ "eval ast node" }; + profile::timer const timer{ util::format("eval ast node {}", + analyze::expression_kind_str(ex->kind)) }; object_ref ret{}; visit_expr([&ret](auto const typed_ex) { ret = eval(typed_ex); }, ex); return ret; @@ -278,7 +267,7 @@ namespace jank::evaluate auto var(__rt_ctx->intern_var(expr->name).expect_ok()); var->meta = expr->name->meta; - auto const meta(var->meta.unwrap_or(jank_nil)); + auto const meta(var->meta.unwrap_or(jank_nil())); auto const dynamic(get(meta, __rt_ctx->intern_keyword("dynamic").expect_ok())); var->set_dynamic(truthy(dynamic)); @@ -580,6 +569,7 @@ namespace jank::evaluate object_ref eval(expr::function_ref const expr) { + profile::timer const timer{ util::format("eval jit function {}", expr->name) }; auto const &module( module::nest_module(expect_object(__rt_ctx->current_ns_var->deref())->to_string(), munge(expr->unique_name))); @@ -605,20 +595,20 @@ namespace jank::evaluate else { codegen::processor cg_prc{ expr, module, codegen::compilation_target::eval }; - util::println("{}\n", util::format_cpp_source(cg_prc.declaration_str()).expect_ok()); - __rt_ctx->jit_prc.eval_string(cg_prc.declaration_str()); - auto const expr_str{ cg_prc.expression_str(true) + ".erase()" }; - clang::Value v; - auto res( - __rt_ctx->jit_prc.interpreter->ParseAndExecute({ expr_str.data(), expr_str.size() }, &v)); - if(res) + + /* TODO: Rename to something generic which makes sense for IR and C++ gen? */ + jtl::immutable_string_view const print_settings{ getenv("JANK_PRINT_IR") ?: "" }; + if(print_settings == "1") { - /* TODO: Helper to turn an llvm::Error into a string. */ - jtl::immutable_string const msg{ "Unable to compile/eval C++ source." }; - llvm::logAllUnhandledErrors(jtl::move(res), llvm::errs(), "error: "); - throw error::internal_codegen_failure(msg); + util::println("{}\n", util::format_cpp_source(cg_prc.declaration_str()).expect_ok()); } - return try_object(v.convertTo()); + + __rt_ctx->jit_prc.eval_string(cg_prc.declaration_str()); + auto const expr_str{ cg_prc.expression_str() + ".erase().data" }; + clang::Value v; + __rt_ctx->jit_prc.eval_string({ expr_str.data(), expr_str.size() }, &v); + auto ret{ try_object(v.convertTo()) }; + return ret; } } @@ -642,7 +632,7 @@ namespace jank::evaluate object_ref eval(expr::do_ref const expr) { - object_ref ret{ jank_nil }; + object_ref ret{ jank_nil() }; for(auto const &form : expr->values) { ret = eval(form); @@ -671,7 +661,7 @@ namespace jank::evaluate { return eval(expr->else_.unwrap()); } - return jank_nil; + return jank_nil(); } object_ref eval(expr::throw_ref const expr) @@ -716,7 +706,8 @@ namespace jank::evaluate object_ref eval(expr::cpp_raw_ref const expr) { - return dynamic_call(eval(wrap_expression(expr, "cpp_raw", {}))); + __rt_ctx->jit_prc.eval_string(expr->code); + return runtime::jank_nil(); } object_ref eval(expr::cpp_type_ref const) diff --git a/compiler+runtime/src/cpp/jank/jit/processor.cpp b/compiler+runtime/src/cpp/jank/jit/processor.cpp index fa5a992a0..98468c6e3 100644 --- a/compiler+runtime/src/cpp/jank/jit/processor.cpp +++ b/compiler+runtime/src/cpp/jank/jit/processor.cpp @@ -21,16 +21,18 @@ #include #include #include +#include #include #include #include +#include namespace jank::jit { static jtl::immutable_string default_shared_lib_name(jtl::immutable_string const &lib) #if defined(__APPLE__) { - return util::format("{}.dylib", lib); + return util::format("lib{}.dylib", lib); } #elif defined(__linux__) { @@ -165,6 +167,9 @@ namespace jank::jit args.emplace_back("-include-pch"); args.emplace_back(strdup(pch_path_str.c_str())); + args.emplace_back("-w"); + args.emplace_back("-Wno-c++11-narrowing"); + util::add_system_flags(args); /********* Every flag after this line is user-provided. *********/ @@ -239,12 +244,23 @@ namespace jank::jit } void processor::eval_string(jtl::immutable_string const &s) const + { + eval_string(s, nullptr); + } + + void processor::eval_string(jtl::immutable_string const &s, clang::Value * const ret) const { profile::timer const timer{ "jit eval_string" }; - //util::println("// eval_string:\n{}\n", s); - auto err(interpreter->ParseAndExecute({ s.data(), s.size() })); - /* TODO: Throw on errors. */ - llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), "error: "); + auto const &formatted{ s }; + /* TODO: There is some sort of immutable_string or result bug here. */ + //auto const &formatted{ util::format_cpp_source(s).expect_ok() }; + //util::println("// eval_string:\n{}\n", formatted); + auto err(interpreter->ParseAndExecute({ formatted.data(), formatted.size() }, ret)); + if(err) + { + llvm::logAllUnhandledErrors(jtl::move(err), llvm::errs(), "error: "); + throw error::internal_codegen_failure("Unable to compile C++ source."); + } register_jit_stack_frames(); } diff --git a/compiler+runtime/src/cpp/jank/perf_native.cpp b/compiler+runtime/src/cpp/jank/perf_native.cpp index 6ec170a8a..e7772652e 100644 --- a/compiler+runtime/src/cpp/jank/perf_native.cpp +++ b/compiler+runtime/src/cpp/jank/perf_native.cpp @@ -8,7 +8,7 @@ #include #include -jank_object_ref jank_load_jank_perf_native() +extern "C" void jank_load_jank_perf_native() { using namespace jank; using namespace jank::runtime; @@ -23,6 +23,4 @@ jank_object_ref jank_load_jank_perf_native() make_box(obj::symbol{ __rt_ctx->current_ns()->to_string(), name }.to_string()))))); }); intern_fn("benchmark", &perf::benchmark); - - return jank_nil.erase(); } diff --git a/compiler+runtime/src/cpp/jank/read/lex.cpp b/compiler+runtime/src/cpp/jank/read/lex.cpp index 17962c9cd..4391c9354 100644 --- a/compiler+runtime/src/cpp/jank/read/lex.cpp +++ b/compiler+runtime/src/cpp/jank/read/lex.cpp @@ -1081,7 +1081,7 @@ namespace jank::read::lex return error::lex_invalid_number( util::format( "Characters '{}' are invalid for a base {} number.", - jtl::immutable_string_view{ invalid_digits.begin(), invalid_digits.end() }, + jtl::immutable_string_view{ invalid_digits.data(), invalid_digits.size() }, radix), { token_start, pos }); } diff --git a/compiler+runtime/src/cpp/jank/read/parse.cpp b/compiler+runtime/src/cpp/jank/read/parse.cpp index a0419dfce..d4be79809 100644 --- a/compiler+runtime/src/cpp/jank/read/parse.cpp +++ b/compiler+runtime/src/cpp/jank/read/parse.cpp @@ -409,7 +409,7 @@ namespace jank::read::parse parsed_keys.insert({ key.ptr, key }); - if constexpr(std::same_as) + if constexpr(jtl::is_same) { map.insert_or_assign(key.ptr, value.unwrap().ptr); } @@ -435,7 +435,7 @@ namespace jank::read::parse return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(map)), + jtl::move(map)), start_token, latest_token }; } @@ -453,7 +453,7 @@ namespace jank::read::parse return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(map)), + jtl::move(map)), start_token, latest_token }; } @@ -537,8 +537,8 @@ namespace jank::read::parse auto meta_result(visit_object( [&](auto const typed_val) -> processor::object_result { - using T = typename decltype(typed_val)::value_type; - if constexpr(std::same_as) + using T = typename jtl::decay_t::value_type; + if constexpr(jtl::is_same) { return object_source_info{ obj::persistent_array_map::create_unique(typed_val, jank_true), start_token, @@ -578,7 +578,7 @@ namespace jank::read::parse return visit_object( [&](auto const typed_val) -> processor::object_result { - using T = typename decltype(typed_val)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { if(typed_val->meta.is_none()) @@ -689,7 +689,7 @@ namespace jank::read::parse expected_closer = prev_expected_closer; return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(ret).persistent()), + jtl::move(ret).persistent()), start_token, latest_token }; } @@ -1157,7 +1157,7 @@ namespace jank::read::parse quoted_item.expect_ok())); } } - auto const vec(make_box(ret.persistent())->seq()); + auto vec(make_box(ret.persistent())->seq()); return vec; }, []() -> jtl::result { @@ -1181,7 +1181,7 @@ namespace jank::read::parse ret.push_back(first(item)); ret.push_back(second(item)); } - auto const vec(make_box(ret.persistent())->seq()); + auto vec(make_box(ret.persistent())->seq()); return vec; }, []() -> jtl::result { @@ -1226,7 +1226,7 @@ namespace jank::read::parse quoted_item.expect_ok())); } } - auto const vec(make_box(ret.persistent())->seq()); + auto vec(make_box(ret.persistent())->seq()); return vec; }, []() -> jtl::result { @@ -1275,7 +1275,7 @@ namespace jank::read::parse auto gensym(get(env, sym)); if(gensym->type == object_type::nil) { - gensym = make_box(__rt_ctx->unique_symbol(sym->name)); + gensym = __rt_ctx->unique_symbol(sym->name); __rt_ctx->gensym_env_var->set(assoc(env, sym, gensym)).expect_ok(); } sym = expect_object(gensym); @@ -1318,9 +1318,9 @@ namespace jank::read::parse * reassemble them. */ auto const res{ visit_seqable( [&](auto const typed_form) -> jtl::result { - using T = typename decltype(typed_form)::value_type; + using T = typename jtl::decay_t::value_type; - if constexpr(std::same_as) + if constexpr(jtl::is_same) { auto const seq(typed_form->seq()); if(seq.is_nil()) @@ -1435,7 +1435,7 @@ namespace jank::read::parse } auto const meta{ runtime::meta(form) }; - if(meta != jank_nil) + if(meta != jank_nil()) { /* We quote the meta as well, to ensure it doesn't get evaluated. * Note that Clojure removes the source info from the meta here. We're keeping it @@ -1542,7 +1542,7 @@ namespace jank::read::parse processor::object_result processor::parse_nil() { ++token_current; - return object_source_info{ jank_nil, latest_token, latest_token }; + return object_source_info{ jank_nil(), latest_token, latest_token }; } processor::object_result processor::parse_boolean() diff --git a/compiler+runtime/src/cpp/jank/read/reparse.cpp b/compiler+runtime/src/cpp/jank/read/reparse.cpp index 6f0c0eb68..9c28dd06c 100644 --- a/compiler+runtime/src/cpp/jank/read/reparse.cpp +++ b/compiler+runtime/src/cpp/jank/read/reparse.cpp @@ -65,7 +65,7 @@ namespace jank::read::parse source reparse_nth(obj::persistent_list_ref const o, usize const n) { auto source(object_source(o)); - if(source == source::unknown) + if(source == source::unknown()) { return source; } @@ -76,7 +76,7 @@ namespace jank::read::parse }; if(res.is_err()) { - return source::unknown; + return source::unknown(); } return res.expect_ok(); } @@ -84,7 +84,7 @@ namespace jank::read::parse source reparse_nth(runtime::obj::persistent_vector_ref const o, usize const n) { auto source(object_source(o)); - if(source == source::unknown) + if(source == source::unknown()) { return source; } @@ -95,7 +95,7 @@ namespace jank::read::parse }; if(res.is_err()) { - return source::unknown; + return source::unknown(); } return res.expect_ok(); } @@ -108,7 +108,7 @@ namespace jank::read::parse * but this will be fine for now. */ return visit_seqable( [](auto const typed_o, usize const n) -> source { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as || std::same_as) diff --git a/compiler+runtime/src/cpp/jank/read/source.cpp b/compiler+runtime/src/cpp/jank/read/source.cpp index a6ad207fe..b4457208a 100644 --- a/compiler+runtime/src/cpp/jank/read/source.cpp +++ b/compiler+runtime/src/cpp/jank/read/source.cpp @@ -4,11 +4,18 @@ namespace jank::read { - source_position const source_position::unknown{ 0, 0, 0 }; - source const source::unknown{ no_source_path, - no_source_path, - source_position::unknown, - source_position::unknown }; + source_position source_position::unknown() + { + return { 0, 0, 0 }; + } + + source source::unknown() + { + return { no_source_path, + no_source_path, + source_position::unknown(), + source_position::unknown() }; + } source::source(source_position const &start) : source{ start, start } diff --git a/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp b/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp index 6261eb0cf..3c5cc78a8 100644 --- a/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp @@ -24,7 +24,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -33,7 +33,7 @@ namespace jank::runtime switch(arity_flags) { case callable::mask_variadic_arity(0): - return typed_source->call(jank_nil); + return typed_source->call(jank_nil()); default: return typed_source->call(); } @@ -52,7 +52,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -66,7 +66,7 @@ namespace jank::runtime case callable::mask_variadic_arity(1): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, jank_nil); + return typed_source->call(a1, jank_nil()); } default: return typed_source->call(a1); @@ -96,7 +96,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -112,7 +112,7 @@ namespace jank::runtime case callable::mask_variadic_arity(2): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, jank_nil); + return typed_source->call(a1, a2, jank_nil()); } default: return typed_source->call(a1, a2); @@ -142,7 +142,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -160,7 +160,7 @@ namespace jank::runtime case callable::mask_variadic_arity(3): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, jank_nil); + return typed_source->call(a1, a2, a3, jank_nil()); } default: return typed_source->call(a1, a2, a3); @@ -184,7 +184,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -204,7 +204,7 @@ namespace jank::runtime case callable::mask_variadic_arity(4): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, jank_nil); + return typed_source->call(a1, a2, a3, a4, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4); @@ -229,7 +229,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -251,7 +251,7 @@ namespace jank::runtime case callable::mask_variadic_arity(5): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, a5, jank_nil); + return typed_source->call(a1, a2, a3, a4, a5, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4, a5); @@ -277,7 +277,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -313,7 +313,7 @@ namespace jank::runtime case callable::mask_variadic_arity(6): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, a5, a6, jank_nil); + return typed_source->call(a1, a2, a3, a4, a5, a6, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4, a5, a6); @@ -340,7 +340,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -380,7 +380,7 @@ namespace jank::runtime case callable::mask_variadic_arity(7): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, a5, a6, a7, jank_nil); + return typed_source->call(a1, a2, a3, a4, a5, a6, a7, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4, a5, a6, a7); @@ -408,7 +408,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -452,7 +452,7 @@ namespace jank::runtime case callable::mask_variadic_arity(8): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8, jank_nil); + return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8); @@ -481,7 +481,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -526,7 +526,7 @@ namespace jank::runtime case callable::mask_variadic_arity(9): if(!callable::is_variadic_ambiguous(arity_flags)) { - return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8, a9, jank_nil); + return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8, a9, jank_nil()); } default: return typed_source->call(a1, a2, a3, a4, a5, a6, a7, a8, a9); @@ -556,7 +556,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -679,7 +679,7 @@ namespace jank::runtime auto const processed_source(pass_through_vars(source)); return visit_object( [=](auto const typed_source) -> object_ref { - using T = typename decltype(typed_source)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(function_like || std::is_base_of_v) { @@ -975,83 +975,92 @@ namespace jank::runtime throw invalid_arity<0>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref) + object_ref callable::call(object_ref const) { throw invalid_arity<1>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, object_ref) + object_ref callable::call(object_ref const, object_ref const) { throw invalid_arity<2>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, object_ref, object_ref) + object_ref callable::call(object_ref const, object_ref const, object_ref const) { throw invalid_arity<3>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, object_ref, object_ref, object_ref) + object_ref + callable::call(object_ref const, object_ref const, object_ref const, object_ref const) { throw invalid_arity<4>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, object_ref, object_ref, object_ref, object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<5>{ runtime::to_code_string(this_object_ref()) }; } - object_ref - callable::call(object_ref, object_ref, object_ref, object_ref, object_ref, object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<6>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<7>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<8>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<9>{ runtime::to_code_string(this_object_ref()) }; } - object_ref callable::call(object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref, - object_ref) + object_ref callable::call(object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const, + object_ref const) { throw invalid_arity<10>{ runtime::to_code_string(this_object_ref()) }; } diff --git a/compiler+runtime/src/cpp/jank/runtime/behavior/metadatable.cpp b/compiler+runtime/src/cpp/jank/runtime/behavior/metadatable.cpp index 6599d78c3..65c8ca205 100644 --- a/compiler+runtime/src/cpp/jank/runtime/behavior/metadatable.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/behavior/metadatable.cpp @@ -8,7 +8,7 @@ namespace jank::runtime::behavior::detail { object_ref validate_meta(object_ref const m) { - if(!is_map(m) && m != jank_nil) + if(!is_map(m) && m.is_some()) { throw std::runtime_error{ util::format("invalid meta: {}", runtime::to_string(m)) }; } diff --git a/compiler+runtime/src/cpp/jank/runtime/context.cpp b/compiler+runtime/src/cpp/jank/runtime/context.cpp index e99e9df91..bd36ab730 100644 --- a/compiler+runtime/src/cpp/jank/runtime/context.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/context.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -94,12 +95,7 @@ namespace jank::runtime .expect_ok(); } - context::~context() - { - thread_binding_frames.erase(this); - } - - obj::symbol_ref context::qualify_symbol(obj::symbol_ref const &sym) const + obj::symbol_ref context::qualify_symbol(obj::symbol_ref const sym) const { obj::symbol_ref qualified_sym{ sym }; if(qualified_sym->ns.empty()) @@ -110,7 +106,7 @@ namespace jank::runtime return qualified_sym; } - var_ref context::find_var(obj::symbol_ref const &sym) + var_ref context::find_var(obj::symbol_ref const sym) { profile::timer const timer{ "rt find_var" }; if(!sym->ns.empty()) @@ -140,7 +136,7 @@ namespace jank::runtime return find_var(make_box(ns, name)); } - jtl::option context::find_local(obj::symbol_ref const &) + jtl::option context::find_local(obj::symbol_ref const) { return none; } @@ -159,14 +155,14 @@ namespace jank::runtime return eval_string(file.expect_ok().view()); } - jtl::option context::eval_string(jtl::immutable_string_view const &code) + jtl::option context::eval_string(jtl::immutable_string const &code) { profile::timer const timer{ "rt eval_string" }; read::lex::processor l_prc{ code }; read::parse::processor p_prc{ l_prc.begin(), l_prc.end() }; bool no_op{ true }; - object_ref ret{ jank_nil }; + object_ref ret{ jank_nil() }; native_vector forms{}; for(auto const &form : p_prc) { @@ -198,11 +194,17 @@ namespace jank::runtime * targeted at AOT and doesn't have access to what's loaded in the JIT runtime. */ if(truthy(compile_files_var->deref())) { + profile::timer const timer{ "rt compile-module" }; auto const &module(runtime::to_string(current_module_var->deref())); auto const name{ module::module_to_load_function(module) }; + if(forms.empty()) + { + forms.emplace_back(jank_nil()); + } + auto const form{ runtime::conj( - runtime::conj(runtime::conj(make_box(std::move(forms)), + runtime::conj(runtime::conj(make_box(jtl::move(forms)), obj::persistent_vector::empty()), make_box(name)), make_box("fn*")) }; @@ -216,13 +218,22 @@ namespace jank::runtime codegen::llvm_processor const cg_prc{ fn, module, codegen::compilation_target::module }; cg_prc.gen().expect_ok(); cg_prc.optimize(); - write_module(cg_prc.get_module_name(), cg_prc.get_module().getModuleUnlocked()).expect_ok(); + write_module(cg_prc.get_module_name(), "", cg_prc.get_module().getModuleUnlocked()) + .expect_ok(); } else { + profile::timer const timer{ "rt compile-module parse + write" }; codegen::processor cg_prc{ fn, module, codegen::compilation_target::module }; //util::println("{}\n", util::format_cpp_source(cg_prc.declaration_str()).expect_ok()); auto const code{ cg_prc.declaration_str() }; + auto module_name{ runtime::to_string(current_module_var->deref()) }; + //aot::processor const aot_prc; + //auto const res{ aot_prc.compile_object(module_name, code) }; + //if(res.is_err()) + //{ + // throw res.expect_err(); + //} auto parse_res{ jit_prc.interpreter->Parse({ code.data(), code.size() }) }; if(!parse_res) { @@ -232,16 +243,15 @@ namespace jank::runtime throw error::internal_codegen_failure(res); } auto &partial_tu{ parse_res.get() }; - auto module_name{ runtime::to_string(current_module_var->deref()) }; - write_module(module_name, partial_tu.TheModule.get()).expect_ok(); + //auto module_name{ runtime::to_string(current_module_var->deref()) }; + write_module(module_name, code, partial_tu.TheModule.get()).expect_ok(); } } return ret; } - jtl::result - context::eval_cpp_string(jtl::immutable_string_view const &code) const + jtl::result context::eval_cpp_string(jtl::immutable_string const &code) const { profile::timer const timer{ "rt eval_cpp_string" }; @@ -259,7 +269,7 @@ namespace jank::runtime if(truthy(compile_files_var->deref())) { auto module_name{ runtime::to_string(current_module_var->deref()) }; - write_module(module_name, partial_tu.TheModule.get()).expect_ok(); + write_module(module_name, code, partial_tu.TheModule.get()).expect_ok(); } auto exec_res(jit_prc.interpreter->Execute(partial_tu)); @@ -271,19 +281,19 @@ namespace jank::runtime return ok(); } - object_ref context::read_string(jtl::immutable_string_view const &code) + object_ref context::read_string(jtl::immutable_string const &code) { profile::timer const timer{ "rt read_string" }; /* When reading an arbitrary string, we don't want the last *current-file* to * be set as source file, so we need to bind it to nil. */ binding_scope const preserve{ obj::persistent_hash_map::create_unique( - std::make_pair(current_file_var, jank_nil)) }; + std::make_pair(current_file_var, jank_nil())) }; read::lex::processor l_prc{ code }; read::parse::processor p_prc{ l_prc.begin(), l_prc.end() }; - object_ref ret{ jank_nil }; + object_ref ret{ jank_nil() }; for(auto const &form : p_prc) { ret = form.expect_ok().unwrap().ptr; @@ -293,7 +303,7 @@ namespace jank::runtime } native_vector - context::analyze_string(jtl::immutable_string_view const &code, bool const eval) + context::analyze_string(jtl::immutable_string const &code, bool const eval) { profile::timer const timer{ "rt analyze_string" }; read::lex::processor l_prc{ code }; @@ -323,7 +333,7 @@ namespace jank::runtime } jtl::result - context::load_module(jtl::immutable_string_view const &module, module::origin const ori) + context::load_module(jtl::immutable_string const &module, module::origin const ori) { auto const ns(current_ns()); @@ -354,13 +364,17 @@ namespace jank::runtime { return error::runtime_unable_to_load_module(e.what()); } - catch(object_ref const &e) + catch(object_ref const e) { return error::runtime_unable_to_load_module(runtime::to_code_string(e)); } + catch(error_ref const e) + { + return e; + } } - jtl::result context::compile_module(jtl::immutable_string_view const &module) + jtl::result context::compile_module(jtl::immutable_string const &module) { module_dependencies.clear(); @@ -377,55 +391,124 @@ namespace jank::runtime return evaluate::eval(expr); } + jtl::immutable_string + context::get_output_module_name(jtl::immutable_string const &module_name) const + { + char const *ext{}; + switch(util::cli::opts.output_target) + { + case util::cli::compilation_target::llvm_ir: + ext = "ll"; + break; + case util::cli::compilation_target::cpp: + ext = "cpp"; + break; + case util::cli::compilation_target::object: + ext = "o"; + break; + case util::cli::compilation_target::unspecified: + default: + throw error::internal_runtime_failure( + util::format("Unable to determine output module name, given output target '{}'.", + util::cli::compilation_target_str(util::cli::opts.output_target))); + } + + return util::cli::opts.output_module_filename.empty() + ? util::format("{}/{}.{}", binary_cache_dir, module::module_to_path(module_name), ext) + : jtl::immutable_string{ util::cli::opts.output_module_filename }; + } + jtl::string_result context::write_module(jtl::immutable_string const &module_name, + jtl::immutable_string const &cpp_code, jtl::ref const &module) const { profile::timer const timer{ util::format("write_module {}", module_name) }; - std::filesystem::path const module_path{ - util::cli::opts.output_object_filename.empty() - ? util::format("{}/{}.o", binary_cache_dir, module::module_to_path(module_name)) - : jtl::immutable_string{ util::cli::opts.output_object_filename } - }; - std::filesystem::create_directories(module_path.parent_path()); - - /* TODO: Is there a better place for this block of code? */ - std::error_code file_error{}; - llvm::raw_fd_ostream os(module_path.c_str(), file_error, llvm::sys::fs::OpenFlags::OF_None); - if(file_error) + std::filesystem::path const module_path{ get_output_module_name(module_name) }; + auto const &module_dir{ module_path.parent_path() }; + if(!module_dir.empty()) { - return err(util::format("failed to open module file {} with error {}", - module_path.c_str(), - file_error.message())); + std::filesystem::create_directories(module_dir); } - //module->print(llvm::outs(), nullptr); - auto const target_triple{ util::default_target_triple() }; - std::string target_error; - auto const target{ llvm::TargetRegistry::lookupTarget(target_triple.c_str(), target_error) }; - if(!target) + switch(util::cli::opts.output_target) { - return err(target_error); - } - llvm::TargetOptions const opt; - auto const target_machine{ target->createTargetMachine(llvm::Triple{ target_triple.c_str() }, - "generic", - "", - opt, - llvm::Reloc::PIC_) }; - if(!target_machine) - { - return err(util::format("failed to create target machine for {}", target_triple)); - } - llvm::legacy::PassManager pass; + case util::cli::compilation_target::cpp: + { + std::ofstream ofs{ module_path.c_str() }; + ofs << "#include \n"; + ofs << cpp_code; + return ok(); + } + case util::cli::compilation_target::llvm_ir: + { + std::error_code file_error{}; + llvm::raw_fd_ostream os(module_path.c_str(), + file_error, + llvm::sys::fs::OpenFlags::OF_None); + if(file_error) + { + return err(util::format("Failed to open module file '{}' with error '{}'.", + module_path.c_str(), + file_error.message())); + } + module->print(os, nullptr); + return ok(); + } + case util::cli::compilation_target::object: + { + /* TODO: Is there a better place for this block of code? */ + std::error_code file_error{}; + llvm::raw_fd_ostream os(module_path.c_str(), + file_error, + llvm::sys::fs::OpenFlags::OF_None); + if(file_error) + { + return err(util::format("Failed to open module file '{}' with error '{}'.", + module_path.c_str(), + file_error.message())); + } + //module->print(llvm::outs(), nullptr); - if(target_machine->addPassesToEmitFile(pass, os, nullptr, llvm::CodeGenFileType::ObjectFile)) - { - return err(util::format("failed to write module to object file for {}", target_triple)); - } + auto const target_triple{ util::default_target_triple() }; + std::string target_error; + auto const target{ llvm::TargetRegistry::lookupTarget(target_triple.c_str(), + target_error) }; + if(!target) + { + return err(target_error); + } + llvm::TargetOptions const opt; + auto const target_machine{ target->createTargetMachine( + llvm::Triple{ target_triple.c_str() }, + "generic", + "", + opt, + llvm::Reloc::PIC_, + llvm::CodeModel::Large, + llvm::CodeGenOptLevel::Default) }; + if(!target_machine) + { + return err(util::format("Failed to create target machine for '{}'.", target_triple)); + } + llvm::legacy::PassManager pass; - pass.run(*module); + if(target_machine->addPassesToEmitFile(pass, + os, + nullptr, + llvm::CodeGenFileType::ObjectFile)) + { + return err( + util::format("Failed to write module to object file for '{}'.", target_triple)); + } - return ok(); + pass.run(*module); + return ok(); + } + case util::cli::compilation_target::unspecified: + default: + return err(util::format("Unable to write module, given output target '{}'.", + util::cli::compilation_target_str(util::cli::opts.output_target))); + } } jtl::immutable_string context::unique_namespaced_string() const @@ -433,36 +516,35 @@ namespace jank::runtime return unique_namespaced_string("G_"); } - jtl::immutable_string - context::unique_namespaced_string(jtl::immutable_string_view const &prefix) const + jtl::immutable_string context::unique_namespaced_string(jtl::immutable_string const &prefix) const { static jtl::immutable_string const dot{ "\\." }; auto const ns{ current_ns() }; return util::format("{}-{}-{}", runtime::munge_and_replace(ns->name->get_name(), dot, "_"), - prefix.data(), + prefix.c_str(), ++ns->symbol_counter); } - jtl::immutable_string context::unique_munged_string() const + jtl::immutable_string context::unique_string() const { - return munge(unique_namespaced_string()); + return unique_string("G_"); } - jtl::immutable_string - context::unique_munged_string(jtl::immutable_string_view const &prefix) const + jtl::immutable_string context::unique_string(jtl::immutable_string const &prefix) const { - return munge(unique_namespaced_string(prefix)); + auto const ns{ current_ns() }; + return util::format("{}-{}", prefix.c_str(), ++ns->symbol_counter); } - obj::symbol context::unique_symbol() const + obj::symbol_ref context::unique_symbol() const { return unique_symbol("G-"); } - obj::symbol context::unique_symbol(jtl::immutable_string_view const &prefix) const + obj::symbol_ref context::unique_symbol(jtl::immutable_string const &prefix) const { - return { "", unique_namespaced_string(prefix) }; + return make_box("", unique_namespaced_string(prefix)); } ns_ref context::intern_ns(jtl::immutable_string const &name) @@ -470,7 +552,7 @@ namespace jank::runtime return intern_ns(make_box(name)); } - ns_ref context::intern_ns(obj::symbol_ref const &sym) + ns_ref context::intern_ns(obj::symbol_ref const sym) { if(!sym->ns.empty()) { @@ -488,7 +570,7 @@ namespace jank::runtime return result.first->second; } - ns_ref context::remove_ns(obj::symbol_ref const &sym) + ns_ref context::remove_ns(obj::symbol_ref const sym) { auto locked_namespaces(namespaces.wlock()); auto const found(locked_namespaces->find(sym)); @@ -501,7 +583,7 @@ namespace jank::runtime return {}; } - ns_ref context::find_ns(obj::symbol_ref const &sym) + ns_ref context::find_ns(obj::symbol_ref const sym) { auto locked_namespaces(namespaces.rlock()); auto const found(locked_namespaces->find(sym)); @@ -512,10 +594,10 @@ namespace jank::runtime return {}; } - ns_ref context::resolve_ns(obj::symbol_ref const &target) + ns_ref context::resolve_ns(obj::symbol_ref const target) { auto const ns(current_ns()); - auto const alias(ns->find_alias(target)); + auto alias(ns->find_alias(target)); if(alias.is_some()) { return alias; @@ -529,6 +611,12 @@ namespace jank::runtime return expect_object(current_ns_var->deref()); } + jtl::result + context::intern_var(jtl::immutable_string const &qualified_name) + { + return intern_var(make_box(qualified_name)); + } + jtl::result context::intern_var(jtl::immutable_string const &ns, jtl::immutable_string const &name) { @@ -536,24 +624,24 @@ namespace jank::runtime } jtl::result - context::intern_var(obj::symbol_ref const &qualified_sym) + context::intern_var(obj::symbol_ref const qualified_name) { profile::timer const timer{ "intern_var" }; - if(qualified_sym->ns.empty()) + if(qualified_name->ns.empty()) { return err( - util::format("Can't intern var. Sym isn't qualified: {}", qualified_sym->to_string())); + util::format("Can't intern var. Sym isn't qualified: {}", qualified_name->to_string())); } auto locked_namespaces(namespaces.wlock()); - obj::symbol const ns_sym{ qualified_sym->ns }; - auto const found_ns(locked_namespaces->find(&ns_sym)); + obj::symbol_ref const ns_sym{ make_box(qualified_name->ns) }; + auto const found_ns(locked_namespaces->find(ns_sym)); if(found_ns == locked_namespaces->end()) { - return err(util::format("Can't intern var. Namespace doesn't exist: {}", qualified_sym->ns)); + return err(util::format("Can't intern var. Namespace doesn't exist: {}", qualified_name->ns)); } - return ok(found_ns->second->intern_var(qualified_sym)); + return ok(found_ns->second->intern_var(qualified_name)); } jtl::result @@ -563,7 +651,13 @@ namespace jank::runtime } jtl::result - context::intern_owned_var(obj::symbol_ref const &qualified_sym) + context::intern_owned_var(jtl::immutable_string const &qualified_name) + { + return intern_owned_var(make_box(qualified_name)); + } + + jtl::result + context::intern_owned_var(obj::symbol_ref const qualified_sym) { /* TODO: Clean up duplication between this and intern_var. */ profile::timer const timer{ "intern_var" }; @@ -574,8 +668,8 @@ namespace jank::runtime } auto locked_namespaces(namespaces.wlock()); - obj::symbol const ns_sym{ qualified_sym->ns }; - auto const found_ns(locked_namespaces->find(&ns_sym)); + obj::symbol_ref const ns_sym{ make_box(qualified_sym->ns) }; + auto const found_ns(locked_namespaces->find(ns_sym)); if(found_ns == locked_namespaces->end()) { return err(util::format("Can't intern var. Namespace doesn't exist: {}", qualified_sym->ns)); @@ -633,7 +727,7 @@ namespace jank::runtime profile::timer const timer{ "rt macroexpand1" }; return visit_seqable( [this](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(!behavior::sequenceable) { @@ -662,7 +756,7 @@ namespace jank::runtime } /* TODO: Provide &env. */ - auto const args(cons(cons(rest(typed_o), jank_nil), typed_o)); + auto const args(cons(cons(rest(typed_o), jank_nil()), typed_o)); return apply_to(var->deref(), args); } }, @@ -678,7 +772,7 @@ namespace jank::runtime /* If we've actually expanded `o` into something else, it's helpful to update the meta * on the expanded data to tie it back to the original form. */ auto const source{ object_source(o) }; - if(source != read::source::unknown) + if(source != read::source::unknown()) { auto meta{ runtime::meta(expanded) }; auto const macro_kw{ __rt_ctx->intern_keyword("jank/macro-expansion").expect_ok() }; @@ -717,7 +811,7 @@ namespace jank::runtime jtl::string_result context::push_thread_bindings() { auto bindings(obj::persistent_hash_map::empty()); - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames); if(!tbfs.empty()) { bindings = tbfs.front().bindings; @@ -746,14 +840,13 @@ namespace jank::runtime context::push_thread_bindings(obj::persistent_hash_map_ref const bindings) { thread_binding_frame frame{ obj::persistent_hash_map::empty() }; - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames); + auto const thread_id{ std::this_thread::get_id() }; if(!tbfs.empty()) { frame.bindings = tbfs.front().bindings; } - auto const thread_id(std::this_thread::get_id()); - for(auto it(bindings->fresh_seq()); it.is_some(); it = it->next_in_place()) { auto const entry(it->first()); @@ -789,7 +882,7 @@ namespace jank::runtime jtl::string_result context::pop_thread_bindings() { - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames); if(tbfs.empty()) { return err("Mismatched thread binding pop"); @@ -802,7 +895,7 @@ namespace jank::runtime obj::persistent_hash_map_ref context::get_thread_bindings() const { - auto const &tbfs(thread_binding_frames[this]); + auto const &tbfs(thread_binding_frames); if(tbfs.empty()) { return obj::persistent_hash_map::empty(); @@ -812,7 +905,7 @@ namespace jank::runtime jtl::option context::current_thread_binding_frame() { - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames); if(tbfs.empty()) { return none; diff --git a/compiler+runtime/src/cpp/jank/runtime/core.cpp b/compiler+runtime/src/cpp/jank/runtime/core.cpp index c6f04cca8..49ccb6652 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core.cpp @@ -16,7 +16,7 @@ namespace jank::runtime bool is_nil(object_ref const o) { - return o == jank_nil; + return o == jank_nil(); } bool is_true(object_ref const o) @@ -31,7 +31,7 @@ namespace jank::runtime bool is_some(object_ref const o) { - return o != jank_nil; + return o != jank_nil(); } bool is_string(object_ref const o) @@ -63,7 +63,7 @@ namespace jank::runtime { return runtime::visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -99,7 +99,7 @@ namespace jank::runtime { visit_object( [](auto const typed_args) { - using T = typename decltype(typed_args)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::sequenceable) { @@ -119,14 +119,14 @@ namespace jank::runtime } }, args); - return jank_nil; + return jank_nil(); } object_ref println(object_ref const args) { visit_object( [](auto const typed_more) { - using T = typename decltype(typed_more)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -151,14 +151,14 @@ namespace jank::runtime } }, args); - return jank_nil; + return jank_nil(); } object_ref pr(object_ref const args) { visit_object( [](auto const typed_args) { - using T = typename decltype(typed_args)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::sequenceable) { @@ -178,14 +178,14 @@ namespace jank::runtime } }, args); - return jank_nil; + return jank_nil(); } object_ref prn(object_ref const args) { visit_object( [](auto const typed_args) { - using T = typename decltype(typed_args)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -210,15 +210,7 @@ namespace jank::runtime } }, args); - return jank_nil; - } - - f64 to_real(object_ref const o) - { - return visit_number_like( - [](auto const typed_o) -> f64 { return typed_o->to_real(); }, - [=]() -> f64 { throw std::runtime_error{ util::format("not a number: {}", to_string(o)) }; }, - o); + return jank_nil(); } obj::persistent_string_ref subs(object_ref const s, object_ref const start) @@ -262,7 +254,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_o) { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::nameable; }, @@ -273,7 +265,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_o) -> jtl::immutable_string { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -295,14 +287,14 @@ namespace jank::runtime { return visit_object( [](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::nameable) { auto const ns(typed_o->get_namespace()); if(ns.empty()) { - return jank_nil; + return jank_nil(); } return make_box(ns); } @@ -356,7 +348,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return std::is_base_of_v; }, @@ -380,7 +372,7 @@ namespace jank::runtime object_ref gensym(object_ref const o) { - return make_box(__rt_ctx->unique_symbol(to_string(o))); + return __rt_ctx->unique_symbol(to_string(o)); } object_ref atom(object_ref const o) @@ -458,7 +450,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::derefable) { @@ -550,7 +542,7 @@ namespace jank::runtime switch(size) { case 0: - return jank_nil; + return jank_nil(); case 1: { return make_box(match_results[0].str()); @@ -613,7 +605,7 @@ namespace jank::runtime if(!match_results.suffix().str().empty()) { - return jank_nil; + return jank_nil(); } return smatch_to_vector(match_results); @@ -629,7 +621,7 @@ namespace jank::runtime } catch(...) { - return jank_nil; + return jank_nil(); } } else @@ -670,7 +662,7 @@ namespace jank::runtime { visit_object( [=](auto const typed_reference) -> void { - using T = typename decltype(typed_reference)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::ref_like) { @@ -692,7 +684,7 @@ namespace jank::runtime { visit_object( [=](auto const typed_reference) -> void { - using T = typename decltype(typed_reference)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::ref_like) { diff --git a/compiler+runtime/src/cpp/jank/runtime/core/equal.cpp b/compiler+runtime/src/cpp/jank/runtime/core/equal.cpp index fd7962b27..2805af947 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/equal.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/equal.cpp @@ -12,7 +12,7 @@ namespace jank::runtime return false; } - auto const typed_rhs = expect_object(rhs); + auto const typed_rhs{ expect_object(rhs) }; return typed_rhs->to_hash() == static_cast(lhs); } @@ -37,16 +37,16 @@ namespace jank::runtime return 0; } - if(l != jank_nil) + if(l != jank_nil()) { - if(r == jank_nil) + if(r == jank_nil()) { return 1; } return visit_object( - [](auto const typed_l, auto const r) -> i64 { - using L = typename decltype(typed_l)::value_type; + [](auto const typed_l, auto const &r) -> i64 { + using L = typename jtl::decay_t::value_type; if constexpr(behavior::comparable) { return typed_l->compare(*r); diff --git a/compiler+runtime/src/cpp/jank/runtime/core/math.cpp b/compiler+runtime/src/cpp/jank/runtime/core/math.cpp index e6766720f..071db4f09 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/math.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/math.cpp @@ -903,7 +903,8 @@ namespace jank::runtime auto const data_l{ to_real(typed_l) }; auto const data_r{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C + = std::common_type_t, jtl::decay_t>; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wfloat-equal" return static_cast(data_l) == static_cast(data_r); @@ -1077,7 +1078,8 @@ namespace jank::runtime f64 rand() { - static std::mt19937 gen; + static std::random_device dev; + static std::mt19937 gen{ dev() }; static std::uniform_real_distribution dis(0.0, 1.0); return dis(gen); } @@ -1369,7 +1371,8 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> f64 { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, + jtl::decay_t>; return std::min(static_cast(typed_l), static_cast(typed_r_data)); }, r, @@ -1381,7 +1384,8 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t, + jtl::decay_t>; return std::min(static_cast(typed_l_data), static_cast(typed_r)); }, l, @@ -1403,7 +1407,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::min(static_cast(typed_l_data), static_cast(typed_r)); }, l, @@ -1415,7 +1419,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> f64 { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::min(static_cast(typed_r_data), static_cast(typed_l)); }, r, @@ -1512,7 +1516,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> f64 { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, decltype(typed_r_data)>; return std::max(static_cast(typed_l), static_cast(typed_r_data)); }, r, @@ -1524,7 +1528,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::max(static_cast(typed_r), static_cast(typed_l_data)); }, l, @@ -1546,7 +1550,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> object_ref { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return make_box(std::max(static_cast(typed_r), static_cast(typed_l_data))); }, l, @@ -1558,7 +1562,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> object_ref { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, decltype(typed_r_data)>; return make_box(std::max(static_cast(typed_l), static_cast(typed_r_data))); }, r, @@ -1703,7 +1707,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::pow(static_cast(typed_l_data), static_cast(typed_r)); }, l, @@ -1725,7 +1729,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> f64 { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, decltype(typed_r_data)>; return std::pow(static_cast(typed_l), static_cast(typed_r_data)); }, r, @@ -1737,7 +1741,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::pow(static_cast(typed_l_data), static_cast(typed_r)); }, l, @@ -1759,7 +1763,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> object_ref { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return make_box(std::pow(static_cast(typed_l_data), static_cast(typed_r))); }, l, @@ -1771,7 +1775,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> object_ref { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, decltype(typed_r_data)>; return make_box(std::pow(static_cast(typed_l), static_cast(typed_r_data))); }, r, @@ -1798,7 +1802,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_l, auto const typed_r) -> f64 { auto const typed_l_data{ to_real(typed_l->data) }; - using C = std::common_type_t; + using C = std::common_type_t>; return std::pow(static_cast(typed_l_data), static_cast(typed_r)); }, l, @@ -1810,7 +1814,7 @@ namespace jank::runtime return visit_number_like( [](auto const typed_r, auto const typed_l) -> f64 { auto const typed_r_data{ to_real(typed_r->data) }; - using C = std::common_type_t; + using C = std::common_type_t, decltype(typed_r_data)>; return std::pow(static_cast(typed_l), static_cast(typed_r_data)); }, r, @@ -1857,6 +1861,14 @@ namespace jank::runtime return static_cast(l); } + f64 to_real(object_ref const o) + { + return visit_number_like( + [](auto const typed_o) -> f64 { return typed_o->to_real(); }, + [=]() -> f64 { throw std::runtime_error{ util::format("not a number: {}", to_string(o)) }; }, + o); + } + bool is_number(object_ref const o) { return visit_number_like([=](auto const) -> bool { return true; }, @@ -1893,7 +1905,7 @@ namespace jank::runtime { return visit_number_like( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -1911,7 +1923,7 @@ namespace jank::runtime { return visit_number_like( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -1994,7 +2006,7 @@ namespace jank::runtime { return visit_number_like( [&](auto const typed_o) -> obj::big_decimal_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { diff --git a/compiler+runtime/src/cpp/jank/runtime/core/meta.cpp b/compiler+runtime/src/cpp/jank/runtime/core/meta.cpp index 755edd2d1..b7035ebe6 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/meta.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/meta.cpp @@ -19,15 +19,15 @@ namespace jank::runtime return visit_object( [](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { - return typed_m->meta.unwrap_or(jank_nil); + return typed_m->meta.unwrap_or(jank_nil()); } else { - return jank_nil; + return jank_nil(); } }, m); @@ -37,7 +37,7 @@ namespace jank::runtime { return visit_object( [&o](auto const typed_o, object_ref const m) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { @@ -63,7 +63,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_o, object_ref const m) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { @@ -82,7 +82,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_o, object_ref const m) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { @@ -105,17 +105,17 @@ namespace jank::runtime { using namespace jank::runtime; - auto const meta(o.unwrap_or(jank_nil)); + auto const meta(o.unwrap_or(jank_nil())); auto const source(get(meta, __rt_ctx->intern_keyword("jank/source").expect_ok())); - if(source == jank_nil) + if(source == jank_nil()) { - return read::source::unknown; + return read::source::unknown(); } auto const file(get(source, __rt_ctx->intern_keyword("file").expect_ok())); - if(file == jank_nil) + if(file == jank_nil()) { - return read::source::unknown; + return read::source::unknown(); } auto const module(get(source, __rt_ctx->intern_keyword("module").expect_ok())); @@ -150,9 +150,9 @@ namespace jank::runtime read::source object_source(object_ref const o) { auto const meta(runtime::meta(o)); - if(meta == jank_nil) + if(meta == jank_nil()) { - return read::source::unknown; + return read::source::unknown(); } return meta_source(meta); } @@ -225,7 +225,7 @@ namespace jank::runtime return meta; } - auto const stripped{ strip_source_from_meta(meta.unwrap()) }; + auto stripped{ strip_source_from_meta(meta.unwrap()) }; if(is_empty(stripped)) { return none; diff --git a/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp b/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp index 1c508e91e..449eaffa4 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp @@ -28,6 +28,8 @@ namespace jank::runtime { '}', "_RBRACE_" }, { '[', "_LBRACK_" }, { ']', "_RBRACK_" }, + { '(', "_LPAREN_" }, + { ')', "_RPAREN_" }, { '/', "_SLASH_" }, { '\\', "_BSLASH_" }, { '?', "_QMARK_" } @@ -40,6 +42,8 @@ namespace jank::runtime { "_RBRACE_", '}' }, { "_LBRACK_", '[' }, { "_RBRACK_", ']' }, + { "_LPAREN_", '(' }, + { "_RPAREN_", ')' }, { "_BSLASH_", '\\' }, { "_SQUOTE_", '\'' }, { "_DQUOTE_", '"' }, diff --git a/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp b/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp index 7ee83ee28..4cf44c42f 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp @@ -28,7 +28,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -55,7 +55,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::sequenceable; }, @@ -64,7 +64,7 @@ namespace jank::runtime bool is_seqable(object_ref const o) { - return visit_seqable([=](auto const) -> bool { return true; }, + return visit_seqable([=](auto const &) -> bool { return true; }, [=]() -> bool { return false; }, o); } @@ -73,7 +73,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::sequential; }, @@ -84,7 +84,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::collection_like; }, @@ -114,7 +114,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return (behavior::associatively_readable && behavior::associatively_writable); }, @@ -131,7 +131,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::countable; }, @@ -142,7 +142,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::transientable; }, @@ -159,7 +159,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::transientable) { @@ -178,7 +178,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::persistentable) { @@ -196,8 +196,8 @@ namespace jank::runtime object_ref conj_in_place(object_ref const coll, object_ref const o) { return visit_object( - [](auto const typed_coll, auto const o) -> object_ref { - using T = typename decltype(typed_coll)::value_type; + [](auto const typed_coll, auto const &o) -> object_ref { + using T = typename jtl::decay_t::value_type; if constexpr(behavior::conjable_in_place) { @@ -236,8 +236,8 @@ namespace jank::runtime object_ref assoc_in_place(object_ref const coll, object_ref const k, object_ref const v) { return visit_object( - [](auto const typed_coll, auto const k, auto const v) -> object_ref { - using T = typename decltype(typed_coll)::value_type; + [](auto const typed_coll, auto const &k, auto const &v) -> object_ref { + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_writable_in_place) { @@ -257,8 +257,8 @@ namespace jank::runtime object_ref dissoc_in_place(object_ref const coll, object_ref const k) { return visit_object( - [](auto const typed_coll, auto const k) -> object_ref { - using T = typename decltype(typed_coll)::value_type; + [](auto const typed_coll, auto const &k) -> object_ref { + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_writable_in_place) { @@ -284,7 +284,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -312,7 +312,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -340,7 +340,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -377,7 +377,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -409,7 +409,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -454,7 +454,7 @@ namespace jank::runtime { return obj::persistent_list::empty(); } - auto const ret(next(seq)); + auto ret(next(seq)); if(ret.is_nil()) { return obj::persistent_list::empty(); @@ -468,7 +468,7 @@ namespace jank::runtime { return visit_seqable( [=](auto const typed_tail) -> object_ref { - using T = typename decltype(typed_tail)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(jtl::is_same) { @@ -493,7 +493,7 @@ namespace jank::runtime { return visit_object( [&](auto const typed_s) -> object_ref { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -532,7 +532,7 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_writable) { @@ -551,7 +551,7 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_writable) { @@ -570,7 +570,7 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable) { @@ -578,7 +578,7 @@ namespace jank::runtime } else { - return jank_nil; + return jank_nil(); } }, m); @@ -588,7 +588,7 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable) { @@ -606,14 +606,14 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable) { return visit_seqable( [&](auto const typed_keys) -> object_ref { object_ref ret{ typed_m }; - for(auto const e : make_sequence_range(typed_keys)) + for(auto const &e : make_sequence_range(typed_keys)) { ret = get(ret, e); } @@ -623,7 +623,7 @@ namespace jank::runtime } else { - return jank_nil; + return jank_nil(); } }, m); @@ -633,19 +633,19 @@ namespace jank::runtime { return visit_object( [&](auto const typed_m) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable) { return visit_seqable( [&](auto const typed_keys) -> object_ref { object_ref ret{ typed_m }; - for(auto const e : make_sequence_range(typed_keys)) + for(auto const &e : make_sequence_range(typed_keys)) { ret = get(ret, e); } - if(ret == jank_nil) + if(ret == jank_nil()) { return fallback; } @@ -655,7 +655,7 @@ namespace jank::runtime } else { - return jank_nil; + return jank_nil(); } }, m); @@ -670,7 +670,7 @@ namespace jank::runtime return visit_object( [](auto const typed_s, object_ref const key) -> object_ref { - using S = typename decltype(typed_s)::value_type; + using S = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable) { @@ -678,7 +678,7 @@ namespace jank::runtime } else { - return jank_nil; + return jank_nil(); } }, s, @@ -694,7 +694,7 @@ namespace jank::runtime return visit_object( [&](auto const typed_s) -> bool { - using S = typename decltype(typed_s)::value_type; + using S = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_readable || behavior::set_like) { @@ -712,7 +712,7 @@ namespace jank::runtime { return visit_object( [](auto const typed_m, object_ref const other) -> object_ref { - using T = typename decltype(typed_m)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(jtl::is_same) { @@ -720,14 +720,14 @@ namespace jank::runtime } else if constexpr(behavior::associatively_writable) { - using R = decltype(assoc(typed_m, jank_nil, jank_nil)); + using R = decltype(assoc(typed_m, jank_nil(), jank_nil())); return visit_map_like( [](auto const typed_other, auto const typed_m) -> object_ref { R ret{ typed_m }; for(auto seq{ typed_other->fresh_seq() }; seq.is_some(); seq = seq->next_in_place()) { - auto const e(seq->first()); + auto const &e(seq->first()); ret = assoc(ret, e->data[0], e->data[1]); } return ret; @@ -752,18 +752,18 @@ namespace jank::runtime return m; } return visit_object( - [](auto const typed_m, auto const other) -> object_ref { - using T = typename decltype(typed_m)::value_type; + [](auto const typed_m, auto const &other) -> object_ref { + using T = typename jtl::decay_t::value_type; if constexpr(behavior::associatively_writable_in_place) { - using R = decltype(assoc_in_place(typed_m, jank_nil, jank_nil)); + using R = decltype(assoc_in_place(typed_m, jank_nil(), jank_nil())); return visit_map_like( [](auto const typed_other, auto const typed_m) -> object_ref { R ret{ typed_m }; for(auto seq{ typed_other->fresh_seq() }; seq.is_some(); seq = seq->next_in_place()) { - auto const e(seq->first()); + auto const &e(seq->first()); ret = assoc_in_place(ret, e->data[0], e->data[1]); } return ret; @@ -788,7 +788,7 @@ namespace jank::runtime throw std::runtime_error{ "not a vector" }; } - auto const v(expect_object(o)); + auto const &v(expect_object(o)); if(end < start || start < 0 || static_cast(end) > v->count()) { @@ -809,14 +809,14 @@ namespace jank::runtime { throw std::runtime_error{ util::format("index out of bounds: {}", index) }; } - else if(o == jank_nil) + else if(o == jank_nil()) { return o; } return visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::indexable) { @@ -825,7 +825,7 @@ namespace jank::runtime else if constexpr(behavior::seqable && behavior::sequential) { i64 i{}; - for(auto const e : make_sequence_range(typed_o)) + for(auto const &e : make_sequence_range(typed_o)) { if(i == index) { @@ -846,14 +846,14 @@ namespace jank::runtime object_ref nth(object_ref const o, object_ref const idx, object_ref const fallback) { auto const index(to_int(idx)); - if(index < 0 || o == jank_nil) + if(index < 0 || o == jank_nil()) { return fallback; } return visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::indexable) { @@ -862,7 +862,7 @@ namespace jank::runtime else if constexpr(behavior::seqable && behavior::sequential) { i64 i{}; - for(auto const e : make_sequence_range(typed_o)) + for(auto const &e : make_sequence_range(typed_o)) { if(i == index) { @@ -882,14 +882,14 @@ namespace jank::runtime object_ref peek(object_ref const o) { - if(o == jank_nil) + if(o == jank_nil()) { return o; } return visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::stackable) { @@ -905,14 +905,14 @@ namespace jank::runtime object_ref pop(object_ref const o) { - if(o == jank_nil) + if(o == jank_nil()) { return o; } return visit_object( [&](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::stackable) { @@ -930,16 +930,16 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::collection_like) { - auto const empty{ T::empty() }; + auto const &empty{ T::empty() }; return with_meta(empty, meta(typed_o)); } else { - return jank_nil; + return jank_nil(); } }, o); @@ -960,7 +960,7 @@ namespace jank::runtime } return visit_seqable( [](auto const typed_args, jtl::string_builder &buff) -> jtl::immutable_string { - for(auto const e : make_sequence_range(typed_args)) + for(auto const &e : make_sequence_range(typed_args)) { if(is_nil(e)) { @@ -1006,7 +1006,7 @@ namespace jank::runtime return visit_object( [&](auto const typed_s) -> usize { - using T = typename decltype(typed_s)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::same_as) { @@ -1019,7 +1019,7 @@ namespace jank::runtime else if constexpr(behavior::seqable) { usize length{ 0 }; - auto const r{ make_sequence_range(typed_s) }; + auto const &r{ make_sequence_range(typed_s) }; for(auto i(r.begin()); i != r.end() && length < max; ++i) { ++length; @@ -1046,8 +1046,8 @@ namespace jank::runtime [](auto const typed_l, object_ref const r) -> bool { return visit_seqable( [](auto const typed_r, auto const typed_l) -> bool { - auto const l_range{ make_sequence_range(typed_l) }; - auto const r_range{ make_sequence_range(typed_r) }; + auto const &l_range{ make_sequence_range(typed_l) }; + auto const &r_range{ make_sequence_range(typed_r) }; auto r_it(r_range.begin()); for(auto l_it(l_range.begin()); l_it != l_range.end(); ++l_it, ++r_it) { @@ -1072,7 +1072,7 @@ namespace jank::runtime return visit_seqable( [](auto const typed_coll, object_ref const f, object_ref const init) -> object_ref { object_ref res{ init }; - for(auto const e : make_sequence_range(typed_coll)) + for(auto const &e : make_sequence_range(typed_coll)) { res = dynamic_call(f, res, e); if(res->type == object_type::reduced) @@ -1105,14 +1105,14 @@ namespace jank::runtime object_ref chunk_append(object_ref const buff, object_ref const val) { - auto const buffer(try_object(buff)); + auto const &buffer(try_object(buff)); buffer->append(val); - return jank_nil; + return jank_nil(); } object_ref chunk(object_ref const buff) { - auto const buffer(try_object(buff)); + auto const &buffer(try_object(buff)); return buffer->chunk(); } @@ -1120,7 +1120,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::chunkable) { @@ -1137,7 +1137,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::chunkable) { @@ -1154,11 +1154,16 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> object_ref { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::chunkable) { - return typed_o->chunked_next().erase() ?: obj::persistent_list::empty().erase(); + auto ret{ typed_o->chunked_next() }; + if(ret.is_nil()) + { + return obj::persistent_list::empty(); + } + return ret; } { throw std::runtime_error{ util::format("not chunkable: {}", typed_o->to_code_string()) }; @@ -1176,7 +1181,7 @@ namespace jank::runtime { return visit_object( [=](auto const typed_o) -> bool { - using T = typename decltype(typed_o)::value_type; + using T = typename jtl::decay_t::value_type; return behavior::chunkable; }, @@ -1203,7 +1208,7 @@ namespace jank::runtime return visit_seqable( [](auto const typed_coll) -> object_ref { native_vector vec; - for(auto const e : make_sequence_range(typed_coll)) + for(auto const &e : make_sequence_range(typed_coll)) { vec.push_back(e); } @@ -1212,7 +1217,7 @@ namespace jank::runtime return runtime::compare(a, b) < 0; }); - using T = typename decltype(typed_coll)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::metadatable) { @@ -1231,7 +1236,7 @@ namespace jank::runtime return visit_seqable( [](auto const typed_coll) -> object_ref { native_vector vec; - for(auto const e : make_sequence_range(typed_coll)) + for(auto const &e : make_sequence_range(typed_coll)) { vec.push_back(e); } diff --git a/compiler+runtime/src/cpp/jank/runtime/core/truthy.cpp b/compiler+runtime/src/cpp/jank/runtime/core/truthy.cpp index 24228c95d..ac7fe3074 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/truthy.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/truthy.cpp @@ -29,7 +29,7 @@ namespace jank::runtime return truthy(o.data); } - bool truthy(obj::nil_ref) + bool truthy(obj::nil_ref const) { return false; } diff --git a/compiler+runtime/src/cpp/jank/runtime/detail/native_array_map.cpp b/compiler+runtime/src/cpp/jank/runtime/detail/native_array_map.cpp index d1ab5e2fe..cb98f1f0c 100644 --- a/compiler+runtime/src/cpp/jank/runtime/detail/native_array_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/detail/native_array_map.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace jank::runtime::detail @@ -117,6 +118,13 @@ namespace jank::runtime::detail } } + native_array_map::~native_array_map() + { + data = nullptr; + /* TODO: data could still be referenced by iterators. shared ptr? */ + //delete[] data; + } + void native_array_map::insert_unique(object_ref const key, object_ref const val) { data = make_next_array(data, cap, length, key, val); @@ -292,7 +300,7 @@ namespace jank::runtime::detail auto const new_capacity{ static_cast(size * 2) }; - if(new_capacity < cap) + if(new_capacity <= cap) { return; } @@ -305,6 +313,8 @@ namespace jank::runtime::detail new_data[i + 1] = data[i + 1]; } + //delete[] data; + data = new_data; cap = new_capacity; } @@ -327,8 +337,11 @@ namespace jank::runtime::detail native_array_map native_array_map::clone() const { native_array_map ret{ *this }; - ret.data = new(GC) object_ref[length]; - memcpy(ret.data, data, length * sizeof(object_ref)); + ret.data = new(GC) object_ref[cap]; + for(u8 i{}; i < length; ++i) + { + ret.data[i] = data[i]; + } return ret; } } diff --git a/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp b/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp index cd8a24c82..b8c4abafd 100644 --- a/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp @@ -22,11 +22,3 @@ namespace immer std::equal_to, jank::memory_policy>; } - -namespace bpptree::detail -{ - template struct BppTreeSet; - template struct BppTreeMap; -} diff --git a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp index 2687ff978..eef941579 100644 --- a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp @@ -63,6 +63,7 @@ namespace jank::runtime::module return util::format("jank_load_{}", ret); } + /* TODO: I don't think this is needed. */ jtl::immutable_string nest_module(jtl::immutable_string const &module, jtl::immutable_string const &sub) { @@ -834,7 +835,7 @@ namespace jank::runtime::module } }; auto const swap_fn_wrapper{ make_box( - std::function{ swap_fn }) }; + std::function{ swap_fn }) }; loaded_libs_atom->swap(swap_fn_wrapper); } @@ -979,7 +980,8 @@ namespace jank::runtime::module auto const existing_load{ __rt_ctx->jit_prc.find_symbol(load_function_name) }; if(existing_load.is_ok()) { - reinterpret_cast(existing_load.expect_ok())(); + /* TODO: Update LLVM IR for this. */ + reinterpret_cast(existing_load.expect_ok())(); return ok(); } @@ -992,8 +994,8 @@ namespace jank::runtime::module __rt_ctx->jit_prc.load_object(entry.path); } - auto const load{ __rt_ctx->jit_prc.find_symbol(load_function_name).expect_ok() }; - reinterpret_cast(load)(); + auto const load_fn_res{ __rt_ctx->jit_prc.find_symbol(load_function_name).expect_ok() }; + reinterpret_cast(load_fn_res)(); return ok(); } @@ -1043,7 +1045,7 @@ namespace jank::runtime::module * What if load function is already loaded/defined? The llvm::Interpreter::Execute will fail. */ auto const load_function_name{ module_to_load_function(module) }; auto const load{ __rt_ctx->jit_prc.find_symbol(load_function_name).expect_ok() }; - reinterpret_cast(load)(); + reinterpret_cast(load)(); return ok(); } diff --git a/compiler+runtime/src/cpp/jank/runtime/ns.cpp b/compiler+runtime/src/cpp/jank/runtime/ns.cpp index 1bd1af4a7..dedb024f9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/ns.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/ns.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace jank::runtime { @@ -85,14 +86,12 @@ namespace jank::runtime if(redefined) { auto const v{ expect_object(*found_var) }; - /* TODO: Util for warning. */ - util::println( - stderr, - "WARNING: '{}' already referred to {} in namespace '{}' but has been replaced by {}", - unqualified_sym->to_string(), - v->to_code_string(), - name->to_string(), - new_var->to_code_string()); + error::warn( + util::format("'{}' already referred to {} in namespace '{}' but has been replaced by {}", + unqualified_sym->to_string(), + v->to_code_string(), + name->to_string(), + new_var->to_code_string())); } *locked_vars = make_box((*locked_vars)->data.set(unqualified_sym, new_var)); diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/atom.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/atom.cpp index 9f38e0322..16c181421 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/atom.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/atom.cpp @@ -48,7 +48,7 @@ namespace jank::runtime::obj static void notify_watches(atom_ref const a, object_ref const old_val, object_ref const new_val) { auto const locked_watches(a->watches.rlock()); - for(auto const entry : (*locked_watches)->data) + for(auto const &entry : (*locked_watches)->data) { auto const fn(entry.second); if(fn.is_some()) @@ -75,7 +75,8 @@ namespace jank::runtime::obj if(val.compare_exchange_weak(v, o.data)) { notify_watches(this, v, o); - return make_box(std::in_place, v, o); + auto ret{ make_box(std::in_place, v, o) }; + return ret; } } } @@ -151,7 +152,8 @@ namespace jank::runtime::obj if(val.compare_exchange_weak(v, next.data)) { notify_watches(this, v, next); - return make_box(std::in_place, v, next); + auto ret{ make_box(std::in_place, v, next) }; + return ret; } } } @@ -165,7 +167,8 @@ namespace jank::runtime::obj if(val.compare_exchange_weak(v, next.data)) { notify_watches(this, v, next); - return make_box(std::in_place, v, next); + auto ret{ make_box(std::in_place, v, next) }; + return ret; } } } @@ -180,7 +183,8 @@ namespace jank::runtime::obj if(val.compare_exchange_weak(v, next.data)) { notify_watches(this, v, next); - return make_box(std::in_place, v, next); + auto ret{ make_box(std::in_place, v, next) }; + return ret; } } } @@ -198,7 +202,8 @@ namespace jank::runtime::obj if(val.compare_exchange_weak(v, next.data)) { notify_watches(this, v, next); - return make_box(std::in_place, v, next); + auto ret{ make_box(std::in_place, v, next) }; + return ret; } } } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/big_decimal.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/big_decimal.cpp index 6339a028c..5debf7607 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/big_decimal.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/big_decimal.cpp @@ -4,7 +4,6 @@ namespace jank::runtime { - native_big_decimal operator+(native_big_decimal const &l, native_big_integer const &r) { return l + native_big_decimal(r.str()); diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/big_integer.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/big_integer.cpp index 1dd1fd314..0e49badb4 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/big_integer.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/big_integer.cpp @@ -7,7 +7,6 @@ namespace jank::runtime { - f64 operator+(native_big_integer const &l, f64 const &r) { return obj::big_integer::to_f64(l) + r; diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/chunked_cons.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/chunked_cons.cpp index 7f4bdc6c0..0c74b2f02 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/chunked_cons.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/chunked_cons.cpp @@ -84,15 +84,15 @@ namespace jank::runtime::obj return visit_object( [&](auto const typed_tail) -> chunked_cons_ref { - using T = typename decltype(typed_tail)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::sequenceable) { o->head = typed_tail->first(); o->tail = typed_tail->next(); - if(o->tail == jank_nil) + if(o->tail == jank_nil()) { - o->tail = jank_nil; + o->tail = jank_nil(); } return o; } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/detail/base_persistent_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/detail/base_persistent_map.cpp index 612cdd25d..a3cfc7859 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/detail/base_persistent_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/detail/base_persistent_map.cpp @@ -55,7 +55,7 @@ namespace jank::runtime::obj::detail inserter = '{'; for(auto i(begin); i != end; ++i) { - auto const pair(*i); + auto const &pair(*i); if(to_code) { runtime::to_code_string(pair.first, buff); diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/detail/iterator_sequence.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/detail/iterator_sequence.cpp index 130c3ee07..6d23dcb48 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/detail/iterator_sequence.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/detail/iterator_sequence.cpp @@ -5,13 +5,13 @@ namespace jank::runtime { - bool equal(object_ref lhs, object_ref rhs); + bool equal(object_ref const lhs, object_ref const rhs); } namespace jank::runtime::obj::detail { template - iterator_sequence::iterator_sequence(object_ref const &c, + iterator_sequence::iterator_sequence(object_ref const c, It const &b, It const &e, usize const s) diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/iterator.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/iterator.cpp index c147b1220..ccc3b3fcb 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/iterator.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/iterator.cpp @@ -45,7 +45,7 @@ namespace jank::runtime::obj if(cached_next.is_some()) { current = cached_next->first(); - cached_next = jank_nil; + cached_next = jank_nil(); } else { diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/jit_closure.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/jit_closure.cpp index 65d791826..5e37e08c8 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/jit_closure.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/jit_closure.cpp @@ -36,11 +36,11 @@ namespace jank::runtime::obj void jit_closure::to_string(jtl::string_builder &buff) { - auto const name(get(meta.unwrap_or(jank_nil), __rt_ctx->intern_keyword("name").expect_ok())); + auto const name(get(meta.unwrap_or(jank_nil()), __rt_ctx->intern_keyword("name").expect_ok())); util::format_to( buff, "#object [{} {} {}]", - (name->type == object_type::nil ? "unknown" : expect_object(name)->data), + (name->type == object_type::nil ? "unknown" : try_object(name)->data), object_type_str(base.type), &base); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/jit_function.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/jit_function.cpp index 5a8187d53..1ecf859db 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/jit_function.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/jit_function.cpp @@ -35,11 +35,11 @@ namespace jank::runtime::obj void jit_function::to_string(jtl::string_builder &buff) { - auto const name(get(meta.unwrap_or(jank_nil), __rt_ctx->intern_keyword("name").expect_ok())); + auto const name(get(meta.unwrap_or(jank_nil()), __rt_ctx->intern_keyword("name").expect_ok())); util::format_to( buff, "#object [{} {} {}]", - (name->type == object_type::nil ? "unknown" : expect_object(name)->data), + (name->type == object_type::nil ? "unknown" : try_object(name)->data), object_type_str(base.type), &base); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp index 328597091..931a74bcf 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp @@ -37,8 +37,8 @@ namespace jank::runtime::obj return {}; } auto const r(runtime::fresh_seq(s)); - jank_debug_assert(r != jank_nil); - return make_box(jank_nil, r); + jank_debug_assert(r != jank_nil()); + return make_box(jank_nil(), r); } object_ref lazy_sequence::first() const @@ -89,7 +89,7 @@ namespace jank::runtime::obj { return 1; } - return hash::ordered(s.erase()); + return hash::ordered(s.erase().data); } cons_ref lazy_sequence::conj(object_ref const head) const @@ -104,7 +104,7 @@ namespace jank::runtime::obj if(sv.is_some()) { auto ls{ sv }; - sv = jank_nil; + sv = jank_nil(); if(ls.is_some() && ls->type == object_type::lazy_sequence) { ls = unwrap(ls); @@ -118,7 +118,7 @@ namespace jank::runtime::obj if(fn.is_some()) { sv = dynamic_call(fn); - fn = jank_nil; + fn = jank_nil(); } } @@ -152,7 +152,7 @@ namespace jank::runtime::obj lazy_sequence_ref lazy_sequence::with_meta(object_ref const m) const { - auto const ret(make_box(jank_nil, seq())); + auto const ret(make_box(jank_nil(), seq())); auto const meta(behavior::detail::validate_meta(m)); ret->meta = meta; return ret; diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/multi_function.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/multi_function.cpp index 2817fc676..bf5c92018 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/multi_function.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/multi_function.cpp @@ -199,7 +199,7 @@ namespace jank::runtime::obj multi_function_ref multi_function::reset() { std::lock_guard const locked{ data_lock }; - cached_hierarchy = jank_nil; + cached_hierarchy = jank_nil(); method_table = prefer_table = method_cache = persistent_hash_map::empty(); return this; } @@ -255,7 +255,7 @@ namespace jank::runtime::obj object_ref const y) const { auto const x_prefs(prefer_table->get(x)); - if(x_prefs != jank_nil && expect_object(x_prefs)->contains(y)) + if(x_prefs != jank_nil() && expect_object(x_prefs)->contains(y)) { return true; } @@ -264,7 +264,7 @@ namespace jank::runtime::obj __rt_ctx->intern_var("clojure.core", "parents").expect_ok()->deref() }; - for(auto it(fresh_seq(dynamic_call(parents, hierarchy, y))); it != jank_nil; + for(auto it(fresh_seq(dynamic_call(parents, hierarchy, y))); it != jank_nil(); it = next_in_place(it)) { if(is_preferred(hierarchy, x, first(it))) @@ -273,7 +273,7 @@ namespace jank::runtime::obj } } - for(auto it(fresh_seq(dynamic_call(parents, hierarchy, x))); it != jank_nil; + for(auto it(fresh_seq(dynamic_call(parents, hierarchy, x))); it != jank_nil(); it = next_in_place(it)) { if(is_preferred(hierarchy, first(it), y)) @@ -303,7 +303,7 @@ namespace jank::runtime::obj object_ref multi_function::get_fn(object_ref const dispatch_val) { auto const target(get_method(dispatch_val)); - if(target == jank_nil) + if(target == jank_nil()) { throw std::runtime_error{ util::format("No method in multimethod '{}' for dispatch value: {}", runtime::to_string(name), @@ -319,8 +319,8 @@ namespace jank::runtime::obj reset_cache(); } - auto const target(method_cache->get(dispatch_val)); - if(target != jank_nil) + auto target(method_cache->get(dispatch_val)); + if(target != jank_nil()) { return target; } @@ -332,7 +332,7 @@ namespace jank::runtime::obj { /* TODO: Clojure uses a RW lock here for better parallelism. */ std::lock_guard const locked{ data_lock }; - object_ref best_value{ jank_nil }; + object_ref best_value{ jank_nil() }; persistent_vector_sequence_ref best_entry{}; for(auto it(method_table->fresh_seq()); it.is_some(); it = it->next_in_place()) @@ -367,7 +367,7 @@ namespace jank::runtime::obj else { best_value = method_table->get(default_dispatch_value); - if(best_value == jank_nil) + if(best_value == jank_nil()) { return best_value; } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/native_function_wrapper.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/native_function_wrapper.cpp index 1645ebb90..ae6dc6cdd 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/native_function_wrapper.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/native_function_wrapper.cpp @@ -1,9 +1,11 @@ #include #include #include +#include #include #include #include +#include #include namespace jank::runtime::obj @@ -25,7 +27,12 @@ namespace jank::runtime::obj void native_function_wrapper::to_string(jtl::string_builder &buff) const { - util::format_to(buff, "#object [{} {}]", object_type_str(base.type), &base); + auto const name(get(meta.unwrap_or(jank_nil()), __rt_ctx->intern_keyword("name").expect_ok())); + util::format_to(buff, + "#object [{} {} {}]", + (name.is_nil() ? "unknown" : try_object(name)->data), + object_type_str(base.type), + &base); } jtl::immutable_string native_function_wrapper::to_string() const @@ -48,7 +55,7 @@ namespace jank::runtime::obj template struct build_arity { - using type = typename build_arity::type; + using type = typename build_arity::type; }; template @@ -72,7 +79,7 @@ namespace jank::runtime::obj { auto const name_kw(__rt_ctx->intern_keyword("name").expect_ok()); auto const name_meta(runtime::get(f.meta.unwrap(), name_kw)); - if(name_meta != jank_nil) + if(name_meta != jank_nil()) { name = to_string(name_meta); } @@ -88,92 +95,95 @@ namespace jank::runtime::obj return apply_function(*this); } - object_ref native_function_wrapper::call(object_ref arg1) + object_ref native_function_wrapper::call(object_ref const arg1) { return apply_function(*this, arg1); } - object_ref native_function_wrapper::call(object_ref arg1, object_ref arg2) + object_ref native_function_wrapper::call(object_ref const arg1, object_ref const arg2) { return apply_function(*this, arg1, arg2); } - object_ref native_function_wrapper::call(object_ref arg1, object_ref arg2, object_ref arg3) + object_ref + native_function_wrapper::call(object_ref const arg1, object_ref const arg2, object_ref const arg3) { return apply_function(*this, arg1, arg2, arg3); } - object_ref - native_function_wrapper::call(object_ref arg1, object_ref arg2, object_ref arg3, object_ref arg4) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4) { return apply_function(*this, arg1, arg2, arg3, arg4); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5, - object_ref arg6) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5, + object_ref const arg6) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5, arg6); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5, - object_ref arg6, - object_ref arg7) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5, + object_ref const arg6, + object_ref const arg7) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5, - object_ref arg6, - object_ref arg7, - object_ref arg8) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5, + object_ref const arg6, + object_ref const arg7, + object_ref const arg8) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5, - object_ref arg6, - object_ref arg7, - object_ref arg8, - object_ref arg9) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5, + object_ref const arg6, + object_ref const arg7, + object_ref const arg8, + object_ref const arg9) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } - object_ref native_function_wrapper::call(object_ref arg1, - object_ref arg2, - object_ref arg3, - object_ref arg4, - object_ref arg5, - object_ref arg6, - object_ref arg7, - object_ref arg8, - object_ref arg9, - object_ref arg10) + object_ref native_function_wrapper::call(object_ref const arg1, + object_ref const arg2, + object_ref const arg3, + object_ref const arg4, + object_ref const arg5, + object_ref const arg6, + object_ref const arg7, + object_ref const arg8, + object_ref const arg9, + object_ref const arg10) { return apply_function(*this, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp index 7603e8e3e..cea169687 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp @@ -12,13 +12,13 @@ namespace jank::runtime::obj } native_vector_sequence::native_vector_sequence(native_vector &&data) - : data{ std::move(data) } + : data{ jtl::move(data) } { jank_debug_assert(!this->data.empty()); } native_vector_sequence::native_vector_sequence(native_vector &&data, usize index) - : data{ std::move(data) } + : data{ jtl::move(data) } , index{ index } { jank_debug_assert(!this->data.empty()); @@ -26,7 +26,7 @@ namespace jank::runtime::obj native_vector_sequence::native_vector_sequence(jtl::option const &meta, native_vector &&data) - : data{ std::move(data) } + : data{ jtl::move(data) } , meta{ meta } { } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/nil.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/nil.cpp index 76fb5940e..226ec4e78 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/nil.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/nil.cpp @@ -50,12 +50,12 @@ namespace jank::runtime::obj return fallback; } - object_ref nil::get_entry(object_ref) + object_ref nil::get_entry(object_ref const) { return &base; } - bool nil::contains(object_ref) const + bool nil::contains(object_ref const) const { return false; } @@ -108,18 +108,9 @@ namespace jank::runtime return lhs->type != object_type::nil; } - static obj::nil_ref nil_const() + obj::nil_ref jank_nil() { - static obj::nil n; + static obj::nil n{}; return &n; } - - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - obj::nil_ref jank_nil{ nil_const() }; - - namespace detail - { - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - obj::nil *jank_nil_ptr{ nil_const().data }; - } } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_array_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_array_map.cpp index 7b40f1e9d..6bee67e1a 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_array_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_array_map.cpp @@ -29,7 +29,7 @@ namespace jank::runtime::obj object_ref persistent_array_map::get(object_ref const key) const { - return data.find(key).unwrap_or(jank_nil); + return data.find(key).unwrap_or(jank_nil()); } object_ref persistent_array_map::get(object_ref const key, object_ref const fallback) const @@ -44,7 +44,7 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, res.unwrap()); } - return jank_nil; + return jank_nil(); } bool persistent_array_map::contains(object_ref const key) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_map.cpp index 406a1deec..c3f0e5d8b 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_map.cpp @@ -40,6 +40,12 @@ namespace jank::runtime::obj { } + persistent_hash_map_ref persistent_hash_map::empty() + { + static auto const ret(make_box()); + return ret; + } + persistent_hash_map_ref persistent_hash_map::create_from_seq(object_ref const seq) { return make_box(visit_seqable( @@ -73,7 +79,7 @@ namespace jank::runtime::obj { return *res; } - return jank_nil; + return jank_nil(); } object_ref persistent_hash_map::get(object_ref const key, object_ref const fallback) const @@ -93,7 +99,7 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, *res); } - return jank_nil; + return jank_nil(); } bool persistent_hash_map::contains(object_ref const key) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_set.cpp index 1890c9651..4225904c3 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_hash_set.cpp @@ -55,7 +55,7 @@ namespace jank::runtime::obj return false; } - for(auto const entry : data) + for(auto const &entry : data) { if(!typed_o->contains(entry)) { @@ -133,7 +133,7 @@ namespace jank::runtime::obj auto const found(data.find(o)); if(!found) { - return jank_nil; + return jank_nil(); } return *found; } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp index 87709932e..a17275b5d 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp @@ -114,7 +114,7 @@ namespace jank::runtime::obj return data.size(); } - persistent_list_ref persistent_list::conj(object_ref head) const + persistent_list_ref persistent_list::conj(object_ref const head) const { auto l(data.conj(head)); auto ret(make_box(meta, std::move(l))); @@ -126,7 +126,7 @@ namespace jank::runtime::obj auto const first(data.first()); if(first.is_none()) { - return jank_nil; + return jank_nil(); } return first.unwrap(); } @@ -161,7 +161,7 @@ namespace jank::runtime::obj object_ref persistent_list::peek() const { - return data.first().unwrap_or(jank_nil); + return data.first().unwrap_or(jank_nil()); } persistent_list_ref persistent_list::pop() const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp index 23fbbea2d..7e0f980a9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp @@ -40,7 +40,7 @@ namespace jank::runtime::obj { return make_box(visit_object( [](auto const typed_seq) -> persistent_sorted_map::value_type { - using T = typename decltype(typed_seq)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(behavior::seqable) { @@ -56,9 +56,9 @@ namespace jank::runtime::obj typed_seq->to_string()) }; } auto const val(*it); - transient.insert_or_assign(key, val); + transient[key] = val; } - return transient.persistent(); + return transient; } else { @@ -75,7 +75,7 @@ namespace jank::runtime::obj { return res->second; } - return jank_nil; + return jank_nil(); } object_ref persistent_sorted_map::get(object_ref const key, object_ref const fallback) const @@ -95,24 +95,26 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, res->second); } - return jank_nil; + return jank_nil(); } bool persistent_sorted_map::contains(object_ref const key) const { - return data.find(key) != data.end(); + return data.contains(key); } persistent_sorted_map_ref persistent_sorted_map::assoc(object_ref const key, object_ref const val) const { - auto copy(data.insert_or_assign(key, val)); + auto copy(data); + copy[key] = val; return make_box(meta, std::move(copy)); } persistent_sorted_map_ref persistent_sorted_map::dissoc(object_ref const key) const { - auto copy(data.erase_key(key)); + auto copy(data); + copy.erase(key); return make_box(meta, std::move(copy)); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp index 2516fc267..1f53e2bbf 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp @@ -41,9 +41,9 @@ namespace jank::runtime::obj runtime::detail::native_transient_sorted_set transient; for(auto const e : make_sequence_range(typed_seq)) { - transient.insert_v(e); + transient.insert(e); } - return transient.persistent(); + return transient; }, seq)); } @@ -62,7 +62,7 @@ namespace jank::runtime::obj return false; } - for(auto const entry : data) + for(auto const &entry : data) { if(!typed_o->contains(entry)) { @@ -130,8 +130,9 @@ namespace jank::runtime::obj persistent_sorted_set_ref persistent_sorted_set::conj(object_ref const head) const { - auto set(data.insert_v(head)); - auto ret(make_box(meta, std::move(set))); + auto copy(data); + copy.insert(head); + auto ret(make_box(meta, std::move(copy))); return ret; } @@ -140,9 +141,9 @@ namespace jank::runtime::obj auto const found(data.find(o)); if(found != data.end()) { - return found.get(); + return *found; } - return jank_nil; + return jank_nil(); } transient_sorted_set_ref persistent_sorted_set::to_transient() const @@ -152,13 +153,14 @@ namespace jank::runtime::obj bool persistent_sorted_set::contains(object_ref const o) const { - return data.find(o) != data.end(); + return data.contains(o); } persistent_sorted_set_ref persistent_sorted_set::disj(object_ref const o) const { - auto set(data.erase_key(o)); - auto ret(make_box(meta, std::move(set))); + auto copy(data); + copy.erase(o); + auto ret(make_box(meta, std::move(copy))); return ret; } } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_string.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_string.cpp index 7221ddef5..e06d9c195 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_string.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_string.cpp @@ -62,7 +62,7 @@ namespace jank::runtime::obj object_ref persistent_string::get(object_ref const key) const { - return get(key, jank_nil); + return get(key, jank_nil()); } object_ref persistent_string::get(object_ref const key, object_ref const fallback) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_vector.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_vector.cpp index 53b5e200d..d5d67a667 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_vector.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_vector.cpp @@ -169,7 +169,7 @@ namespace jank::runtime::obj return data.size(); } - persistent_vector_ref persistent_vector::conj(object_ref head) const + persistent_vector_ref persistent_vector::conj(object_ref const head) const { auto vec(data.push_back(head)); auto ret(make_box(meta, std::move(vec))); @@ -196,7 +196,7 @@ namespace jank::runtime::obj object_ref persistent_vector::get(object_ref const key) const { - return get(key, jank_nil); + return get(key, jank_nil()); } object_ref persistent_vector::get(object_ref const key, object_ref const fallback) const @@ -223,14 +223,14 @@ namespace jank::runtime::obj auto const i(expect_object(key)->data); if(i < 0 || data.size() <= static_cast(i)) { - return jank_nil; + return jank_nil(); } /* TODO: Map entry type? */ return make_box(std::in_place, key, data[i]); } else { - return jank_nil; + return jank_nil(); } } @@ -281,7 +281,7 @@ namespace jank::runtime::obj { if(data.empty()) { - return jank_nil; + return jank_nil(); } return data[data.size() - 1]; diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/range.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/range.cpp index 626e9601d..70fa102c9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/range.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/range.cpp @@ -59,7 +59,7 @@ namespace jank::runtime::obj object_ref const step, range::bounds_check_t const bounds_check, array_chunk_ref const chunk, - range_ptr const chunk_next) + range_ref const chunk_next) : start{ start } , end{ end } , step{ step } @@ -102,12 +102,12 @@ namespace jank::runtime::obj : static_cast(negative_step_bounds_check)); } - range_ptr range::seq() + range_ref range::seq() { return this; } - range_ptr range::fresh_seq() const + range_ref range::fresh_seq() const { return make_box(start, end, step, bounds_check); } @@ -150,7 +150,7 @@ namespace jank::runtime::obj chunk_next = make_box(val, end, step, bounds_check); } - range_ptr range::next() const + range_ref range::next() const { if(cached_next.is_some()) { @@ -172,7 +172,7 @@ namespace jank::runtime::obj return chunked_next(); } - range_ptr range::next_in_place() + range_ref range::next_in_place() { force_chunk(); if(chunk->count() > 1) @@ -190,7 +190,7 @@ namespace jank::runtime::obj return chunk; } - range_ptr range::chunked_next() const + range_ref range::chunked_next() const { force_chunk(); if(chunk_next.is_nil()) @@ -230,7 +230,7 @@ namespace jank::runtime::obj return hash::ordered(&base); } - range_ptr range::with_meta(object_ref const m) const + range_ref range::with_meta(object_ref const m) const { auto const meta(behavior::detail::validate_meta(m)); auto ret(fresh_seq()); diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/symbol.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/symbol.cpp index 3461decde..b219741f9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/symbol.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/symbol.cpp @@ -194,14 +194,14 @@ namespace std } size_t hash::operator()( - jank::runtime::obj::symbol_ref const &o) const noexcept + jank::runtime::obj::symbol_ref const o) const noexcept { return o->to_hash(); } bool equal_to::operator()( - jank::runtime::obj::symbol_ref const &lhs, - jank::runtime::obj::symbol_ref const &rhs) const noexcept + jank::runtime::obj::symbol_ref const lhs, + jank::runtime::obj::symbol_ref const rhs) const noexcept { if(lhs.is_nil()) { diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/tagged_literal.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/tagged_literal.cpp index eb05c786b..aa184c0b1 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/tagged_literal.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/tagged_literal.cpp @@ -26,8 +26,7 @@ namespace jank::runtime::obj return runtime::equal(tag, s->tag) && runtime::equal(form, s->form); } - static void - to_string_impl(object_ref const &tag, object_ref const &form, jtl::string_builder &buff) + static void to_string_impl(object_ref const tag, object_ref const form, jtl::string_builder &buff) { buff('#'); runtime::to_string(tag, buff); @@ -82,7 +81,7 @@ namespace jank::runtime::obj object_ref tagged_literal::get(object_ref const key) const { - return get(key, jank_nil); + return get(key, jank_nil()); } object_ref tagged_literal::get_entry(object_ref const key) const @@ -100,7 +99,7 @@ namespace jank::runtime::obj return make_box(std::in_place, form_kw, form); } - return jank_nil; + return jank_nil(); } bool tagged_literal::contains(object_ref const key) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_array_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_array_map.cpp index edd947926..d923a616d 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_array_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_array_map.cpp @@ -64,7 +64,7 @@ namespace jank::runtime::obj object_ref transient_array_map::get(object_ref const key) const { assert_active(); - return data.find(key).unwrap_or(jank_nil); + return data.find(key).unwrap_or(jank_nil()); } object_ref transient_array_map::get(object_ref const key, object_ref const fallback) const @@ -79,7 +79,7 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, res.unwrap()); } - return jank_nil; + return jank_nil(); } bool transient_array_map::contains(object_ref const key) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_map.cpp index 538a6be5c..9001a44a4 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_map.cpp @@ -81,7 +81,7 @@ namespace jank::runtime::obj { return *res; } - return jank_nil; + return jank_nil(); } object_ref transient_hash_map::get(object_ref const key, object_ref const fallback) const @@ -103,7 +103,7 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, *res); } - return jank_nil; + return jank_nil(); } bool transient_hash_map::contains(object_ref const key) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_set.cpp index c254e8791..9d6e927ba 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_hash_set.cpp @@ -81,7 +81,7 @@ namespace jank::runtime::obj auto const found(data.find(elem)); if(!found) { - return jank_nil; + return jank_nil(); } return *found; } @@ -110,7 +110,7 @@ namespace jank::runtime::obj object_ref transient_hash_set::get_entry(object_ref const elem) const { auto const found = call(elem); - auto const nil(jank_nil); + auto const nil(jank_nil()); if(found == nil) { return nil; diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp index 7fbb68553..9a7c9f994 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp @@ -9,17 +9,12 @@ namespace jank::runtime::obj { - transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d) - : data{ std::move(d).transient() } - { - } - transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map const &d) - : data{ d.transient() } + : data{ d } { } - transient_sorted_map::transient_sorted_map(runtime::detail::native_transient_sorted_map &&d) + transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d) : data{ std::move(d) } { } @@ -72,7 +67,7 @@ namespace jank::runtime::obj { return res->second; } - return jank_nil; + return jank_nil(); } object_ref transient_sorted_map::get(object_ref const key, object_ref const fallback) const @@ -94,27 +89,27 @@ namespace jank::runtime::obj { return make_box(std::in_place, key, res->second); } - return jank_nil; + return jank_nil(); } bool transient_sorted_map::contains(object_ref const key) const { assert_active(); - return data.find(key) != data.end(); + return data.contains(key); } transient_sorted_map_ref transient_sorted_map::assoc_in_place(object_ref const key, object_ref const val) { assert_active(); - data.insert_or_assign(key, val); + data[key] = val; return this; } transient_sorted_map_ref transient_sorted_map::dissoc_in_place(object_ref const key) { assert_active(); - data.erase_key(key); + data.erase(key); return this; } @@ -151,7 +146,7 @@ namespace jank::runtime::obj { assert_active(); active = false; - return make_box(std::move(data).persistent()); + return make_box(std::move(data)); } object_ref transient_sorted_map::call(object_ref const o) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp index 0e92a615a..e727dbc3f 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp @@ -6,17 +6,12 @@ namespace jank::runtime::obj { - transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d) - : data{ std::move(d).transient() } - { - } - transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set const &d) - : data{ d.transient() } + : data{ d } { } - transient_sorted_set::transient_sorted_set(runtime::detail::native_transient_sorted_set &&d) + transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d) : data{ std::move(d) } { } @@ -64,7 +59,7 @@ namespace jank::runtime::obj transient_sorted_set_ref transient_sorted_set::conj_in_place(object_ref const elem) { assert_active(); - data.insert_v(elem); + data.insert(elem); return this; } @@ -72,7 +67,7 @@ namespace jank::runtime::obj { assert_active(); active = false; - return make_box(data.persistent()); + return make_box(data); } object_ref transient_sorted_set::call(object_ref const elem) @@ -81,9 +76,9 @@ namespace jank::runtime::obj auto const found(data.find(elem)); if(found != data.end()) { - return found.get(); + return *found; } - return jank_nil; + return jank_nil(); } object_ref transient_sorted_set::call(object_ref const elem, object_ref const fallback) @@ -92,7 +87,7 @@ namespace jank::runtime::obj auto const found(data.find(elem)); if(found != data.end()) { - return found.get(); + return *found; } return fallback; } @@ -109,11 +104,10 @@ namespace jank::runtime::obj object_ref transient_sorted_set::get_entry(object_ref const elem) { - auto const found = call(elem); - auto const nil(jank_nil); - if(found == nil) + auto found{ call(elem) }; + if(found == jank_nil()) { - return nil; + return found; } return make_box(std::in_place, found, found); @@ -122,13 +116,13 @@ namespace jank::runtime::obj bool transient_sorted_set::contains(object_ref const elem) const { assert_active(); - return data.find(elem) != data.end(); + return data.contains(elem); } transient_sorted_set_ref transient_sorted_set::disjoin_in_place(object_ref const elem) { assert_active(); - data.erase_key(elem); + data.erase(elem); return this; } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_vector.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_vector.cpp index 4c9ce26a2..c90ea73d8 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_vector.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_vector.cpp @@ -107,7 +107,7 @@ namespace jank::runtime::obj auto const i(expect_object(idx)->data); if(i < 0 || data.size() <= static_cast(i)) { - return jank_nil; + return jank_nil(); } return data[i]; @@ -146,7 +146,7 @@ namespace jank::runtime::obj auto const i(expect_object(idx)->data); if(i < 0 || data.size() <= static_cast(i)) { - return jank_nil; + return jank_nil(); } /* TODO: Map entry type? */ return make_box(std::in_place, idx, data[i]); diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/uuid.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/uuid.cpp index 38717e840..ef9634ebb 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/uuid.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/uuid.cpp @@ -17,7 +17,7 @@ namespace jank::runtime::obj static jtl::ref from_string(jtl::immutable_string const &s) { - auto const result = uuids::uuid::from_string(s.c_str()); + auto const result{ uuids::uuid::from_string(s.c_str()) }; if(result) { return jtl::make_ref(result.value()); diff --git a/compiler+runtime/src/cpp/jank/runtime/object.cpp b/compiler+runtime/src/cpp/jank/runtime/object.cpp index 89878309e..af12fae2e 100644 --- a/compiler+runtime/src/cpp/jank/runtime/object.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/object.cpp @@ -2,9 +2,45 @@ #include #include #include +#include namespace jank::runtime { + object::object(object const &rhs) noexcept + : type{ rhs.type } + { + } + + object::object(object &&rhs) noexcept + : type{ rhs.type } + { + } + + object::object(object_type const type) noexcept + : type{ type } + { + } + + object &object::operator=(object const &rhs) noexcept + { + if(this == &rhs) + { + return *this; + } + type = rhs.type; + return *this; + } + + object &object::operator=(object &&rhs) noexcept + { + if(this == &rhs) + { + return *this; + } + type = rhs.type; + return *this; + } + bool very_equal_to::operator()(object_ref const lhs, object_ref const rhs) const noexcept { if(lhs->type != rhs->type) @@ -27,23 +63,23 @@ namespace jank::runtime namespace std { - using namespace jank; - using namespace jank::runtime; - - size_t hash::operator()(object_ref const o) const noexcept + size_t + hash::operator()(jank::runtime::object_ref const o) const noexcept { return jank::hash::visit(o.data); } - size_t hash::operator()(object const &o) const noexcept + size_t hash::operator()(jank::runtime::object const &o) const noexcept { - return jank::hash::visit(const_cast(&o)); + return jank::hash::visit(const_cast(&o)); } bool // NOLINTNEXTLINE(bugprone-exception-escape): TODO: Sort this out. - equal_to::operator()(object_ref const lhs, object_ref const rhs) const noexcept + equal_to::operator()( + jank::runtime::object_ref const lhs, + jank::runtime::object_ref const rhs) const noexcept { - return equal(lhs, rhs); + return jank::runtime::equal(lhs, rhs); } } diff --git a/compiler+runtime/src/cpp/jank/runtime/perf.cpp b/compiler+runtime/src/cpp/jank/runtime/perf.cpp index eff588226..08d8be739 100644 --- a/compiler+runtime/src/cpp/jank/runtime/perf.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/perf.cpp @@ -14,7 +14,7 @@ namespace jank::runtime::perf auto const label_str(to_string(label)); visit_object( [](auto const typed_f, jtl::immutable_string const &label) { - using T = typename decltype(typed_f)::value_type; + using T = typename jtl::decay_t::value_type; if constexpr(std::is_base_of_v) { @@ -45,6 +45,6 @@ namespace jank::runtime::perf }, f, label_str); - return jank_nil; + return jank_nil(); } } diff --git a/compiler+runtime/src/cpp/jank/runtime/var.cpp b/compiler+runtime/src/cpp/jank/runtime/var.cpp index 44f739671..aca244db6 100644 --- a/compiler+runtime/src/cpp/jank/runtime/var.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/var.cpp @@ -13,22 +13,22 @@ namespace jank::runtime { - var::var(ns_ref const &n, obj::symbol_ref const &name) + var::var(ns_ref const n, obj::symbol_ref const name) : n{ n } , name{ name } , root{ make_box(this) } { } - var::var(ns_ref const &n, obj::symbol_ref const &name, object_ref const root) + var::var(ns_ref const n, obj::symbol_ref const name, object_ref const root) : n{ n } , name{ name } , root{ root } { } - var::var(ns_ref const &n, - obj::symbol_ref const &name, + var::var(ns_ref const n, + obj::symbol_ref const name, object_ref const root, bool const dynamic, bool const thread_bound) @@ -55,7 +55,7 @@ namespace jank::runtime return n == v.n && name == v.name; } - static void to_string_impl(ns_ref const n, obj::symbol_ref const &name, jtl::string_builder &buff) + static void to_string_impl(ns_ref const n, obj::symbol_ref const name, jtl::string_builder &buff) { buff("#'")(n->name->name)('/')(name->name); } @@ -143,6 +143,11 @@ namespace jank::runtime return this; } + obj::symbol_ref var::to_qualified_symbol() const + { + return make_box(n->name->name, name->name); + } + var_thread_binding_ref var::get_thread_binding() const { if(!thread_bound.load()) @@ -150,7 +155,7 @@ namespace jank::runtime return {}; } - auto &tbfs(__rt_ctx->thread_binding_frames[__rt_ctx]); + auto &tbfs(runtime::context::thread_binding_frames); if(tbfs.empty()) { return {}; @@ -244,3 +249,24 @@ namespace jank::runtime return static_cast(reinterpret_cast(this)); } } + +namespace std +{ + size_t hash::operator()(jank::runtime::var const &o) const noexcept + { + static auto hasher(std::hash{}); + return hasher(*o.name); + } + + size_t hash::operator()(jank::runtime::var_ref const o) const noexcept + { + static auto hasher(std::hash{}); + return hasher(*o->name); + } + + bool equal_to::operator()(jank::runtime::var_ref const lhs, + jank::runtime::var_ref const rhs) const noexcept + { + return lhs->equal(*rhs); + } +} diff --git a/compiler+runtime/src/cpp/jank/ui/highlight.cpp b/compiler+runtime/src/cpp/jank/ui/highlight.cpp index 7c70d3812..b22afcf11 100644 --- a/compiler+runtime/src/cpp/jank/ui/highlight.cpp +++ b/compiler+runtime/src/cpp/jank/ui/highlight.cpp @@ -10,7 +10,7 @@ namespace jank::ui using namespace ftxui; /* TODO: Also support core fns? */ - static std::set const specials{ + static native_set const specials{ "def", "fn*", "fn", "let*", "let", "loop*", "loop", "do", "if", "quote", "var", "try", "catch", "finally", "throw", "letfn*", }; diff --git a/compiler+runtime/src/cpp/jank/util/clang_format.cpp b/compiler+runtime/src/cpp/jank/util/clang_format.cpp index 820a2aaf9..07176c5cc 100644 --- a/compiler+runtime/src/cpp/jank/util/clang_format.cpp +++ b/compiler+runtime/src/cpp/jank/util/clang_format.cpp @@ -68,6 +68,7 @@ namespace jank::util { return err(llvm::toString(formatted_code.takeError())); } - return ok(jtl::immutable_string{ *formatted_code }); + jtl::immutable_string const ret{ *formatted_code }; + return ok(ret); } } diff --git a/compiler+runtime/src/cpp/jank/util/cli.cpp b/compiler+runtime/src/cpp/jank/util/cli.cpp index e48405128..93d90b16b 100644 --- a/compiler+runtime/src/cpp/jank/util/cli.cpp +++ b/compiler+runtime/src/cpp/jank/util/cli.cpp @@ -1,189 +1,404 @@ -#include - #include -#include +#include #include +#include namespace jank::util::cli { /* NOLINTNEXTLINE */ options opts; - static std::string make_default(std::string const &input) - { - return "default: " + input; - } + using flag_it = native_vector::const_iterator; - jtl::result parse(int const argc, char const **argv) + static bool check_flag(flag_it &it, + flag_it const end, + jtl::immutable_string &out, + jtl::immutable_string const &short_flag, + jtl::immutable_string const &long_flag, + bool const needs_value) { - CLI::App cli{ "jank compiler" }; - - cli.set_help_flag("-h,--help", "Print this help message and exit."); - - /* Runtime. */ - cli.add_option( - "--module-path", - opts.module_path, - util::format( - "A {} separated list of directories, JAR files, and ZIP files to search for modules.", - runtime::module::loader::module_separator_name)); - cli.add_flag("--profile", opts.profiler_enabled, "Enable compiler and runtime profiling."); - cli - .add_option("--profile-output", - opts.profiler_file, - "The file to write profile entries (will be overwritten).") - ->default_str(make_default(opts.profiler_file)); - cli.add_flag("--perf", opts.perf_profiling_enabled, "Enable Linux perf event sampling."); - cli.add_flag("--gc-incremental", opts.gc_incremental, "Enable incremental GC collection."); - cli.add_flag("--debug", opts.debug, "Enable debug symbol generation for generated code."); - cli.add_flag("--direct-call", - opts.direct_call, - "Elides the dereferencing of vars for improved performance."); - cli - .add_option("-O,--optimization", - opts.optimization_level, - "The optimization level to use for AOT compilation.") - /* TODO: This does not validate. */ - ->check(CLI::Range(0, 3)); - - std::map const codegen_types{ - { "llvm_ir", codegen_type::llvm_ir }, - { "cpp", codegen_type::cpp } - }; - cli.add_option("--codegen", opts.codegen, "The type of code generation to use.") - ->transform(CLI::CheckedTransformer(codegen_types).description("{llvm_ir,cpp}")) - ->default_str(make_default("llvm_ir")); - - /* Native dependencies. */ - cli.add_option("-I,--include-dir", - opts.include_dirs, - "Absolute or relative path to the directory for includes resolution. Can be " - "specified multiple times."); - cli.add_option("-L,--library-dir", - opts.library_dirs, - "Absolute or relative path to the directory to search dynamic libraries in. " - "Can be specified multiple times."); - cli.add_option("-D,--define-macro", - opts.define_macros, - "Defines macro value, sets to 1 if omitted. Can be specified multiple times."); - cli.add_option("-l", - opts.libs, - "Library identifiers, absolute or relative paths eg. -lfoo for libfoo.so or " - "foo.dylib. Can be specified multiple times."); - - /* Run subcommand. */ - auto &cli_run(*cli.add_subcommand("run", "Load and run a file.")); - cli_run.fallthrough(); - cli_run.add_option("file", opts.target_file, "The entrypoint file.") - ->check(CLI::ExistingFile) - ->required(); - - /* Compile module subcommand. */ - auto &cli_compile_module( - *cli.add_subcommand("compile-module", - "Compile a module (given its namespace) and its dependencies.")); - cli_compile_module.fallthrough(); - cli_compile_module - .add_option("--runtime", opts.target_runtime, "The runtime of the compiled program.") - ->check(CLI::IsMember({ "dynamic", "static" })) - ->default_str(make_default("dynamic")); - cli_compile_module - .add_option("module", opts.target_module, "Module to compile (must be on the module path).") - ->required(); - cli_compile_module.add_option("-o", opts.output_object_filename, "Output object file name."); - - /* REPL subcommand. */ - auto &cli_repl(*cli.add_subcommand("repl", "Start up a terminal REPL and optional server.")); - cli_repl.fallthrough(); - cli_repl.add_option("module", opts.target_module, "The entrypoint module."); - cli_repl.add_flag("--server", opts.repl_server, "Start an nREPL server."); - - /* C++ REPL subcommand. */ - auto &cli_cpp_repl(*cli.add_subcommand("cpp-repl", "Start up a terminal C++ REPL.")); - - /* Run-main subcommand. */ - auto &cli_run_main(*cli.add_subcommand("run-main", "Load and execute -main.")); - cli_run_main.fallthrough(); - cli_run_main - .add_option("module", - opts.target_module, - "The entrypoint module (must be on the module path.") - ->required(); - - /* Compile subcommand. */ - auto &cli_compile(*cli.add_subcommand( - "compile", - "Ahead of time compile project with entrypoint module containing -main.")); - cli_compile.fallthrough(); - cli_compile - .add_option("--runtime", opts.target_runtime, "The runtime of the compiled program.") - ->check(CLI::IsMember({ "dynamic", "static" })) - ->default_str(make_default(opts.target_runtime)); - cli_compile.add_option("-o", opts.output_filename, "Output executable name.") - ->default_str(make_default(opts.output_filename)); - cli_compile.add_option("module", opts.target_module, "The entrypoint module.")->required(); - - /* Health check subcommand. */ - auto &cli_check_health( - *cli.add_subcommand("check-health", "Provide a status report on the jank installation.")); - cli_check_health.fallthrough(); - - cli.require_subcommand(1); - cli.failure_message(CLI::FailureMessage::help); - cli.allow_extras(); - - try + if(*it == long_flag) { - cli.parse(argc, argv); + ++it; + if(needs_value) + { + if(it == end) + { + throw util::format("The '{}' flag requires an argument, but one was not provided.", + long_flag); + } + out = *it; + } + return true; } - catch(CLI::ParseError const &e) + else if(!short_flag.empty() && (*it).starts_with(short_flag)) { - return err(cli.exit(e)); + if(needs_value) + { + out = (*it).substr(short_flag.size()); + if(out.empty()) + { + ++it; + if(it == end) + { + throw util::format("The '{}' flag requires an argument, but one was not provided.", + short_flag); + } + out = *it; + } + } + return true; } + return false; + } - if(cli.remaining_size() >= 0) - { - opts.extra_opts = cli.remaining(); - } + static bool check_flag(flag_it &it, + flag_it const end, + jtl::immutable_string &out, + jtl::immutable_string const &long_flag, + bool const needs_value) + { + return check_flag(it, end, out, "", long_flag, needs_value); + } - if(cli.got_subcommand(&cli_run)) - { - opts.command = command::run; - } - else if(cli.got_subcommand(&cli_compile_module)) - { - opts.command = command::compile_module; - } - else if(cli.got_subcommand(&cli_repl)) - { - opts.command = command::repl; - } - else if(cli.got_subcommand(&cli_cpp_repl)) + static jtl::immutable_string + get_positional_arg(jtl::immutable_string const &command, + jtl::immutable_string const &name, + native_deque &pending_positional_args) + { + if(pending_positional_args.empty()) { - opts.command = command::cpp_repl; + throw util::format("Please provide the {} command a {}.", command, name); } - else if(cli.got_subcommand(&cli_run_main)) + + jtl::immutable_string ret{ pending_positional_args.front() }; + pending_positional_args.pop_front(); + return ret; + } + + static bool check_pending_flag( + jtl::immutable_string const &long_flag, + jtl::immutable_string &out, + native_unordered_map &pending_flags) + { + auto const found{ pending_flags.find(long_flag) }; + if(found == pending_flags.end()) { - opts.command = command::run_main; + return false; } - else if(cli.got_subcommand(&cli_compile)) + out = found->second; + pending_flags.erase(found); + return true; + } + + static void show_help() + { + /* TODO: Support command help. */ + /* TODO: Provide examples. */ + /* TODO: Improve layout and required arg indicators. */ + /* TODO: Colorize output. */ + util::println(R"( +jank compiler {} + +The jank compiler is used to evaluate and compile jank, Clojure, and C++ sources. + +COMMANDS + run Load and run a file. + compile-module Compile a module (given its namespace) and its dependencies. + repl Start up a terminal REPL and optional server. + cpp-repl Start up a terminal C++ REPL. + run-main Load and execute -main. + compile Ahead of time compile project with entrypoint module containing + -main. + check-health Provide a status report on the jank installation. + +OPTIONS + -h, --help Print this help message and exit. + --module-path + A colon separated list of directories, JAR files, and ZIP files + to search for modules. + --profile Enable compiler and runtime profiling. + --profile-output [default: jank.profile] + The file to write profile entries (will be overwritten). + --perf Enable Linux perf event sampling. + --gc-incremental Enable incremental GC collection. + --debug Enable debug symbol generation for generated code. + --direct-call Elides the dereferencing of vars for improved performance. + -O, --optimization <0 - 3> + The optimization level to use for AOT compilation. + --codegen [default: cpp] + The type of code generation to use. + -I, --include-dir + Absolute or relative path to the directory for includes + resolution. Can be specified multiple times. + -D, --define-macro + Defines a macro. The value will be 1, if omitted. Can be specified + multiple times. + -L, --library-dir + Absolute or relative path to the directory to search dynamic + libraries in. Can be specified multiple times. + -l Library identifiers, absolute or relative paths eg. -lfoo for + libfoo.so or foo.dylib. Can be specified multiple times.)", + JANK_VERSION); + std::exit(1); + } + + jtl::result parse_opts(int const argc, char const **argv) + { + auto const flags{ parse_into_vector(argc, argv) }; + + static native_unordered_map valid_commands{ + { "run", command::run }, + { "run-main", command::run_main }, + { "repl", command::repl }, + { "cpp-repl", command::cpp_repl }, + { "compile-module", command::compile_module }, + { "compile", command::compile }, + { "check-health", command::check_health } + }; + + /* The flow of this is broken into the following steps. + * + * 1. Parse known flags into changes to the `opts` global + * 2. Determine the first positional arg to be the command + * 3. Store other positional args to be handled later (pending) + * 4. Store unhandled flags to be handled later (pending) + * 5. Once we've gone through everything, use the command we have + * to pick apart the pending flags and positional args + * 6. Complain about anything left over */ + try { - opts.command = command::compile; + native_unordered_map pending_flags; + native_deque pending_positional_args; + auto const end{ flags.end() }; + jtl::immutable_string command; + jtl::immutable_string value; + + for(auto it{ flags.begin() }; it != end; ++it) + { + /**** These are all of the global flags which can apply to any command. ****/ + if(check_flag(it, end, value, "--", false)) + { + /* This implies that everything coming after is meant for the running program. */ + std::copy(it, end, std::back_inserter(opts.extra_opts)); + break; + } + else if(check_flag(it, end, value, "-h", "--help", false)) + { + show_help(); + } + else if(check_flag(it, end, value, "--module-path", true)) + { + opts.module_path = value; + } + else if(check_flag(it, end, value, "--profile", false)) + { + opts.profiler_enabled = true; + } + else if(check_flag(it, end, value, "--profile-output", true)) + { + opts.profiler_file = value; + } + else if(check_flag(it, end, value, "--perf", false)) + { + opts.perf_profiling_enabled = true; + } + else if(check_flag(it, end, value, "--direct-call", false)) + { + opts.direct_call = true; + } + else if(check_flag(it, end, value, "-O", "--optimization", true)) + { + if(value == "0") + { + opts.optimization_level = 0; + } + else if(value == "1") + { + opts.optimization_level = 1; + } + else if(value == "2") + { + opts.optimization_level = 2; + } + else if(value == "3") + { + opts.optimization_level = 3; + } + else + { + throw util::format("Invalid optimization level '{}'.", value); + } + } + else if(check_flag(it, end, value, "--codegen", true)) + { + if(value == "cpp") + { + opts.codegen = codegen_type::cpp; + } + else if(value == "llvm-ir") + { + opts.codegen = codegen_type::llvm_ir; + } + else + { + throw util::format("Invalid codegen type '{}'.", value); + } + } + else if(check_flag(it, end, value, "-I", "--include-dir", true)) + { + opts.include_dirs.emplace_back(value); + } + else if(check_flag(it, end, value, "-D", "--define-macro", true)) + { + opts.define_macros.emplace_back(value); + } + else if(check_flag(it, end, value, "-L", "--library-dir", true)) + { + opts.library_dirs.emplace_back(value); + } + else if(check_flag(it, end, value, "-l", "--link", true)) + { + opts.libs.emplace_back(value); + } + + /**** These are command-specific flags which we will store until we know the command. ****/ + else if(check_flag(it, end, value, "-o", "--output", true)) + { + pending_flags["--output"] = value; + } + else if(check_flag(it, end, value, "--output-target", true)) + { + pending_flags["--output-target"] = value; + } + else if(check_flag(it, end, value, "--runtime", true)) + { + pending_flags["--runtime"] = value; + } + else if(command.empty()) + { + command = *it; + auto const found_command{ valid_commands.find(command) }; + if(found_command == valid_commands.end()) + { + throw util::format("Invalid command '{}'.", command); + } + opts.command = found_command->second; + } + else + { + pending_positional_args.emplace_back(*it); + } + } + + if(command.empty()) + { + show_help(); + } + + /* Now process all pending flags, depending on our command. */ + if(command == "run") + { + opts.target_file = get_positional_arg(command, "file", pending_positional_args); + } + else if(command == "run-main") + { + opts.target_module = get_positional_arg(command, "module", pending_positional_args); + } + else if(command == "repl") + { + if(!pending_positional_args.empty()) + { + opts.target_module = get_positional_arg(command, "module", pending_positional_args); + } + } + else if(command == "compile-module" || command == "compile") + { + opts.target_module = get_positional_arg(command, "module", pending_positional_args); + if(check_pending_flag("--output", value, pending_flags)) + { + if(command == "compile-module") + { + opts.output_module_filename = value; + } + else + { + opts.output_filename = value; + } + } + if(check_pending_flag("--output-target", value, pending_flags)) + { + if(value == "llvm-ir") + { + opts.output_target = compilation_target::llvm_ir; + } + else if(value == "cpp") + { + opts.output_target = compilation_target::cpp; + } + else if(value == "object") + { + opts.output_target = compilation_target::object; + } + else + { + throw util::format("Invalid output type '{}'.", value); + } + } + if(check_pending_flag("--runtime", value, pending_flags)) + { + opts.target_file = value; + } + + if(command == "compile" && opts.output_target == compilation_target::unspecified) + { + opts.output_target = compilation_target::object; + } + } + + /* If we have any more pending flags at this point, they don't belong. */ + if(!pending_flags.empty()) + { + jtl::string_builder sb; + util::format_to(sb, "These flags were not used:"); + for(auto const &flag : pending_flags) + { + util::format_to(sb, " {}", flag.first); + if(!flag.second.empty()) + { + util::format_to(sb, " {}", flag.second); + } + } + error::warn(sb.release()); + } + else if(!pending_positional_args.empty()) + { + jtl::string_builder sb; + util::format_to(sb, "Extra positional args:"); + for(auto const &arg : pending_positional_args) + { + util::format_to(sb, " {}", arg); + } + throw sb.release(); + } } - else if(cli.got_subcommand(&cli_check_health)) + catch(jtl::immutable_string const &msg) { - opts.command = command::check_health; + util::println(stderr, "error: {}", msg); + return err(1); } return ok(); } - std::vector parse_empty(int const argc, char const **argv) + native_vector parse_into_vector(int const argc, char const **argv) { - CLI::App cli{ "jank default cli" }; - cli.allow_extras(); - cli.parse(argc, argv); - - return cli.remaining(); + native_vector ret; + ret.reserve(argc - 1); + for(int i{ 1 }; i < argc; ++i) + { + ret.emplace_back(argv[i]); + } + return ret; } } diff --git a/compiler+runtime/src/cpp/jank/util/environment.cpp b/compiler+runtime/src/cpp/jank/util/environment.cpp index f21fcc197..fff692f50 100644 --- a/compiler+runtime/src/cpp/jank/util/environment.cpp +++ b/compiler+runtime/src/cpp/jank/util/environment.cpp @@ -173,8 +173,14 @@ namespace jank::util auto const dev_build{ jank_path.filename() == "build" && jank_path.parent_path().filename() == "compiler+runtime" }; + if(dev_build) + { + auto const compiler_runtime{ jank_path / ".." }; + return compiler_runtime.c_str(); + } + auto const configured_path{ (jank_path / dir) }; - if(std::filesystem::exists(configured_path) || dev_build) + if(std::filesystem::exists(configured_path)) { return configured_path.c_str(); } diff --git a/compiler+runtime/src/cpp/jank/util/try.cpp b/compiler+runtime/src/cpp/jank/util/try.cpp index 0a4430917..c50e77d98 100644 --- a/compiler+runtime/src/cpp/jank/util/try.cpp +++ b/compiler+runtime/src/cpp/jank/util/try.cpp @@ -47,7 +47,7 @@ namespace jank::util * at the start/end of each stack trace. */ static bool filter_frame(cpptrace::stacktrace_frame const &frame) { - static std::set const symbols_to_ignore{ + static native_set const symbols_to_ignore{ /* (Top) Linux exception pipework. */ "get_adjusted_ptr", "__gxx_personality_v0", diff --git a/compiler+runtime/src/cpp/jtl/panic.cpp b/compiler+runtime/src/cpp/jtl/panic.cpp index 54e48705e..c405088af 100644 --- a/compiler+runtime/src/cpp/jtl/panic.cpp +++ b/compiler+runtime/src/cpp/jtl/panic.cpp @@ -5,6 +5,7 @@ namespace jtl::detail { + [[noreturn]] void panic(char const * const msg) { jank::util::println(stderr, "Panic encountered: {}", msg); diff --git a/compiler+runtime/src/cpp/jtl/string_builder.cpp b/compiler+runtime/src/cpp/jtl/string_builder.cpp index ef7de4a32..783a1e4a0 100644 --- a/compiler+runtime/src/cpp/jtl/string_builder.cpp +++ b/compiler+runtime/src/cpp/jtl/string_builder.cpp @@ -12,16 +12,14 @@ namespace jtl using allocator_type = jank::native_allocator; using allocator_traits = std::allocator_traits; - /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - static allocator_type allocator; - static void realloc(string_builder &sb, usize const required) { auto const new_capacity{ std::bit_ceil(required) }; - /* TODO: Pointer-free GC alloc. */ - auto const new_data{ allocator_traits::allocate(allocator, new_capacity) }; + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + auto const new_data{ reinterpret_cast(malloc(new_capacity)) }; string_builder::traits_type::copy(new_data, sb.buffer, sb.pos); - allocator_traits::deallocate(allocator, sb.buffer, sb.pos); + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + free(sb.buffer); sb.buffer = new_data; sb.capacity = new_capacity; } @@ -103,7 +101,8 @@ namespace jtl string_builder::~string_builder() { - allocator_traits::deallocate(allocator, buffer, pos); + /* NOLINTNEXTLINE(cppcoreguidelines-no-malloc) */ + free(buffer); } string_builder &string_builder::operator()(bool const d) & @@ -396,6 +395,11 @@ namespace jtl return pos; } + bool string_builder::empty() const + { + return pos == 0; + } + jtl::immutable_string string_builder::release() { jank_debug_assert(pos < capacity); diff --git a/compiler+runtime/src/cpp/main.cpp b/compiler+runtime/src/cpp/main.cpp index e716a110d..9d89312b2 100644 --- a/compiler+runtime/src/cpp/main.cpp +++ b/compiler+runtime/src/cpp/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,7 @@ #include #ifdef JANK_PHASE_2 -extern "C" jank_object_ref jank_load_clojure_core(); +extern "C" void jank_load_clojure_core(); #endif namespace jank @@ -111,6 +112,63 @@ namespace jank using namespace jank; using namespace jank::runtime; + if(opts.output_target == util::cli::compilation_target::unspecified) + { + if(opts.output_module_filename.empty()) + { + opts.output_target = util::cli::compilation_target::object; + } + else + { + auto const ext{ std::filesystem::path{ opts.output_module_filename }.extension() }; + if(ext == ".ll") + { + opts.output_target = util::cli::compilation_target::llvm_ir; + } + else if(ext == ".cpp") + { + opts.output_target = util::cli::compilation_target::cpp; + } + else if(ext == ".o") + { + opts.output_target = util::cli::compilation_target::object; + } + else + { + /* TODO: Dedicated error. */ + throw error::internal_failure( + util::format("Unable to determine the output target type, given output file name '{}'. " + "If you provide a '.ll', '.cpp', or '.o' extension, this can be inferred. " + "Otherwise, please provide the --output-type flag to specify.", + opts.output_module_filename)); + } + } + } + else if(!opts.output_module_filename.empty()) + { + auto const ext{ std::filesystem::path{ opts.output_module_filename }.extension() }; + if((ext == ".ll" && opts.output_target != util::cli::compilation_target::llvm_ir) + || (ext == ".cpp" && opts.output_target != util::cli::compilation_target::cpp) + || (ext == ".o" && opts.output_target != util::cli::compilation_target::object)) + { + error::warn(util::format("The output file name '{}' has the extension '{}', but the output " + "target is '{}'. These appear to be mismatched.", + opts.output_module_filename, + ext, + util::cli::compilation_target_str(opts.output_target))); + } + } + + if(opts.output_target == util::cli::compilation_target::cpp + && opts.codegen != util::cli::codegen_type::cpp) + { + /* TODO: Dedicated error. */ + throw error::internal_failure( + util::format("Unable to output C++ when the codegen flag is set to '{}'. Please either " + "output a different target or change the codegen to C++.", + util::cli::codegen_type_str(opts.codegen))); + } + if(opts.target_module != "clojure.core") { __rt_ctx->load_module("/clojure.core", module::origin::latest).expect_ok(); @@ -168,10 +226,10 @@ namespace jank auto const error_var{ __rt_ctx->find_var("clojure.core", "*e") }; context::binding_scope const scope{ obj::persistent_hash_map::create_unique( - std::make_pair(first_res_var, jank_nil), - std::make_pair(second_res_var, jank_nil), - std::make_pair(third_res_var, jank_nil), - std::make_pair(error_var, jank_nil)) }; + std::make_pair(first_res_var, jank_nil()), + std::make_pair(second_res_var, jank_nil()), + std::make_pair(third_res_var, jank_nil()), + std::make_pair(error_var, jank_nil())) }; /* TODO: Completion. */ /* TODO: Syntax highlighting. */ @@ -286,7 +344,7 @@ namespace jank __rt_ctx->compile_module(opts.target_module).expect_ok(); jank::aot::processor const aot_prc{}; - aot_prc.compile(opts.target_module).expect_ok(); + aot_prc.build_executable(opts.target_module).expect_ok(); } } @@ -300,7 +358,7 @@ int main(int const argc, char const **argv) using namespace jank::runtime; return jank_init(argc, argv, /*init_default_ctx=*/false, [](int const argc, char const **argv) { - auto const parse_result(util::cli::parse(argc, argv)); + auto const parse_result(util::cli::parse_opts(argc, argv)); if(parse_result.is_err()) { return parse_result.expect_err(); diff --git a/compiler+runtime/src/jank/clojure/core.jank b/compiler+runtime/src/jank/clojure/core.jank index cabba7446..8dbacd855 100644 --- a/compiler+runtime/src/jank/clojure/core.jank +++ b/compiler+runtime/src/jank/clojure/core.jank @@ -38,6 +38,27 @@ (def ^:dynamic *print-readably* nil) (def ^:dynamic *read-eval* nil) +(def ^:dynamic + ^{:doc "bound in a repl thread to the most recent value printed"} + *1) + +(def ^:dynamic + ^{:doc "bound in a repl thread to the second most recent value printed"} + *2) + +(def ^:dynamic + ^{:doc "bound in a repl thread to the third most recent value printed"} + *3) + +(def ^:dynamic + ^{:doc "bound in a repl thread to the most recent exception caught by the repl"} + *e) + +(def ^:dynamic + ^{:doc "Bound to true in a repl thread"} + *repl* false) + + (cpp/raw "#include ") (cpp/raw "#include ") (cpp/raw "#include ") @@ -493,7 +514,7 @@ false)))) (def ^:private sigs - (fn* [fdecl] + (fn* sigs [fdecl] (let* [asig (fn* asig [fdecl] (let* [arglist (first fdecl) ;elide implicit macro args @@ -6608,26 +6629,6 @@ fails, attempts to require sym's namespace and retries." ;; (instance? clojure.lang.Indexed coll) (throw "TODO: port indexed?")) -(def ^:dynamic - ^{:doc "bound in a repl thread to the most recent value printed"} - *1) - -(def ^:dynamic - ^{:doc "bound in a repl thread to the second most recent value printed"} - *2) - -(def ^:dynamic - ^{:doc "bound in a repl thread to the third most recent value printed"} - *3) - -(def ^:dynamic - ^{:doc "bound in a repl thread to the most recent exception caught by the repl"} - *e) - -(def ^:dynamic - ^{:doc "Bound to true in a repl thread"} - *repl* false) - (defn trampoline "trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if diff --git a/compiler+runtime/test/bash/ahead-of-time/pass-test b/compiler+runtime/test/bash/ahead-of-time/pass-test index dde02123d..6e0229548 100755 --- a/compiler+runtime/test/bash/ahead-of-time/pass-test +++ b/compiler+runtime/test/bash/ahead-of-time/pass-test @@ -18,7 +18,7 @@ :or {optimization-flag "-O0" output-file default-output-file}}] (str "jank " optimization-flag - " --module-path=" module-path + " --module-path " module-path " compile " main-module " -o " output-file)) diff --git a/compiler+runtime/test/bash/ahead-of-time/src/jank-and-cpp-modules/my_lib.cpp b/compiler+runtime/test/bash/ahead-of-time/src/jank-and-cpp-modules/my_lib.cpp index fcd4b04d8..ae7138497 100644 --- a/compiler+runtime/test/bash/ahead-of-time/src/jank-and-cpp-modules/my_lib.cpp +++ b/compiler+runtime/test/bash/ahead-of-time/src/jank-and-cpp-modules/my_lib.cpp @@ -19,11 +19,11 @@ using namespace jank::runtime; static object_ref greet_str(object_ref name) { auto const s_obj(try_object(name)); - auto const new_str{ "Hello from cpp module, " + s_obj->to_string() + "!"}; - return make_box(new_str).erase(); + auto const new_str{ "Hello from cpp module, " + s_obj->to_string() + "!" }; + return make_box(new_str).erase().data; } -extern "C" jank_object_ref jank_load_my_lib() +extern "C" void jank_load_my_lib() { auto const ns_name{ "my-lib" }; auto const ns(__rt_ctx->intern_ns(ns_name)); @@ -41,6 +41,5 @@ extern "C" jank_object_ref jank_load_my_lib() intern_fn("greet-str", &greet_str); __rt_ctx->module_loader.set_is_loaded(ns_name); - std::cout<<"Loaded '"<eval_file(dir_entry.path().string()).unwrap_or(runtime::jank_nil)); + __rt_ctx->eval_file(dir_entry.path().string()).unwrap_or(runtime::jank_nil())); if(!expect_success) { failures.push_back({ dir_entry.path(), diff --git a/compiler+runtime/test/cpp/jank/read/lex.cpp b/compiler+runtime/test/cpp/jank/read/lex.cpp index 6dfc6b92e..bef890d82 100644 --- a/compiler+runtime/test/cpp/jank/read/lex.cpp +++ b/compiler+runtime/test/cpp/jank/read/lex.cpp @@ -153,7 +153,7 @@ namespace jank::read::lex runtime::to_code_string(runtime::__rt_ctx->current_ns_var->deref()), { offset, 1, offset + 1 }, { offset + width, 1, offset + width + 1 }, - runtime::jank_nil + runtime::jank_nil() }); } diff --git a/compiler+runtime/test/cpp/jank/read/parse.cpp b/compiler+runtime/test/cpp/jank/read/parse.cpp index 57814f2d9..8523225bc 100644 --- a/compiler+runtime/test/cpp/jank/read/parse.cpp +++ b/compiler+runtime/test/cpp/jank/read/parse.cpp @@ -39,7 +39,7 @@ namespace jank::read::parse lex::processor lp{ "nil" }; processor p{ lp.begin(), lp.end() }; auto const r(p.next()); - CHECK(equal(r.expect_ok().unwrap().ptr, jank_nil)); + CHECK(equal(r.expect_ok().unwrap().ptr, jank_nil())); CHECK(r.expect_ok().unwrap().start == lex::token{ 0, 3, lex::token_kind::nil }); CHECK(r.expect_ok().unwrap().end == r.expect_ok().unwrap().start); } @@ -992,7 +992,7 @@ namespace jank::read::parse auto const r(p.next()); CHECK(equal(r.expect_ok().unwrap().ptr, obj::persistent_array_map::empty())); auto const m{ meta(r.expect_ok().unwrap().ptr) }; - CHECK(equal(get(m, __rt_ctx->intern_keyword("foo").expect_ok()), jank_nil)); + CHECK(equal(get(m, __rt_ctx->intern_keyword("foo").expect_ok()), jank_nil())); } SUBCASE("Symbol meta for a non-metadatable target") diff --git a/compiler+runtime/test/cpp/jank/runtime/core/seq.cpp b/compiler+runtime/test/cpp/jank/runtime/core/seq.cpp index 26b019034..37bb4f315 100644 --- a/compiler+runtime/test/cpp/jank/runtime/core/seq.cpp +++ b/compiler+runtime/test/cpp/jank/runtime/core/seq.cpp @@ -12,9 +12,9 @@ namespace jank::runtime::core { TEST_CASE("sequence_equal") { - CHECK(sequence_equal(jank_nil, make_box())); - CHECK(sequence_equal(make_box(), jank_nil)); - CHECK(sequence_equal(make_box(), jank_nil)); + CHECK(sequence_equal(jank_nil(), make_box())); + CHECK(sequence_equal(make_box(), jank_nil())); + CHECK(sequence_equal(make_box(), jank_nil())); CHECK(sequence_equal(make_box(std::in_place, make_box('f')), make_box(std::in_place, make_box('f')))); CHECK(!sequence_equal(make_box(std::in_place, make_box('f')), diff --git a/compiler+runtime/test/cpp/jank/runtime/obj/persistent_string.cpp b/compiler+runtime/test/cpp/jank/runtime/obj/persistent_string.cpp index 34d631281..cc75ad9e1 100644 --- a/compiler+runtime/test/cpp/jank/runtime/obj/persistent_string.cpp +++ b/compiler+runtime/test/cpp/jank/runtime/obj/persistent_string.cpp @@ -25,9 +25,9 @@ namespace jank::runtime::obj CHECK(equal(s.get(min), min_char)); CHECK(equal(s.get(mid), mid_char)); CHECK(equal(s.get(max), max_char)); - CHECK(equal(s.get(over), jank_nil)); - CHECK(equal(s.get(under), jank_nil)); - CHECK(equal(s.get(non_int), jank_nil)); + CHECK(equal(s.get(over), jank_nil())); + CHECK(equal(s.get(under), jank_nil())); + CHECK(equal(s.get(non_int), jank_nil())); } TEST_CASE("get with fallback") { diff --git a/compiler+runtime/test/cpp/jank/runtime/obj/persistent_vector.cpp b/compiler+runtime/test/cpp/jank/runtime/obj/persistent_vector.cpp index 630192322..b17bdda7e 100644 --- a/compiler+runtime/test/cpp/jank/runtime/obj/persistent_vector.cpp +++ b/compiler+runtime/test/cpp/jank/runtime/obj/persistent_vector.cpp @@ -32,9 +32,9 @@ namespace jank::runtime::obj CHECK(equal(v->get(min), min_char)); CHECK(equal(v->get(mid), mid_char)); CHECK(equal(v->get(max), max_char)); - CHECK(equal(v->get(over), jank_nil)); - CHECK(equal(v->get(under), jank_nil)); - CHECK(equal(v->get(non_int), jank_nil)); + CHECK(equal(v->get(over), jank_nil())); + CHECK(equal(v->get(under), jank_nil())); + CHECK(equal(v->get(non_int), jank_nil())); } TEST_CASE("get with fallback") { @@ -59,9 +59,9 @@ namespace jank::runtime::obj CHECK(equal(v->get_entry(min), make_box(std::in_place, min, min_char))); CHECK(equal(v->get_entry(mid), make_box(std::in_place, mid, mid_char))); CHECK(equal(v->get_entry(max), make_box(std::in_place, max, max_char))); - CHECK(equal(v->get_entry(over), jank_nil)); - CHECK(equal(v->get_entry(under), jank_nil)); - CHECK(equal(v->get_entry(non_int), jank_nil)); + CHECK(equal(v->get_entry(over), jank_nil())); + CHECK(equal(v->get_entry(under), jank_nil())); + CHECK(equal(v->get_entry(non_int), jank_nil())); } TEST_CASE("equal") { diff --git a/compiler+runtime/test/cpp/jank/runtime/obj/ratio.cpp b/compiler+runtime/test/cpp/jank/runtime/obj/ratio.cpp index 2fb7c3dc2..cae9f1790 100644 --- a/compiler+runtime/test/cpp/jank/runtime/obj/ratio.cpp +++ b/compiler+runtime/test/cpp/jank/runtime/obj/ratio.cpp @@ -25,8 +25,8 @@ namespace jank::runtime } SUBCASE("Valid ratio object_ref ctor") { - auto const num_ptr{ make_box(4).erase() }; - auto const denom_ptr{ make_box(6).erase() }; + auto const num_ptr{ make_box(4) }; + auto const denom_ptr{ make_box(6) }; obj::ratio_data const ratio{ num_ptr, denom_ptr }; CHECK_EQ(ratio.numerator, 2); CHECK_EQ(ratio.denominator, 3); diff --git a/compiler+runtime/test/cpp/jank/runtime/obj/repeat.cpp b/compiler+runtime/test/cpp/jank/runtime/obj/repeat.cpp index 0ddc5a372..1dab68e58 100644 --- a/compiler+runtime/test/cpp/jank/runtime/obj/repeat.cpp +++ b/compiler+runtime/test/cpp/jank/runtime/obj/repeat.cpp @@ -28,11 +28,11 @@ namespace jank::runtime::obj !equal(repeat::create(make_box(1), make_box(1)), repeat::create(make_box(0), make_box(1)))); CHECK(equal(repeat::create(make_box(0), make_box(0)), persistent_list::empty())); - CHECK(equal(seq(repeat::create(make_box(0), make_box(0))), jank_nil)); + CHECK(equal(seq(repeat::create(make_box(0), make_box(0))), jank_nil())); } TEST_CASE("seq") { - CHECK(equal(seq(repeat::create(make_box(0), make_box(0))), jank_nil)); + CHECK(equal(seq(repeat::create(make_box(0), make_box(0))), jank_nil())); } } } diff --git a/compiler+runtime/test/cpp/jtl/string_builder.cpp b/compiler+runtime/test/cpp/jtl/string_builder.cpp index 61f0d4b94..bcfcdde96 100644 --- a/compiler+runtime/test/cpp/jtl/string_builder.cpp +++ b/compiler+runtime/test/cpp/jtl/string_builder.cpp @@ -89,6 +89,24 @@ namespace jtl CHECK_EQ("3.140000", sb.view()); } + TEST_CASE("infinity") + { + string_builder sb; + sb(INFINITY); + CHECK_EQ(3, sb.pos); + CHECK_EQ(initial_capacity, sb.capacity); + CHECK_EQ("inf", sb.view()); + } + + TEST_CASE("nan") + { + string_builder sb; + sb(NAN); + CHECK_EQ(3, sb.pos); + CHECK_EQ(initial_capacity, sb.capacity); + CHECK_EQ("nan", sb.view()); + } + TEST_CASE("char32_t") { string_builder sb; diff --git a/compiler+runtime/test/cpp/main.cpp b/compiler+runtime/test/cpp/main.cpp index 3808ddf00..05f156eb3 100644 --- a/compiler+runtime/test/cpp/main.cpp +++ b/compiler+runtime/test/cpp/main.cpp @@ -1,9 +1,6 @@ #define DOCTEST_CONFIG_IMPLEMENT #include -#include -#include - #include #include #include @@ -19,6 +16,10 @@ #include #include +#ifdef JANK_PHASE_2 +extern "C" void jank_load_clojure_core(); +#endif + /* NOLINTNEXTLINE(bugprone-exception-escape): println can throw. */ int main(int const argc, char const **argv) try @@ -29,10 +30,14 @@ try context.setOption("no-breaks", true); jank_load_clojure_core_native(); - /* We're loading from source always due to a bug in how we generate symbols which is - * leading to duplicate symbols being generated. */ + +#ifdef JANK_PHASE_2 + jank_load_clojure_core(); + jank::runtime::__rt_ctx->module_loader.set_is_loaded("/clojure.core"); +#else jank::runtime::__rt_ctx->load_module("/clojure.core", jank::runtime::module::origin::latest) .expect_ok(); +#endif auto const res(context.run()); if(context.shouldExit()) diff --git a/compiler+runtime/test/jank/cpp/auto-box/pass-closure.jank b/compiler+runtime/test/jank/cpp/auto-box/pass-closure.jank index b0640ac19..a07fd8182 100644 --- a/compiler+runtime/test/jank/cpp/auto-box/pass-closure.jank +++ b/compiler+runtime/test/jank/cpp/auto-box/pass-closure.jank @@ -1,9 +1,9 @@ (let [i (cpp/int. 5) - ifn (fn* [] + ifn (fn* capture-i [] (assert (= 5 i))) _ (ifn) f (cpp/float. 5.0) - ffn (fn* [] + ffn (fn* capture-f [] (if (= 5.0 f) :success))] (ffn)) diff --git a/compiler+runtime/test/jank/cpp/constructor/complex/fail-template-instantiation.jank b/compiler+runtime/test/jank/cpp/constructor/complex/fail-template-instantiation.jank index 59b73e64a..9f60209bc 100644 --- a/compiler+runtime/test/jank/cpp/constructor/complex/fail-template-instantiation.jank +++ b/compiler+runtime/test/jank/cpp/constructor/complex/fail-template-instantiation.jank @@ -10,6 +10,6 @@ std::string a{}; }; }") -(let* [arg (cpp/int 5) +(let* [arg (cpp/int* cpp/nullptr) _ (cpp/jank.cpp.constructor.complex.fail_template_instantiation.foo arg)] :success) diff --git a/compiler+runtime/test/jank/cpp/global-value/pass-static-non-copyable.jank b/compiler+runtime/test/jank/cpp/global-value/pass-static-non-copyable.jank new file mode 100644 index 000000000..f01aca9d6 --- /dev/null +++ b/compiler+runtime/test/jank/cpp/global-value/pass-static-non-copyable.jank @@ -0,0 +1,24 @@ +(cpp/raw "namespace jank::cpp::global_value::pass_static_non_copyable + { + struct foo + { + foo() = delete; + foo(foo const&) = delete; + foo(foo &&) = delete; + foo(int i) + : data{ i } + { } + + int data{}; + }; + + struct bar + { + static foo const boop; + }; + foo const bar::boop{ 5 }; + }") +(let* [foo cpp/jank.cpp.global_value.pass_static_non_copyable.bar.boop] + (if (= 5 (cpp/.-data foo)) + :success + :failure)) diff --git a/compiler+runtime/test/jank/cpp/global-value/pass-static.jank b/compiler+runtime/test/jank/cpp/global-value/pass-static.jank index ccbe5224a..54a3ab721 100644 --- a/compiler+runtime/test/jank/cpp/global-value/pass-static.jank +++ b/compiler+runtime/test/jank/cpp/global-value/pass-static.jank @@ -1,10 +1,10 @@ (cpp/raw "namespace jank::cpp::global_value::pass_static - { - struct foo - { - static int const boop{ 5 }; - }; - }") + { + struct foo + { + static int const boop{ 5 }; + }; + }") (if (= 5 cpp/jank.cpp.global_value.pass_static.foo.boop) :success :failure) diff --git a/compiler+runtime/test/jank/cpp/member/pass-static.jank b/compiler+runtime/test/jank/cpp/member/pass-static.jank index 56afb7ecd..582cb3460 100644 --- a/compiler+runtime/test/jank/cpp/member/pass-static.jank +++ b/compiler+runtime/test/jank/cpp/member/pass-static.jank @@ -2,8 +2,9 @@ { struct bar { - static const int a{ 5 }; + static int const a; }; + int const bar::a{ 5 }; }") (let* [b (cpp/jank.cpp.member.pass_static.bar.) a (cpp/.-a b)] diff --git a/compiler+runtime/test/jank/cpp/member/skip-static-const.jank b/compiler+runtime/test/jank/cpp/member/skip-static-const.jank new file mode 100644 index 000000000..757315a21 --- /dev/null +++ b/compiler+runtime/test/jank/cpp/member/skip-static-const.jank @@ -0,0 +1,11 @@ +(cpp/raw "namespace jank::cpp::member::pass_static_const + { + struct bar + { + static int const a{ 5 }; + }; + }") +(let* [b (cpp/jank.cpp.member.pass_static_const.bar.) + a (cpp/.-a b)] + (if (= 5 a) + :success)) diff --git a/compiler+runtime/test/jank/form/case/pass-real.jank b/compiler+runtime/test/jank/form/case/pass-real.jank index efb4ac9b3..4ebeabfb6 100644 --- a/compiler+runtime/test/jank/form/case/pass-real.jank +++ b/compiler+runtime/test/jank/form/case/pass-real.jank @@ -1,9 +1,8 @@ -(assert - (= - (case 3.14 3.14 :pi - 2.71 :e - 1.61 :phi - :default) - :pi)) +(assert (= (case 3.14 + 3.14 :pi + 2.71 :e + 1.61 :phi + :default) + :pi)) :success diff --git a/compiler+runtime/test/jank/form/fn/arity/variadic/pass-packing-exceeds-max-params.jank b/compiler+runtime/test/jank/form/fn/arity/variadic/pass-packing-exceeds-max-params.jank index 2986e57b1..eac3700fa 100644 --- a/compiler+runtime/test/jank/form/fn/arity/variadic/pass-packing-exceeds-max-params.jank +++ b/compiler+runtime/test/jank/form/fn/arity/variadic/pass-packing-exceeds-max-params.jank @@ -1,5 +1,5 @@ (def variadic - (fn* + (fn* variadic ([& args] args))) (assert (= (variadic 1 2 3 4 5 6 7 8 9) [1 2 3 4 5 6 7 8 9])) (assert (= (variadic 1 2 3 4 5 6 7 8 9 10) [1 2 3 4 5 6 7 8 9 10])) @@ -8,7 +8,7 @@ ; This will be code-generated, not evaluated. (def foo - (fn* [] + (fn* foo [] (assert (= (variadic 1 2 3 4 5 6 7 8 9 10 11) [1 2 3 4 5 6 7 8 9 10 11])) (assert (= (variadic 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15])))) (foo) diff --git a/compiler+runtime/third-party/bdwgc b/compiler+runtime/third-party/bdwgc index 88a61fc6f..32b748111 160000 --- a/compiler+runtime/third-party/bdwgc +++ b/compiler+runtime/third-party/bdwgc @@ -1 +1 @@ -Subproject commit 88a61fc6f2688d8e1ea94f3f810c23db89a3f30b +Subproject commit 32b74811147649efab0944b2762fc3300074d25e diff --git a/compiler+runtime/third-party/bpptree b/compiler+runtime/third-party/bpptree deleted file mode 160000 index addf92b02..000000000 --- a/compiler+runtime/third-party/bpptree +++ /dev/null @@ -1 +0,0 @@ -Subproject commit addf92b029bef74ae07f4ebb7e82312a6950ae8c diff --git a/compiler+runtime/third-party/cli11 b/compiler+runtime/third-party/cli11 deleted file mode 160000 index 5a03ee583..000000000 --- a/compiler+runtime/third-party/cli11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5a03ee58384ce18b6b3de5a2256e18f5ef103633 diff --git a/flake.nix b/flake.nix index a9aca9a34..9173a8f9c 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,8 @@ "-L${lib.getLib pkgs.openssl}/lib" "-L${lib.getLib pkgs.zlib}/lib" "-L${lib.getLib pkgs.zstd}/lib" + "-L${lib.getLib pkgs.libedit}/lib" + "-L${lib.getLib pkgs.libxml2}/lib" ]; in { legacyPackages = pkgs; @@ -81,6 +83,8 @@ bzip2 openssl zstd + libedit + libxml2 ]); checkInputs = with pkgs; [ @@ -114,6 +118,8 @@ # jank options (lib.cmakeBool "jank_unity_build" true) (lib.cmakeBool "jank_test" finalAttrs.doCheck) + # We run out of memory in CI without this. + (lib.cmakeBool "jank_force_phase_2" true) ]; # Use a UTF-8 locale or else tests which use UTF-8 characters will @@ -171,6 +177,7 @@ shellHook = '' export CC=${llvm.clang}/bin/clang export CXX=${llvm.clang}/bin/clang++ + export CMAKE_CXX_FLAGS=${lib.escapeShellArg cmakeCxxFlags} export ASAN_OPTIONS=detect_leaks=0 ''; diff --git a/lein-jank-template/resources/leiningen/new/jank/project.clj b/lein-jank-template/resources/leiningen/new/jank/project.clj index 8bcbeae38..0de0e9635 100644 --- a/lein-jank-template/resources/leiningen/new/jank/project.clj +++ b/lein-jank-template/resources/leiningen/new/jank/project.clj @@ -2,7 +2,7 @@ :license {:name "MPL 2.0" :url "https://www.mozilla.org/en-US/MPL/2.0/"} :dependencies [] - :plugins [[org.jank-lang/lein-jank "0.2"]] + :plugins [[org.jank-lang/lein-jank "0.3"]] :middleware [leiningen.jank/middleware] :main {{namespace}} :profiles {:debug {:jank {:optimization-level 0}} diff --git a/lein-jank/project.clj b/lein-jank/project.clj index ea294dfa3..96bfcab0f 100644 --- a/lein-jank/project.clj +++ b/lein-jank/project.clj @@ -1,4 +1,4 @@ -(defproject org.jank-lang/lein-jank "0.2" +(defproject org.jank-lang/lein-jank "0.3" :description "Build your jank projects using leiningen." :url "https://jank-lang.org/" :license {:name "MPL 2.0" diff --git a/lein-jank/src/leiningen/jank.clj b/lein-jank/src/leiningen/jank.clj index 52422e58a..e9170b141 100644 --- a/lein-jank/src/leiningen/jank.clj +++ b/lein-jank/src/leiningen/jank.clj @@ -9,6 +9,8 @@ [leiningen.core.main :as lmain]) (:import [java.io File])) +(defonce verbose? (atom false)) + (defn build-declarative-flag [flag value] (case flag :direct-call @@ -42,7 +44,6 @@ (build-declarative-flag flag value)) (:jank project)))) - (defn shell-out! [project classpath command compiler-args runtime-args] (let [jank (b.f/which "jank") env (System/getenv) @@ -53,6 +54,8 @@ runtime-args) ; TODO: Better error handling. _ (assert (some? jank)) + _ (when @verbose? + (println ">" (clojure.string/join " " args))) proc (apply ps/shell {:continue true :dir (:root project) @@ -126,12 +129,25 @@ :help (-> fn-ref meta :doc)}) subtask-kw->var))) +(defn process-args [args] + (loop [args args + ret []] + (if (empty? args) + ret + (let [arg (first args) + ret (case arg + "-v" (do + (reset! verbose? true) + ret) + (conj ret arg))] + (recur (rest args) ret))))) + (defn jank "Compile, run and repl into jank." [project subcmd & args] ;(clojure.pprint/pprint (:jank project)) (if-some [handler (subtask-kw->var (keyword subcmd))] - (apply handler project args) + (apply handler project (process-args args)) (do (lmain/warn "Invalid subcommand!") (print-help!) diff --git a/ray.jank b/ray.jank index 22afb109c..425f72851 100644 --- a/ray.jank +++ b/ray.jank @@ -348,5 +348,13 @@ (println "meow")))) -;(jank.perf/benchmark {:label "ray"} (-main)) +; macOS +; -- main +; +; -- ref counting - non-atomic - no weak refs +; | ms/op | op/s | err% | total | benchmark +; |--------------------:|--------------------:|--------:|----------:|:---------- +; | 109.99 | 9.09 | 0.3% | 26.67 | `ray` + +(jank.perf/benchmark {:label "ray"} (-main)) ;(-main)