From 2cb227e14f2d9fc3bec52a0c5bcac6b6ee94f0c2 Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Wed, 27 Mar 2024 21:27:03 -0700 Subject: [PATCH] [prql] use cxx for rust ffi stuff --- README.md | 1 + snapcraft.yaml | 2 + src/CMakeLists.txt | 2 +- src/Makefile.am | 14 +- src/command_executor.cc | 38 +- src/lnav.cc | 17 + src/lnav_config.cc | 8 +- src/logfile_sub_source.cc | 2 +- src/prql/prql.am | 4 + src/{prelude.prql => prql/stats.prql} | 2 - src/sqlite-extension-func.cc | 13 +- src/sqlite-extension-func.hh | 3 +- src/third-party/prqlc-c/Cargo.lock | 73 +- src/third-party/prqlc-c/Cargo.toml | 6 +- src/third-party/prqlc-c/prqlc.cxx.cc | 891 ++++++++++++++++++ src/third-party/prqlc-c/prqlc.cxx.hh | 775 +++++++++++++++ src/third-party/prqlc-c/src/lib.rs | 410 ++------ test/Makefile.am | 2 +- ...1e242cdfa2db9005d4fe752a7b05d1ab5cba29.err | 12 +- ...51b55dff7332c5bee2c9b797c401c5614d574a.out | 2 + ...24078983cf1b7a80b6fb65d5186cd125498136.out | 2 + ...88ea61a5382458cc48a2607e2639e52b0be1da.out | 2 + 22 files changed, 1923 insertions(+), 358 deletions(-) create mode 100644 src/prql/prql.am rename src/{prelude.prql => prql/stats.prql} (66%) create mode 100644 src/third-party/prqlc-c/prqlc.cxx.cc create mode 100644 src/third-party/prqlc-c/prqlc.cxx.hh diff --git a/README.md b/README.md index f7cf5f31..74a0113a 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ The following software packages are required to build lnav: - libcurl - The cURL library for downloading files from URLs. Version 7.23.0 or higher is required. - libarchive - The libarchive library for opening archive files, like zip/tgz. - wireshark - The 'tshark' program is used to interpret pcap files. +- cargo/rust - The Rust language is used to build the PRQL compiler. #### Build diff --git a/snapcraft.yaml b/snapcraft.yaml index 109b541b..6756b6d3 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -66,6 +66,7 @@ parts: "$SNAPCRAFT_STAGE"/scriptlets/selective-checkout --debug --force-snapshot build-packages: - build-essential + - cargo - libarchive-dev - libcurl4-gnutls-dev - libpcre2-dev @@ -75,6 +76,7 @@ parts: - zlib1g-dev - libbz2-dev - libgpm-dev + - rustc stage-packages: - zlib1g - git-core diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 435c8807..de451431 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,7 +130,7 @@ function(bin2c) DEPENDS bin2c "${FILE_TO_LINK}") endfunction(bin2c) -foreach (FILE_TO_LINK animals.json ansi-palette.json css-color-names.json diseases.json emojis.json xml-entities.json xterm-palette.json help.txt help.md init.sql prelude.prql words.json) +foreach (FILE_TO_LINK animals.json ansi-palette.json css-color-names.json diseases.json emojis.json xml-entities.json xterm-palette.json help.txt help.md init.sql words.json) string(REPLACE "." "-" DST_FILE "${FILE_TO_LINK}") add_custom_command( OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc" diff --git a/src/Makefile.am b/src/Makefile.am index a21e46a0..07737a52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ default-formats.cc: $(BIN2C_PATH) $(FORMAT_FILES) $(BIN2C_V)$(BIN2C_PATH) -n lnav_format_json default-formats $(FORMAT_FILES) include keymaps/keymaps.am +include prql/prql.am include themes/themes.am CONFIG_FILES = \ @@ -54,6 +55,9 @@ CONFIG_FILES = \ default-config.cc: $(BIN2C_PATH) $(CONFIG_FILES) $(BIN2C_V)$(BIN2C_PATH) -n lnav_config_json default-config $(CONFIG_FILES) +prql-modules.cc: $(BIN2C_PATH) $(PRQL_FILES) + $(BIN2C_V)$(BIN2C_PATH) -n lnav_prql_modules prql-modules $(PRQL_FILES) + include scripts/scripts.am builtin-scripts.cc: $(BIN2C_PATH) $(BUILTIN_LNAVSCRIPTS) @@ -107,7 +111,7 @@ LNAV_BUILT_FILES = \ words-json.cc \ help-md.cc \ init-sql.cc \ - prelude-prql.cc \ + prql-modules.cc \ time_fmts.cc \ xml-entities-json.cc \ xterm-palette-json.cc @@ -123,7 +127,7 @@ RUST_DEPS_CPPFLAGS = -I$(srcdir)/third-party/prqlc-c -DHAVE_RUST_DEPS=1 PRQLC_DIR = third-party/prqlc-c/target RUST_DEPS_LIBS = $(PRQLC_DIR)/release/libprqlc_c.a -$(RUST_DEPS_LIBS): $(srcdir)/third-party/prqlc-c/src/lib.rs +$(RUST_DEPS_LIBS): $(srcdir)/third-party/prqlc-c/src/lib.rs $(srcdir)/third-party/prqlc-c/Cargo.toml mkdir -p $(PRQLC_DIR) env CARGO_TARGET_DIR=third-party/prqlc-c/target $(CARGO_CMD) build --manifest-path \ $(srcdir)/third-party/prqlc-c/Cargo.toml --package prqlc-c --release @@ -197,6 +201,7 @@ dist_noinst_DATA = \ $(BUILTIN_SHSCRIPTS) \ $(CONFIG_FILES) \ $(FORMAT_FILES) \ + $(PRQL_FILES) \ words.json \ xml-entities.json \ xterm-palette.json @@ -205,6 +210,7 @@ noinst_HEADERS = \ third-party/md4c/md4c.h \ third-party/prqlc-c/prqlc.h \ third-party/prqlc-c/prqlc.hpp \ + third-party/prqlc-c/prqlc.cxx.hh \ third-party/rapidyaml/ryml_all.hpp \ all_logs_vtab.hh \ archive_manager.hh \ @@ -300,7 +306,6 @@ noinst_HEADERS = \ piper.looper.cfg.hh \ plain_text_source.hh \ pollable.hh \ - prelude.prql \ pretty_printer.hh \ preview_status_source.hh \ ptimec.hh \ @@ -404,6 +409,7 @@ THIRD_PARTY_SRCS = \ third-party/doctest-root/doctest/doctest.h \ third-party/intervaltree/IntervalTree.h \ third-party/md4c/md4c.c \ + third-party/prqlc-c/prqlc.cxx.cc \ third-party/robin_hood/robin_hood.h \ third-party/sqlite/ext/dbdump.c \ third-party/sqlite/ext/series.c @@ -576,7 +582,7 @@ DISTCLEANFILES = \ words-json.h \ help-md.h \ init-sql.h \ - prelude-prql.h \ + prql-modules.h \ time_fmts.h \ xml-entities-json.h \ xterm-palette-json.h \ diff --git a/src/command_executor.cc b/src/command_executor.cc index f6709529..7684eba7 100644 --- a/src/command_executor.cc +++ b/src/command_executor.cc @@ -47,7 +47,7 @@ #include "lnav_config.hh" #include "lnav_util.hh" #include "log_format_loader.hh" -#include "prelude-prql.h" +#include "prql-modules.h" #include "readline_highlighters.hh" #include "service_tags.hh" #include "shlex.hh" @@ -56,7 +56,7 @@ #include "vtab_module.hh" #ifdef HAVE_RUST_DEPS -# include "prqlc.hpp" +# include "prqlc.cxx.hh" #endif using namespace lnav::roles::literals; @@ -269,15 +269,17 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg) #if HAVE_RUST_DEPS auto opts = prqlc::Options{true, "sql.sqlite", true}; - auto full_prql = fmt::format(FMT_STRING("{}\n{}{}"), - prelude_prql.to_string_fragment(), - sqlite_extension_prql, - stmt_str); - auto cr = prqlc::compile(full_prql.c_str(), &opts); - - for (size_t lpc = 0; lpc < cr.messages_len; lpc++) { - const auto& msg = cr.messages[lpc]; + auto tree = sqlite_extension_prql; + for (const auto& mod : lnav_prql_modules) { + tree.emplace_back(prqlc::SourceTreeElement{ + mod.get_name(), + mod.to_string_fragment().to_string(), + }); + } + tree.emplace_back(prqlc::SourceTreeElement{"", stmt_str}); + auto cr = prqlc::compile_tree(tree, opts); + for (const auto& msg : cr.messages) { if (msg.kind != prqlc::MessageKind::Error) { continue; } @@ -287,19 +289,17 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg) auto um = lnav::console::user_message::error( attr_line_t("unable to compile PRQL: ").append(stmt_al)) - .with_reason(msg.reason); - if (msg.display && *msg.display) { - um.with_note(*msg.display); + .with_reason((std::string) msg.reason); + if (!msg.display.empty()) { + um.with_note((std::string) msg.display); } - if (msg.hint && *msg.hint) { - um.with_help(*msg.hint); + for (const auto& hint : msg.hints) { + um.with_help(hint.data()); + break; } return Err(um); } - if (cr.output && cr.output[0]) { - stmt_str = cr.output; - } - prqlc::result_destroy(cr); + stmt_str = (std::string) cr.output; #else auto um = lnav::console::user_message::error( attr_line_t("PRQL is not supported in this build")); diff --git a/src/lnav.cc b/src/lnav.cc index beca285a..6dbd026d 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -3290,6 +3290,23 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%' log_info(" %s", file_iter->first.c_str()); } + if (!(lnav_data.ld_flags & LNF_HEADLESS) + && verbosity == verbosity_t::quiet && load_stdin + && lnav_data.ld_active_files.fc_file_names.size() == 1) + { + rescan_files(true); + gather_pipers(); + rebuild_indexes(ui_clock::now() + 10ms); + if (lnav_data.ld_child_pollers.empty()) { + if (lnav_data.ld_active_files.fc_files.empty() + || lnav_data.ld_active_files.fc_files[0]->size() < 24) + { + lnav_data.ld_flags |= LNF_HEADLESS; + verbosity = verbosity_t::standard; + } + } + } + if (lnav_data.ld_flags & LNF_HEADLESS) { std::vector< std::pair, diff --git a/src/lnav_config.cc b/src/lnav_config.cc index 812ecd64..35e47164 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -256,19 +256,23 @@ install_from_git(const std::string& repo) } auto finished_child = std::move(git_cmd).wait_for_child(); - if (!finished_child.was_normal_exit() || finished_child.exit_status() != 0) { return false; } + if (ghc::filesystem::is_directory(local_formats_path) + || ghc::filesystem::is_directory(local_configs_path)) + { + return false; + } if (!ghc::filesystem::is_directory(local_staging_path)) { auto um = lnav::console::user_message::error( attr_line_t("failed to install git repo: ") .append(lnav::roles::file(repo))) .with_reason( - attr_line_t("git failed to create the local directory") + attr_line_t("git failed to create the local directory ") .append( lnav::roles::file(local_staging_path.string()))); lnav::console::print(stderr, um); diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index c2bb3020..3466e3e7 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -1237,7 +1237,7 @@ logfile_sub_source::rebuild_index( void logfile_sub_source::text_update_marks(vis_bookmarks& bm) { - logfile* last_file; + logfile* last_file = nullptr; vis_line_t vl; bm[&BM_WARNINGS].clear(); diff --git a/src/prql/prql.am b/src/prql/prql.am new file mode 100644 index 00000000..a1780799 --- /dev/null +++ b/src/prql/prql.am @@ -0,0 +1,4 @@ + +PRQL_FILES = \ + $(srcdir)/%reldir%/stats.prql \ + $() diff --git a/src/prelude.prql b/src/prql/stats.prql similarity index 66% rename from src/prelude.prql rename to src/prql/stats.prql index c2938298..b29dabc0 100644 --- a/src/prelude.prql +++ b/src/prql/stats.prql @@ -1,5 +1,3 @@ -let json_each = func input -> s"SELECT * FROM json_each({input})" - let count_by = func column rel -> ( rel group {column} (aggregate {total = count this}) diff --git a/src/sqlite-extension-func.cc b/src/sqlite-extension-func.cc index ac9d7fc4..7364f605 100644 --- a/src/sqlite-extension-func.cc +++ b/src/sqlite-extension-func.cc @@ -47,7 +47,7 @@ int sqlite3_series_init(sqlite3* db, const sqlite3_api_routines* pApi); } -std::string sqlite_extension_prql; +rust::Vec sqlite_extension_prql; namespace lnav { namespace sql { @@ -209,7 +209,16 @@ register_sqlite_funcs(sqlite3* db, sqlite_registration_func_t* reg_funcs) } if (sqlite_extension_prql.empty()) { - phier.to_string(sqlite_extension_prql); + require(phier.ph_declarations.empty()); + for (const auto& mod_pair : phier.ph_modules) { + std::string content; + + mod_pair.second.to_string(content); + sqlite_extension_prql.emplace_back(prqlc::SourceTreeElement{ + fmt::format(FMT_STRING("{}.prql"), mod_pair.first), + content, + }); + } } static help_text builtin_funcs[] = { diff --git a/src/sqlite-extension-func.hh b/src/sqlite-extension-func.hh index 57045023..ff59de98 100644 --- a/src/sqlite-extension-func.hh +++ b/src/sqlite-extension-func.hh @@ -39,6 +39,7 @@ #include #include "help_text.hh" +#include "prqlc.cxx.hh" struct FuncDef { const char* zName{nullptr}; @@ -95,7 +96,7 @@ extern sqlite_registration_func_t sqlite_registration_funcs[]; int register_sqlite_funcs(sqlite3* db, sqlite_registration_func_t* reg_funcs); -extern std::string sqlite_extension_prql; +extern rust::Vec sqlite_extension_prql; extern "C" { diff --git a/src/third-party/prqlc-c/Cargo.lock b/src/third-party/prqlc-c/Cargo.lock index 076084b3..8ddcc8dd 100644 --- a/src/third-party/prqlc-c/Cargo.lock +++ b/src/third-party/prqlc-c/Cargo.lock @@ -309,6 +309,16 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "color-eyre" version = "0.6.2" @@ -394,6 +404,50 @@ dependencies = [ "memchr", ] +[[package]] +name = "cxx" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dc7287237dd438b926a81a1a5605dad33d286870e5eee2db17bf2bcd9e92a" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47c6c8ad7c1a10d3ef0fe3ff6733f4db0d78f08ef0b13121543163ef327058b" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "701a1ac7a697e249cdd8dc026d7a7dafbfd0dbcd8bd24ec55889f2bc13dd6287" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b404f596046b0bb2d903a9c786b875a126261b52b7c3a64bbb66382c41c771df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.10.0" @@ -647,6 +701,15 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -828,9 +891,9 @@ dependencies = [ name = "prqlc-c" version = "0.11.3" dependencies = [ - "libc", + "cxx", + "cxx-build", "prqlc", - "serde_json", ] [[package]] @@ -942,6 +1005,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + [[package]] name = "semver" version = "1.0.22" diff --git a/src/third-party/prqlc-c/Cargo.toml b/src/third-party/prqlc-c/Cargo.toml index 682df43c..52eddeea 100644 --- a/src/third-party/prqlc-c/Cargo.toml +++ b/src/third-party/prqlc-c/Cargo.toml @@ -20,9 +20,11 @@ test = false doc = false [dependencies] -libc = "0.2.153" prqlc = { git = "https://github.com/PRQL/prql.git" } -serde_json = "1.0.114" +cxx = "1.0" + +[build-dependencies] +cxx-build = "1.0" [package.metadata.release] tag-name = "{{version}}" diff --git a/src/third-party/prqlc-c/prqlc.cxx.cc b/src/third-party/prqlc-c/prqlc.cxx.cc new file mode 100644 index 00000000..df9c7cb7 --- /dev/null +++ b/src/third-party/prqlc-c/prqlc.cxx.cc @@ -0,0 +1,891 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rust { +inline namespace cxxbridge1 { +// #include "rust/cxx.h" + +#ifndef CXXBRIDGE1_PANIC +#define CXXBRIDGE1_PANIC +template +void panic [[noreturn]] (const char *msg); +#endif // CXXBRIDGE1_PANIC + +struct unsafe_bitcopy_t; + +namespace { +template +class impl; +} // namespace + +class Opaque; + +template +::std::size_t size_of(); +template +::std::size_t align_of(); + +#ifndef CXXBRIDGE1_RUST_STRING +#define CXXBRIDGE1_RUST_STRING +class String final { +public: + String() noexcept; + String(const String &) noexcept; + String(String &&) noexcept; + ~String() noexcept; + + String(const std::string &); + String(const char *); + String(const char *, std::size_t); + String(const char16_t *); + String(const char16_t *, std::size_t); + + static String lossy(const std::string &) noexcept; + static String lossy(const char *) noexcept; + static String lossy(const char *, std::size_t) noexcept; + static String lossy(const char16_t *) noexcept; + static String lossy(const char16_t *, std::size_t) noexcept; + + String &operator=(const String &) &noexcept; + String &operator=(String &&) &noexcept; + + explicit operator std::string() const; + + const char *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + const char *c_str() noexcept; + + std::size_t capacity() const noexcept; + void reserve(size_t new_cap) noexcept; + + using iterator = char *; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = const char *; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + bool operator==(const String &) const noexcept; + bool operator!=(const String &) const noexcept; + bool operator<(const String &) const noexcept; + bool operator<=(const String &) const noexcept; + bool operator>(const String &) const noexcept; + bool operator>=(const String &) const noexcept; + + void swap(String &) noexcept; + + String(unsafe_bitcopy_t, const String &) noexcept; + +private: + struct lossy_t; + String(lossy_t, const char *, std::size_t) noexcept; + String(lossy_t, const char16_t *, std::size_t) noexcept; + friend void swap(String &lhs, String &rhs) noexcept { lhs.swap(rhs); } + + std::array repr; +}; +#endif // CXXBRIDGE1_RUST_STRING + +#ifndef CXXBRIDGE1_RUST_SLICE +#define CXXBRIDGE1_RUST_SLICE +namespace detail { +template +struct copy_assignable_if {}; + +template <> +struct copy_assignable_if { + copy_assignable_if() noexcept = default; + copy_assignable_if(const copy_assignable_if &) noexcept = default; + copy_assignable_if &operator=(const copy_assignable_if &) &noexcept = delete; + copy_assignable_if &operator=(copy_assignable_if &&) &noexcept = default; +}; +} // namespace detail + +template +class Slice final + : private detail::copy_assignable_if::value> { +public: + using value_type = T; + + Slice() noexcept; + Slice(T *, std::size_t count) noexcept; + + Slice &operator=(const Slice &) &noexcept = default; + Slice &operator=(Slice &&) &noexcept = default; + + T *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + T &operator[](std::size_t n) const noexcept; + T &at(std::size_t n) const; + T &front() const noexcept; + T &back() const noexcept; + + Slice(const Slice &) noexcept = default; + ~Slice() noexcept = default; + + class iterator; + iterator begin() const noexcept; + iterator end() const noexcept; + + void swap(Slice &) noexcept; + +private: + class uninit; + Slice(uninit) noexcept; + friend impl; + friend void sliceInit(void *, const void *, std::size_t) noexcept; + friend void *slicePtr(const void *) noexcept; + friend std::size_t sliceLen(const void *) noexcept; + + std::array repr; +}; + +template +class Slice::iterator final { +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = typename std::add_pointer::type; + using reference = typename std::add_lvalue_reference::type; + + reference operator*() const noexcept; + pointer operator->() const noexcept; + reference operator[](difference_type) const noexcept; + + iterator &operator++() noexcept; + iterator operator++(int) noexcept; + iterator &operator--() noexcept; + iterator operator--(int) noexcept; + + iterator &operator+=(difference_type) noexcept; + iterator &operator-=(difference_type) noexcept; + iterator operator+(difference_type) const noexcept; + iterator operator-(difference_type) const noexcept; + difference_type operator-(const iterator &) const noexcept; + + bool operator==(const iterator &) const noexcept; + bool operator!=(const iterator &) const noexcept; + bool operator<(const iterator &) const noexcept; + bool operator<=(const iterator &) const noexcept; + bool operator>(const iterator &) const noexcept; + bool operator>=(const iterator &) const noexcept; + +private: + friend class Slice; + void *pos; + std::size_t stride; +}; + +template +Slice::Slice() noexcept { + sliceInit(this, reinterpret_cast(align_of()), 0); +} + +template +Slice::Slice(T *s, std::size_t count) noexcept { + assert(s != nullptr || count == 0); + sliceInit(this, + s == nullptr && count == 0 + ? reinterpret_cast(align_of()) + : const_cast::type *>(s), + count); +} + +template +T *Slice::data() const noexcept { + return reinterpret_cast(slicePtr(this)); +} + +template +std::size_t Slice::size() const noexcept { + return sliceLen(this); +} + +template +std::size_t Slice::length() const noexcept { + return this->size(); +} + +template +bool Slice::empty() const noexcept { + return this->size() == 0; +} + +template +T &Slice::operator[](std::size_t n) const noexcept { + assert(n < this->size()); + auto ptr = static_cast(slicePtr(this)) + size_of() * n; + return *reinterpret_cast(ptr); +} + +template +T &Slice::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Slice index out of range"); + } + return (*this)[n]; +} + +template +T &Slice::front() const noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +T &Slice::back() const noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +typename Slice::iterator::reference +Slice::iterator::operator*() const noexcept { + return *static_cast(this->pos); +} + +template +typename Slice::iterator::pointer +Slice::iterator::operator->() const noexcept { + return static_cast(this->pos); +} + +template +typename Slice::iterator::reference Slice::iterator::operator[]( + typename Slice::iterator::difference_type n) const noexcept { + auto ptr = static_cast(this->pos) + this->stride * n; + return *reinterpret_cast(ptr); +} + +template +typename Slice::iterator &Slice::iterator::operator++() noexcept { + this->pos = static_cast(this->pos) + this->stride; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator++(int) noexcept { + auto ret = iterator(*this); + this->pos = static_cast(this->pos) + this->stride; + return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator--() noexcept { + this->pos = static_cast(this->pos) - this->stride; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator--(int) noexcept { + auto ret = iterator(*this); + this->pos = static_cast(this->pos) - this->stride; + return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator+=( + typename Slice::iterator::difference_type n) noexcept { + this->pos = static_cast(this->pos) + this->stride * n; + return *this; +} + +template +typename Slice::iterator &Slice::iterator::operator-=( + typename Slice::iterator::difference_type n) noexcept { + this->pos = static_cast(this->pos) - this->stride * n; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator+( + typename Slice::iterator::difference_type n) const noexcept { + auto ret = iterator(*this); + ret.pos = static_cast(this->pos) + this->stride * n; + return ret; +} + +template +typename Slice::iterator Slice::iterator::operator-( + typename Slice::iterator::difference_type n) const noexcept { + auto ret = iterator(*this); + ret.pos = static_cast(this->pos) - this->stride * n; + return ret; +} + +template +typename Slice::iterator::difference_type +Slice::iterator::operator-(const iterator &other) const noexcept { + auto diff = std::distance(static_cast(other.pos), + static_cast(this->pos)); + return diff / static_cast::iterator::difference_type>( + this->stride); +} + +template +bool Slice::iterator::operator==(const iterator &other) const noexcept { + return this->pos == other.pos; +} + +template +bool Slice::iterator::operator!=(const iterator &other) const noexcept { + return this->pos != other.pos; +} + +template +bool Slice::iterator::operator<(const iterator &other) const noexcept { + return this->pos < other.pos; +} + +template +bool Slice::iterator::operator<=(const iterator &other) const noexcept { + return this->pos <= other.pos; +} + +template +bool Slice::iterator::operator>(const iterator &other) const noexcept { + return this->pos > other.pos; +} + +template +bool Slice::iterator::operator>=(const iterator &other) const noexcept { + return this->pos >= other.pos; +} + +template +typename Slice::iterator Slice::begin() const noexcept { + iterator it; + it.pos = slicePtr(this); + it.stride = size_of(); + return it; +} + +template +typename Slice::iterator Slice::end() const noexcept { + iterator it = this->begin(); + it.pos = static_cast(it.pos) + it.stride * this->size(); + return it; +} + +template +void Slice::swap(Slice &rhs) noexcept { + std::swap(*this, rhs); +} +#endif // CXXBRIDGE1_RUST_SLICE + +#ifndef CXXBRIDGE1_RUST_BITCOPY_T +#define CXXBRIDGE1_RUST_BITCOPY_T +struct unsafe_bitcopy_t final { + explicit unsafe_bitcopy_t() = default; +}; +#endif // CXXBRIDGE1_RUST_BITCOPY_T + +#ifndef CXXBRIDGE1_RUST_VEC +#define CXXBRIDGE1_RUST_VEC +template +class Vec final { +public: + using value_type = T; + + Vec() noexcept; + Vec(std::initializer_list); + Vec(const Vec &); + Vec(Vec &&) noexcept; + ~Vec() noexcept; + + Vec &operator=(Vec &&) &noexcept; + Vec &operator=(const Vec &) &; + + std::size_t size() const noexcept; + bool empty() const noexcept; + const T *data() const noexcept; + T *data() noexcept; + std::size_t capacity() const noexcept; + + const T &operator[](std::size_t n) const noexcept; + const T &at(std::size_t n) const; + const T &front() const noexcept; + const T &back() const noexcept; + + T &operator[](std::size_t n) noexcept; + T &at(std::size_t n); + T &front() noexcept; + T &back() noexcept; + + void reserve(std::size_t new_cap); + void push_back(const T &value); + void push_back(T &&value); + template + void emplace_back(Args &&...args); + void truncate(std::size_t len); + void clear(); + + using iterator = typename Slice::iterator; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = typename Slice::iterator; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + void swap(Vec &) noexcept; + + Vec(unsafe_bitcopy_t, const Vec &) noexcept; + +private: + void reserve_total(std::size_t new_cap) noexcept; + void set_len(std::size_t len) noexcept; + void drop() noexcept; + + friend void swap(Vec &lhs, Vec &rhs) noexcept { lhs.swap(rhs); } + + std::array repr; +}; + +template +Vec::Vec(std::initializer_list init) : Vec{} { + this->reserve_total(init.size()); + std::move(init.begin(), init.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(const Vec &other) : Vec() { + this->reserve_total(other.size()); + std::copy(other.begin(), other.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(Vec &&other) noexcept : repr(other.repr) { + new (&other) Vec(); +} + +template +Vec::~Vec() noexcept { + this->drop(); +} + +template +Vec &Vec::operator=(Vec &&other) &noexcept { + this->drop(); + this->repr = other.repr; + new (&other) Vec(); + return *this; +} + +template +Vec &Vec::operator=(const Vec &other) & { + if (this != &other) { + this->drop(); + new (this) Vec(other); + } + return *this; +} + +template +bool Vec::empty() const noexcept { + return this->size() == 0; +} + +template +T *Vec::data() noexcept { + return const_cast(const_cast *>(this)->data()); +} + +template +const T &Vec::operator[](std::size_t n) const noexcept { + assert(n < this->size()); + auto data = reinterpret_cast(this->data()); + return *reinterpret_cast(data + n * size_of()); +} + +template +const T &Vec::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +const T &Vec::front() const noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +const T &Vec::back() const noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +T &Vec::operator[](std::size_t n) noexcept { + assert(n < this->size()); + auto data = reinterpret_cast(this->data()); + return *reinterpret_cast(data + n * size_of()); +} + +template +T &Vec::at(std::size_t n) { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +T &Vec::front() noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +T &Vec::back() noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +void Vec::reserve(std::size_t new_cap) { + this->reserve_total(new_cap); +} + +template +void Vec::push_back(const T &value) { + this->emplace_back(value); +} + +template +void Vec::push_back(T &&value) { + this->emplace_back(std::move(value)); +} + +template +template +void Vec::emplace_back(Args &&...args) { + auto size = this->size(); + this->reserve_total(size + 1); + ::new (reinterpret_cast(reinterpret_cast(this->data()) + + size * size_of())) + T(std::forward(args)...); + this->set_len(size + 1); +} + +template +void Vec::clear() { + this->truncate(0); +} + +template +typename Vec::iterator Vec::begin() noexcept { + return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::iterator Vec::end() noexcept { + return Slice(this->data(), this->size()).end(); +} + +template +typename Vec::const_iterator Vec::begin() const noexcept { + return this->cbegin(); +} + +template +typename Vec::const_iterator Vec::end() const noexcept { + return this->cend(); +} + +template +typename Vec::const_iterator Vec::cbegin() const noexcept { + return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::const_iterator Vec::cend() const noexcept { + return Slice(this->data(), this->size()).end(); +} + +template +void Vec::swap(Vec &rhs) noexcept { + using std::swap; + swap(this->repr, rhs.repr); +} + +template +Vec::Vec(unsafe_bitcopy_t, const Vec &bits) noexcept : repr(bits.repr) {} +#endif // CXXBRIDGE1_RUST_VEC + +#ifndef CXXBRIDGE1_IS_COMPLETE +#define CXXBRIDGE1_IS_COMPLETE +namespace detail { +namespace { +template +struct is_complete : std::false_type {}; +template +struct is_complete : std::true_type {}; +} // namespace +} // namespace detail +#endif // CXXBRIDGE1_IS_COMPLETE + +#ifndef CXXBRIDGE1_LAYOUT +#define CXXBRIDGE1_LAYOUT +class layout { + template + friend std::size_t size_of(); + template + friend std::size_t align_of(); + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return T::layout::size(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return sizeof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + size_of() { + return do_size_of(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return T::layout::align(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return alignof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + align_of() { + return do_align_of(); + } +}; + +template +std::size_t size_of() { + return layout::size_of(); +} + +template +std::size_t align_of() { + return layout::align_of(); +} +#endif // CXXBRIDGE1_LAYOUT + +namespace detail { +template +struct operator_new { + void *operator()(::std::size_t sz) { return ::operator new(sz); } +}; + +template +struct operator_new { + void *operator()(::std::size_t sz) { return T::operator new(sz); } +}; +} // namespace detail + +template +union MaybeUninit { + T value; + void *operator new(::std::size_t sz) { return detail::operator_new{}(sz); } + MaybeUninit() {} + ~MaybeUninit() {} +}; +} // namespace cxxbridge1 +} // namespace rust + +namespace prqlc { + struct Options; + struct SourceTreeElement; + enum class MessageKind : ::std::uint8_t; + struct Message; + struct CompileResult2; +} + +namespace prqlc { +#ifndef CXXBRIDGE1_STRUCT_prqlc$Options +#define CXXBRIDGE1_STRUCT_prqlc$Options +struct Options final { + bool format; + ::rust::String target; + bool signature_comment; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$Options + +#ifndef CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement +#define CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement +struct SourceTreeElement final { + ::rust::String path; + ::rust::String content; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement + +#ifndef CXXBRIDGE1_ENUM_prqlc$MessageKind +#define CXXBRIDGE1_ENUM_prqlc$MessageKind +enum class MessageKind : ::std::uint8_t { + Error = 0, + Warning = 1, + Lint = 2, +}; +#endif // CXXBRIDGE1_ENUM_prqlc$MessageKind + +#ifndef CXXBRIDGE1_STRUCT_prqlc$Message +#define CXXBRIDGE1_STRUCT_prqlc$Message +struct Message final { + ::prqlc::MessageKind kind; + ::rust::String code; + ::rust::String reason; + ::rust::Vec<::rust::String> hints; + ::rust::String display; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$Message + +#ifndef CXXBRIDGE1_STRUCT_prqlc$CompileResult2 +#define CXXBRIDGE1_STRUCT_prqlc$CompileResult2 +struct CompileResult2 final { + ::rust::String output; + ::rust::Vec<::prqlc::Message> messages; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$CompileResult2 + +extern "C" { +void prqlc$cxxbridge1$compile_tree(::rust::Vec<::prqlc::SourceTreeElement> const &tree, ::prqlc::Options const &options, ::prqlc::CompileResult2 *return$) noexcept; +} // extern "C" + +::prqlc::CompileResult2 compile_tree(::rust::Vec<::prqlc::SourceTreeElement> const &tree, ::prqlc::Options const &options) noexcept { + ::rust::MaybeUninit<::prqlc::CompileResult2> return$; + prqlc$cxxbridge1$compile_tree(tree, options, &return$.value); + return ::std::move(return$.value); +} +} // namespace prqlc + +extern "C" { +void cxxbridge1$rust_vec$prqlc$Message$new(::rust::Vec<::prqlc::Message> const *ptr) noexcept; +void cxxbridge1$rust_vec$prqlc$Message$drop(::rust::Vec<::prqlc::Message> *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$prqlc$Message$len(::rust::Vec<::prqlc::Message> const *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$prqlc$Message$capacity(::rust::Vec<::prqlc::Message> const *ptr) noexcept; +::prqlc::Message const *cxxbridge1$rust_vec$prqlc$Message$data(::rust::Vec<::prqlc::Message> const *ptr) noexcept; +void cxxbridge1$rust_vec$prqlc$Message$reserve_total(::rust::Vec<::prqlc::Message> *ptr, ::std::size_t new_cap) noexcept; +void cxxbridge1$rust_vec$prqlc$Message$set_len(::rust::Vec<::prqlc::Message> *ptr, ::std::size_t len) noexcept; +void cxxbridge1$rust_vec$prqlc$Message$truncate(::rust::Vec<::prqlc::Message> *ptr, ::std::size_t len) noexcept; + +void cxxbridge1$rust_vec$prqlc$SourceTreeElement$new(::rust::Vec<::prqlc::SourceTreeElement> const *ptr) noexcept; +void cxxbridge1$rust_vec$prqlc$SourceTreeElement$drop(::rust::Vec<::prqlc::SourceTreeElement> *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$prqlc$SourceTreeElement$len(::rust::Vec<::prqlc::SourceTreeElement> const *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$prqlc$SourceTreeElement$capacity(::rust::Vec<::prqlc::SourceTreeElement> const *ptr) noexcept; +::prqlc::SourceTreeElement const *cxxbridge1$rust_vec$prqlc$SourceTreeElement$data(::rust::Vec<::prqlc::SourceTreeElement> const *ptr) noexcept; +void cxxbridge1$rust_vec$prqlc$SourceTreeElement$reserve_total(::rust::Vec<::prqlc::SourceTreeElement> *ptr, ::std::size_t new_cap) noexcept; +void cxxbridge1$rust_vec$prqlc$SourceTreeElement$set_len(::rust::Vec<::prqlc::SourceTreeElement> *ptr, ::std::size_t len) noexcept; +void cxxbridge1$rust_vec$prqlc$SourceTreeElement$truncate(::rust::Vec<::prqlc::SourceTreeElement> *ptr, ::std::size_t len) noexcept; +} // extern "C" + +namespace rust { +inline namespace cxxbridge1 { +template <> +Vec<::prqlc::Message>::Vec() noexcept { + cxxbridge1$rust_vec$prqlc$Message$new(this); +} +template <> +void Vec<::prqlc::Message>::drop() noexcept { + return cxxbridge1$rust_vec$prqlc$Message$drop(this); +} +template <> +::std::size_t Vec<::prqlc::Message>::size() const noexcept { + return cxxbridge1$rust_vec$prqlc$Message$len(this); +} +template <> +::std::size_t Vec<::prqlc::Message>::capacity() const noexcept { + return cxxbridge1$rust_vec$prqlc$Message$capacity(this); +} +template <> +::prqlc::Message const *Vec<::prqlc::Message>::data() const noexcept { + return cxxbridge1$rust_vec$prqlc$Message$data(this); +} +template <> +void Vec<::prqlc::Message>::reserve_total(::std::size_t new_cap) noexcept { + return cxxbridge1$rust_vec$prqlc$Message$reserve_total(this, new_cap); +} +template <> +void Vec<::prqlc::Message>::set_len(::std::size_t len) noexcept { + return cxxbridge1$rust_vec$prqlc$Message$set_len(this, len); +} +template <> +void Vec<::prqlc::Message>::truncate(::std::size_t len) { + return cxxbridge1$rust_vec$prqlc$Message$truncate(this, len); +} +template <> +Vec<::prqlc::SourceTreeElement>::Vec() noexcept { + cxxbridge1$rust_vec$prqlc$SourceTreeElement$new(this); +} +template <> +void Vec<::prqlc::SourceTreeElement>::drop() noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$drop(this); +} +template <> +::std::size_t Vec<::prqlc::SourceTreeElement>::size() const noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$len(this); +} +template <> +::std::size_t Vec<::prqlc::SourceTreeElement>::capacity() const noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$capacity(this); +} +template <> +::prqlc::SourceTreeElement const *Vec<::prqlc::SourceTreeElement>::data() const noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$data(this); +} +template <> +void Vec<::prqlc::SourceTreeElement>::reserve_total(::std::size_t new_cap) noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$reserve_total(this, new_cap); +} +template <> +void Vec<::prqlc::SourceTreeElement>::set_len(::std::size_t len) noexcept { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$set_len(this, len); +} +template <> +void Vec<::prqlc::SourceTreeElement>::truncate(::std::size_t len) { + return cxxbridge1$rust_vec$prqlc$SourceTreeElement$truncate(this, len); +} +} // namespace cxxbridge1 +} // namespace rust diff --git a/src/third-party/prqlc-c/prqlc.cxx.hh b/src/third-party/prqlc-c/prqlc.cxx.hh new file mode 100644 index 00000000..badfce6f --- /dev/null +++ b/src/third-party/prqlc-c/prqlc.cxx.hh @@ -0,0 +1,775 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rust { +inline namespace cxxbridge1 { +// #include "rust/cxx.h" + +#ifndef CXXBRIDGE1_PANIC +#define CXXBRIDGE1_PANIC +template +void panic [[noreturn]] (const char *msg); +#endif // CXXBRIDGE1_PANIC + +struct unsafe_bitcopy_t; + +namespace { +template +class impl; +} // namespace + +class Opaque; + +template +::std::size_t size_of(); +template +::std::size_t align_of(); + +#ifndef CXXBRIDGE1_RUST_STRING +#define CXXBRIDGE1_RUST_STRING +class String final { +public: + String() noexcept; + String(const String &) noexcept; + String(String &&) noexcept; + ~String() noexcept; + + String(const std::string &); + String(const char *); + String(const char *, std::size_t); + String(const char16_t *); + String(const char16_t *, std::size_t); + + static String lossy(const std::string &) noexcept; + static String lossy(const char *) noexcept; + static String lossy(const char *, std::size_t) noexcept; + static String lossy(const char16_t *) noexcept; + static String lossy(const char16_t *, std::size_t) noexcept; + + String &operator=(const String &) &noexcept; + String &operator=(String &&) &noexcept; + + explicit operator std::string() const; + + const char *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + const char *c_str() noexcept; + + std::size_t capacity() const noexcept; + void reserve(size_t new_cap) noexcept; + + using iterator = char *; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = const char *; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + bool operator==(const String &) const noexcept; + bool operator!=(const String &) const noexcept; + bool operator<(const String &) const noexcept; + bool operator<=(const String &) const noexcept; + bool operator>(const String &) const noexcept; + bool operator>=(const String &) const noexcept; + + void swap(String &) noexcept; + + String(unsafe_bitcopy_t, const String &) noexcept; + +private: + struct lossy_t; + String(lossy_t, const char *, std::size_t) noexcept; + String(lossy_t, const char16_t *, std::size_t) noexcept; + friend void swap(String &lhs, String &rhs) noexcept { lhs.swap(rhs); } + + std::array repr; +}; +#endif // CXXBRIDGE1_RUST_STRING + +#ifndef CXXBRIDGE1_RUST_SLICE +#define CXXBRIDGE1_RUST_SLICE +namespace detail { +template +struct copy_assignable_if {}; + +template <> +struct copy_assignable_if { + copy_assignable_if() noexcept = default; + copy_assignable_if(const copy_assignable_if &) noexcept = default; + copy_assignable_if &operator=(const copy_assignable_if &) &noexcept = delete; + copy_assignable_if &operator=(copy_assignable_if &&) &noexcept = default; +}; +} // namespace detail + +template +class Slice final + : private detail::copy_assignable_if::value> { +public: + using value_type = T; + + Slice() noexcept; + Slice(T *, std::size_t count) noexcept; + + Slice &operator=(const Slice &) &noexcept = default; + Slice &operator=(Slice &&) &noexcept = default; + + T *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + T &operator[](std::size_t n) const noexcept; + T &at(std::size_t n) const; + T &front() const noexcept; + T &back() const noexcept; + + Slice(const Slice &) noexcept = default; + ~Slice() noexcept = default; + + class iterator; + iterator begin() const noexcept; + iterator end() const noexcept; + + void swap(Slice &) noexcept; + +private: + class uninit; + Slice(uninit) noexcept; + friend impl; + friend void sliceInit(void *, const void *, std::size_t) noexcept; + friend void *slicePtr(const void *) noexcept; + friend std::size_t sliceLen(const void *) noexcept; + + std::array repr; +}; + +template +class Slice::iterator final { +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = typename std::add_pointer::type; + using reference = typename std::add_lvalue_reference::type; + + reference operator*() const noexcept; + pointer operator->() const noexcept; + reference operator[](difference_type) const noexcept; + + iterator &operator++() noexcept; + iterator operator++(int) noexcept; + iterator &operator--() noexcept; + iterator operator--(int) noexcept; + + iterator &operator+=(difference_type) noexcept; + iterator &operator-=(difference_type) noexcept; + iterator operator+(difference_type) const noexcept; + iterator operator-(difference_type) const noexcept; + difference_type operator-(const iterator &) const noexcept; + + bool operator==(const iterator &) const noexcept; + bool operator!=(const iterator &) const noexcept; + bool operator<(const iterator &) const noexcept; + bool operator<=(const iterator &) const noexcept; + bool operator>(const iterator &) const noexcept; + bool operator>=(const iterator &) const noexcept; + +private: + friend class Slice; + void *pos; + std::size_t stride; +}; + +template +Slice::Slice() noexcept { + sliceInit(this, reinterpret_cast(align_of()), 0); +} + +template +Slice::Slice(T *s, std::size_t count) noexcept { + assert(s != nullptr || count == 0); + sliceInit(this, + s == nullptr && count == 0 + ? reinterpret_cast(align_of()) + : const_cast::type *>(s), + count); +} + +template +T *Slice::data() const noexcept { + return reinterpret_cast(slicePtr(this)); +} + +template +std::size_t Slice::size() const noexcept { + return sliceLen(this); +} + +template +std::size_t Slice::length() const noexcept { + return this->size(); +} + +template +bool Slice::empty() const noexcept { + return this->size() == 0; +} + +template +T &Slice::operator[](std::size_t n) const noexcept { + assert(n < this->size()); + auto ptr = static_cast(slicePtr(this)) + size_of() * n; + return *reinterpret_cast(ptr); +} + +template +T &Slice::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Slice index out of range"); + } + return (*this)[n]; +} + +template +T &Slice::front() const noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +T &Slice::back() const noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +typename Slice::iterator::reference +Slice::iterator::operator*() const noexcept { + return *static_cast(this->pos); +} + +template +typename Slice::iterator::pointer +Slice::iterator::operator->() const noexcept { + return static_cast(this->pos); +} + +template +typename Slice::iterator::reference Slice::iterator::operator[]( + typename Slice::iterator::difference_type n) const noexcept { + auto ptr = static_cast(this->pos) + this->stride * n; + return *reinterpret_cast(ptr); +} + +template +typename Slice::iterator &Slice::iterator::operator++() noexcept { + this->pos = static_cast(this->pos) + this->stride; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator++(int) noexcept { + auto ret = iterator(*this); + this->pos = static_cast(this->pos) + this->stride; + return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator--() noexcept { + this->pos = static_cast(this->pos) - this->stride; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator--(int) noexcept { + auto ret = iterator(*this); + this->pos = static_cast(this->pos) - this->stride; + return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator+=( + typename Slice::iterator::difference_type n) noexcept { + this->pos = static_cast(this->pos) + this->stride * n; + return *this; +} + +template +typename Slice::iterator &Slice::iterator::operator-=( + typename Slice::iterator::difference_type n) noexcept { + this->pos = static_cast(this->pos) - this->stride * n; + return *this; +} + +template +typename Slice::iterator Slice::iterator::operator+( + typename Slice::iterator::difference_type n) const noexcept { + auto ret = iterator(*this); + ret.pos = static_cast(this->pos) + this->stride * n; + return ret; +} + +template +typename Slice::iterator Slice::iterator::operator-( + typename Slice::iterator::difference_type n) const noexcept { + auto ret = iterator(*this); + ret.pos = static_cast(this->pos) - this->stride * n; + return ret; +} + +template +typename Slice::iterator::difference_type +Slice::iterator::operator-(const iterator &other) const noexcept { + auto diff = std::distance(static_cast(other.pos), + static_cast(this->pos)); + return diff / static_cast::iterator::difference_type>( + this->stride); +} + +template +bool Slice::iterator::operator==(const iterator &other) const noexcept { + return this->pos == other.pos; +} + +template +bool Slice::iterator::operator!=(const iterator &other) const noexcept { + return this->pos != other.pos; +} + +template +bool Slice::iterator::operator<(const iterator &other) const noexcept { + return this->pos < other.pos; +} + +template +bool Slice::iterator::operator<=(const iterator &other) const noexcept { + return this->pos <= other.pos; +} + +template +bool Slice::iterator::operator>(const iterator &other) const noexcept { + return this->pos > other.pos; +} + +template +bool Slice::iterator::operator>=(const iterator &other) const noexcept { + return this->pos >= other.pos; +} + +template +typename Slice::iterator Slice::begin() const noexcept { + iterator it; + it.pos = slicePtr(this); + it.stride = size_of(); + return it; +} + +template +typename Slice::iterator Slice::end() const noexcept { + iterator it = this->begin(); + it.pos = static_cast(it.pos) + it.stride * this->size(); + return it; +} + +template +void Slice::swap(Slice &rhs) noexcept { + std::swap(*this, rhs); +} +#endif // CXXBRIDGE1_RUST_SLICE + +#ifndef CXXBRIDGE1_RUST_BITCOPY_T +#define CXXBRIDGE1_RUST_BITCOPY_T +struct unsafe_bitcopy_t final { + explicit unsafe_bitcopy_t() = default; +}; +#endif // CXXBRIDGE1_RUST_BITCOPY_T + +#ifndef CXXBRIDGE1_RUST_VEC +#define CXXBRIDGE1_RUST_VEC +template +class Vec final { +public: + using value_type = T; + + Vec() noexcept; + Vec(std::initializer_list); + Vec(const Vec &); + Vec(Vec &&) noexcept; + ~Vec() noexcept; + + Vec &operator=(Vec &&) &noexcept; + Vec &operator=(const Vec &) &; + + std::size_t size() const noexcept; + bool empty() const noexcept; + const T *data() const noexcept; + T *data() noexcept; + std::size_t capacity() const noexcept; + + const T &operator[](std::size_t n) const noexcept; + const T &at(std::size_t n) const; + const T &front() const noexcept; + const T &back() const noexcept; + + T &operator[](std::size_t n) noexcept; + T &at(std::size_t n); + T &front() noexcept; + T &back() noexcept; + + void reserve(std::size_t new_cap); + void push_back(const T &value); + void push_back(T &&value); + template + void emplace_back(Args &&...args); + void truncate(std::size_t len); + void clear(); + + using iterator = typename Slice::iterator; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = typename Slice::iterator; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + void swap(Vec &) noexcept; + + Vec(unsafe_bitcopy_t, const Vec &) noexcept; + +private: + void reserve_total(std::size_t new_cap) noexcept; + void set_len(std::size_t len) noexcept; + void drop() noexcept; + + friend void swap(Vec &lhs, Vec &rhs) noexcept { lhs.swap(rhs); } + + std::array repr; +}; + +template +Vec::Vec(std::initializer_list init) : Vec{} { + this->reserve_total(init.size()); + std::move(init.begin(), init.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(const Vec &other) : Vec() { + this->reserve_total(other.size()); + std::copy(other.begin(), other.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(Vec &&other) noexcept : repr(other.repr) { + new (&other) Vec(); +} + +template +Vec::~Vec() noexcept { + this->drop(); +} + +template +Vec &Vec::operator=(Vec &&other) &noexcept { + this->drop(); + this->repr = other.repr; + new (&other) Vec(); + return *this; +} + +template +Vec &Vec::operator=(const Vec &other) & { + if (this != &other) { + this->drop(); + new (this) Vec(other); + } + return *this; +} + +template +bool Vec::empty() const noexcept { + return this->size() == 0; +} + +template +T *Vec::data() noexcept { + return const_cast(const_cast *>(this)->data()); +} + +template +const T &Vec::operator[](std::size_t n) const noexcept { + assert(n < this->size()); + auto data = reinterpret_cast(this->data()); + return *reinterpret_cast(data + n * size_of()); +} + +template +const T &Vec::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +const T &Vec::front() const noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +const T &Vec::back() const noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +T &Vec::operator[](std::size_t n) noexcept { + assert(n < this->size()); + auto data = reinterpret_cast(this->data()); + return *reinterpret_cast(data + n * size_of()); +} + +template +T &Vec::at(std::size_t n) { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +T &Vec::front() noexcept { + assert(!this->empty()); + return (*this)[0]; +} + +template +T &Vec::back() noexcept { + assert(!this->empty()); + return (*this)[this->size() - 1]; +} + +template +void Vec::reserve(std::size_t new_cap) { + this->reserve_total(new_cap); +} + +template +void Vec::push_back(const T &value) { + this->emplace_back(value); +} + +template +void Vec::push_back(T &&value) { + this->emplace_back(std::move(value)); +} + +template +template +void Vec::emplace_back(Args &&...args) { + auto size = this->size(); + this->reserve_total(size + 1); + ::new (reinterpret_cast(reinterpret_cast(this->data()) + + size * size_of())) + T(std::forward(args)...); + this->set_len(size + 1); +} + +template +void Vec::clear() { + this->truncate(0); +} + +template +typename Vec::iterator Vec::begin() noexcept { + return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::iterator Vec::end() noexcept { + return Slice(this->data(), this->size()).end(); +} + +template +typename Vec::const_iterator Vec::begin() const noexcept { + return this->cbegin(); +} + +template +typename Vec::const_iterator Vec::end() const noexcept { + return this->cend(); +} + +template +typename Vec::const_iterator Vec::cbegin() const noexcept { + return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::const_iterator Vec::cend() const noexcept { + return Slice(this->data(), this->size()).end(); +} + +template +void Vec::swap(Vec &rhs) noexcept { + using std::swap; + swap(this->repr, rhs.repr); +} + +template +Vec::Vec(unsafe_bitcopy_t, const Vec &bits) noexcept : repr(bits.repr) {} +#endif // CXXBRIDGE1_RUST_VEC + +#ifndef CXXBRIDGE1_IS_COMPLETE +#define CXXBRIDGE1_IS_COMPLETE +namespace detail { +namespace { +template +struct is_complete : std::false_type {}; +template +struct is_complete : std::true_type {}; +} // namespace +} // namespace detail +#endif // CXXBRIDGE1_IS_COMPLETE + +#ifndef CXXBRIDGE1_LAYOUT +#define CXXBRIDGE1_LAYOUT +class layout { + template + friend std::size_t size_of(); + template + friend std::size_t align_of(); + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return T::layout::size(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return sizeof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + size_of() { + return do_size_of(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return T::layout::align(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return alignof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + align_of() { + return do_align_of(); + } +}; + +template +std::size_t size_of() { + return layout::size_of(); +} + +template +std::size_t align_of() { + return layout::align_of(); +} +#endif // CXXBRIDGE1_LAYOUT +} // namespace cxxbridge1 +} // namespace rust + +namespace prqlc { + struct Options; + struct SourceTreeElement; + enum class MessageKind : ::std::uint8_t; + struct Message; + struct CompileResult2; +} + +namespace prqlc { +#ifndef CXXBRIDGE1_STRUCT_prqlc$Options +#define CXXBRIDGE1_STRUCT_prqlc$Options +struct Options final { + bool format; + ::rust::String target; + bool signature_comment; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$Options + +#ifndef CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement +#define CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement +struct SourceTreeElement final { + ::rust::String path; + ::rust::String content; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$SourceTreeElement + +#ifndef CXXBRIDGE1_ENUM_prqlc$MessageKind +#define CXXBRIDGE1_ENUM_prqlc$MessageKind +enum class MessageKind : ::std::uint8_t { + Error = 0, + Warning = 1, + Lint = 2, +}; +#endif // CXXBRIDGE1_ENUM_prqlc$MessageKind + +#ifndef CXXBRIDGE1_STRUCT_prqlc$Message +#define CXXBRIDGE1_STRUCT_prqlc$Message +struct Message final { + ::prqlc::MessageKind kind; + ::rust::String code; + ::rust::String reason; + ::rust::Vec<::rust::String> hints; + ::rust::String display; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$Message + +#ifndef CXXBRIDGE1_STRUCT_prqlc$CompileResult2 +#define CXXBRIDGE1_STRUCT_prqlc$CompileResult2 +struct CompileResult2 final { + ::rust::String output; + ::rust::Vec<::prqlc::Message> messages; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_prqlc$CompileResult2 + +::prqlc::CompileResult2 compile_tree(::rust::Vec<::prqlc::SourceTreeElement> const &tree, ::prqlc::Options const &options) noexcept; +} // namespace prqlc diff --git a/src/third-party/prqlc-c/src/lib.rs b/src/third-party/prqlc-c/src/lib.rs index 90c9b19e..cebd65b2 100644 --- a/src/third-party/prqlc-c/src/lib.rs +++ b/src/third-party/prqlc-c/src/lib.rs @@ -1,346 +1,126 @@ #![cfg(not(target_family = "wasm"))] -extern crate libc; - -use libc::{c_char, size_t}; -use prqlc::{ErrorMessage, ErrorMessages}; use prqlc::Target; -use std::ffi::CStr; -use std::ffi::CString; +use prqlc::{ErrorMessage, ErrorMessages}; use std::panic; +use std::path::PathBuf; use std::str::FromStr; -/// Compile a PRQL string into a SQL string. -/// -/// This is a wrapper for: `prql_to_pl`, `pl_to_rq` and `rq_to_sql` without converting to JSON -/// between each of the functions. -/// -/// See `Options` struct for available compilation options. -/// -/// # Safety -/// -/// This function assumes zero-terminated input strings. -/// Calling code is responsible for freeing memory allocated for `CompileResult` -/// by calling `result_destroy`. -#[no_mangle] -pub unsafe extern "C" fn compile( - prql_query: *const c_char, - options: *const Options, -) -> CompileResult { - let prql_query: String = c_str_to_string(prql_query); - - let options = options.as_ref().map(convert_options).transpose(); - - let result = options - .and_then(|opts| { - panic::catch_unwind(|| { - Ok(prql_query.as_str()) - .and_then(prqlc::prql_to_pl) - .and_then(prqlc::pl_to_rq) - .and_then(|rq| prqlc::rq_to_sql(rq, &opts.unwrap_or_default())) - }).map_err(|p| ErrorMessages { - inner: vec![ErrorMessage { - kind: prqlc::MessageKind::Error, - code: None, - reason: format!("internal error: {:#?}", p), - hints: vec![], - span: None, - display: None, - location: None, - }] - })? - }) - .map_err(|e| e.composed(&prql_query.into())); - - result_into_c_str(result) -} - -/// Build PL AST from a PRQL string. PL in documented in the -/// [prqlc Rust crate](https://docs.rs/prqlc/latest/prqlc/ir/pl). -/// -/// Takes PRQL source buffer and writes PL serialized as JSON to `out` buffer. -/// -/// Returns 0 on success and a negative number -1 on failure. -/// -/// # Safety -/// -/// This function assumes zero-terminated input strings. -/// Calling code is responsible for freeing memory allocated for `CompileResult` -/// by calling `result_destroy`. -#[no_mangle] -pub unsafe extern "C" fn prql_to_pl(prql_query: *const c_char) -> CompileResult { - let prql_query: String = c_str_to_string(prql_query); - - let result = Ok(prql_query.as_str()) - .and_then(prqlc::prql_to_pl) - .and_then(|x| prqlc::json::from_pl(&x)); - result_into_c_str(result) -} - -/// Finds variable references, validates functions calls, determines frames and converts PL to RQ. -/// PL and RQ are documented in the -/// [prqlc Rust crate](https://docs.rs/prqlc/latest/prqlc/ast). -/// -/// Takes PL serialized as JSON buffer and writes RQ serialized as JSON to `out` buffer. -/// -/// Returns 0 on success and a negative number -1 on failure. -/// -/// # Safety -/// -/// This function assumes zero-terminated input strings. -/// Calling code is responsible for freeing memory allocated for `CompileResult` -/// by calling `result_destroy`. -#[no_mangle] -pub unsafe extern "C" fn pl_to_rq(pl_json: *const c_char) -> CompileResult { - let pl_json: String = c_str_to_string(pl_json); - - let result = Ok(pl_json.as_str()) - .and_then(prqlc::json::to_pl) - .and_then(prqlc::pl_to_rq) - .and_then(|x| prqlc::json::from_rq(&x)); - result_into_c_str(result) -} - -/// Convert RQ AST into an SQL string. RQ is documented in the -/// [prqlc Rust crate](https://docs.rs/prqlc/latest/prqlc/ir/rq). -/// -/// Takes RQ serialized as JSON buffer and writes SQL source to `out` buffer. -/// -/// Returns 0 on success and a negative number -1 on failure. -/// -/// # Safety -/// -/// This function assumes zero-terminated input strings. -/// Calling code is responsible for freeing memory allocated for `CompileResult` -/// by calling `result_destroy`. -#[no_mangle] -pub unsafe extern "C" fn rq_to_sql( - rq_json: *const c_char, - options: *const Options, -) -> CompileResult { - let rq_json: String = c_str_to_string(rq_json); - - let options = options.as_ref().map(convert_options).transpose(); - - let result = options.and_then(|options| { - Ok(rq_json.as_str()) - .and_then(prqlc::json::to_rq) - .and_then(|x| prqlc::rq_to_sql(x, &options.unwrap_or_default())) - }); - result_into_c_str(result) -} - -/// Compilation options -#[repr(C)] -pub struct Options { - /// Pass generated SQL string trough a formatter that splits it - /// into multiple lines and prettifies indentation and spacing. - /// - /// Defaults to true. - pub format: bool, - - /// Target and dialect to compile to. - /// - /// Defaults to `sql.any`, which uses `target` argument from the query header to determine - /// the SQL dialect. - pub target: *mut c_char, - - /// Emits the compiler signature as a comment after generated SQL - /// - /// Defaults to true. - pub signature_comment: bool, -} - -/// Result of compilation. -#[repr(C)] -pub struct CompileResult { - pub output: *const libc::c_char, - pub messages: *const Message, - pub messages_len: size_t, -} - -/// Compile message kind. Currently only Error is implemented. -#[repr(C)] -pub enum MessageKind { - Error, - Warning, - Lint, -} +#[cxx::bridge(namespace = "prqlc")] +mod ffi { + struct Options { + pub format: bool, + pub target: String, + pub signature_comment: bool, + } -/// Compile result message. -/// -/// Calling code is responsible for freeing all memory allocated -/// for fields as well as strings. -// Make sure to keep in sync with prqlc::ErrorMessage -#[repr(C)] -pub struct Message { - /// Message kind. Currently only Error is implemented. - pub kind: MessageKind, - /// Machine-readable identifier of the error - pub code: *const *const libc::c_char, - /// Plain text of the error - pub reason: *const libc::c_char, - /// A list of suggestions of how to fix the error - pub hint: *const *const libc::c_char, - /// Character offset of error origin within a source file - pub span: *const Span, + struct SourceTreeElement { + pub path: String, + pub content: String, + } - /// Annotated code, containing cause and hints. - pub display: *const *const libc::c_char, - /// Line and column number of error origin within a source file - pub location: *const SourceLocation, -} + enum MessageKind { + Error, + Warning, + Lint, + } -/// Identifier of a location in source. -/// Contains offsets in terms of chars. -// Make sure to keep in sync with prqlc::Span -#[repr(C)] -pub struct Span { - pub start: size_t, - pub end: size_t, -} + struct Message { + pub kind: MessageKind, + pub code: String, + pub reason: String, + pub hints: Vec, + pub display: String, + } -/// Location within a source file. -// Make sure to keep in sync with prqlc::SourceLocation -#[repr(C)] -pub struct SourceLocation { - pub start_line: size_t, - pub start_col: size_t, + #[derive(Default)] + struct CompileResult2 { + pub output: String, + pub messages: Vec, + } - pub end_line: size_t, - pub end_col: size_t, + extern "Rust" { + fn compile_tree(tree: &Vec, options: &Options) -> CompileResult2; + } } -/// Destroy a `CompileResult` once you are done with it. -/// -/// # Safety -/// -/// This function expects to be called exactly once after the call of any the functions -/// that return `CompileResult`. No fields should be freed manually. -#[no_mangle] -pub unsafe extern "C" fn result_destroy(res: CompileResult) { - // This is required because we are allocating memory for - // strings, vectors and options. - // For strings and vectors this is required, but options may be - // able to live entirely within the struct, instead of the heap. - - for i in 0..res.messages_len { - let e = &*res.messages.add(i); +impl TryFrom<&ffi::Options> for prqlc::Options { + type Error = ErrorMessages; - if !e.code.is_null() { - drop(CString::from_raw(*e.code as *mut libc::c_char)); - drop(Box::from_raw(e.code as *mut *const libc::c_char)); - } - drop(CString::from_raw(e.reason as *mut libc::c_char)); - if !e.hint.is_null() { - drop(CString::from_raw(*e.hint as *mut libc::c_char)); - drop(Box::from_raw(e.hint as *mut *const libc::c_char)); - } - if !e.span.is_null() { - drop(Box::from_raw(e.span as *mut Span)); - } - if !e.display.is_null() { - drop(CString::from_raw(*e.display as *mut libc::c_char)); - drop(Box::from_raw(e.display as *mut *const libc::c_char)); - } - if !e.location.is_null() { - drop(Box::from_raw(e.location as *mut SourceLocation)); - } + fn try_from(value: &ffi::Options) -> Result { + Ok(prqlc::Options { + format: value.format, + target: Target::from_str(value.target.as_str()).map_err(prqlc::ErrorMessages::from)?, + signature_comment: value.signature_comment, + color: false, + }) } - drop(Vec::from_raw_parts( - res.messages as *mut i8, - res.messages_len, - res.messages_len, - )); - drop(CString::from_raw(res.output as *mut libc::c_char)); } -unsafe fn result_into_c_str(result: Result) -> CompileResult { - match result { - Ok(output) => CompileResult { - output: convert_string(output), - messages: ::std::ptr::null_mut(), - messages_len: 0, - }, - Err(err) => { - let mut errors = Vec::with_capacity(err.inner.len()); - errors.extend(err.inner.into_iter().map(|e| Message { - kind: MessageKind::Error, - code: option_to_ptr(e.code.map(convert_string)), - reason: convert_string(e.reason), - hint: option_to_ptr(if e.hints.is_empty() { - None - } else { - Some(convert_string(e.hints.join("\n"))) - }), - span: option_to_ptr(e.span.map(convert_span)), - display: option_to_ptr(e.display.map(convert_string)), - location: option_to_ptr(e.location.map(convert_source_location)), - })); - CompileResult { - output: CString::default().into_raw(), - messages_len: errors.len(), - messages: errors.leak().as_ptr(), - } +impl From for ffi::MessageKind { + fn from(value: prqlc::MessageKind) -> Self { + match value { + prqlc::MessageKind::Error => ffi::MessageKind::Error, + prqlc::MessageKind::Warning => ffi::MessageKind::Warning, + prqlc::MessageKind::Lint => ffi::MessageKind::Lint, } } } -/// Allocates the value on the heap and returns a pointer to it. -/// If the input is None, it returns null pointer. -fn option_to_ptr(o: Option) -> *const T { - match o { - Some(x) => { - let b = Box::new(x); - Box::into_raw(b) +impl From for ffi::Message { + fn from(value: ErrorMessage) -> Self { + ffi::Message { + kind: value.kind.into(), + code: value.code.unwrap_or(String::new()), + reason: value.reason, + hints: value.hints, + display: value.display.unwrap_or(String::new()), } - None => ::std::ptr::null(), } } -fn convert_string(x: String) -> *const libc::c_char { - CString::new(x).unwrap_or_default().into_raw() +fn compile_tree_int( + tree: &Vec, + options: &ffi::Options, +) -> Result { + let tree = prqlc::SourceTree::new( + tree.iter() + .map(|ste| (PathBuf::from(ste.path.clone()), ste.content.clone())), + None, + ); + + let options: prqlc::Options = options.try_into()?; + + panic::catch_unwind(|| { + Ok(prqlc::prql_to_pl_tree(&tree) + .and_then(prqlc::pl_to_rq) + .map_err(|e: ErrorMessages| ErrorMessages::from(e).composed(&tree)) + .and_then(|rq| prqlc::rq_to_sql(rq, &options))?) + .map_err(|e: ErrorMessages| ErrorMessages::from(e).composed(&tree)) + }) + .map_err(|p| { + ErrorMessages::from(ErrorMessage { + kind: prqlc::MessageKind::Error, + code: None, + reason: format!("internal error: {:#?}", p), + hints: vec![], + span: None, + display: None, + location: None, + }) + })? } -fn convert_span(x: prqlc::Span) -> Span { - Span { - start: x.start, - end: x.end, - } -} +pub fn compile_tree( + tree: &Vec, + options: &ffi::Options, +) -> ffi::CompileResult2 { + let mut retval = ffi::CompileResult2::default(); -fn convert_source_location(x: prqlc::SourceLocation) -> SourceLocation { - SourceLocation { - start_line: x.start.0, - start_col: x.start.1, - end_line: x.end.0, - end_col: x.end.1, + match compile_tree_int(tree, options) { + Ok(output) => retval.output = output, + Err(errors) => retval.messages = errors.inner.into_iter().map(|x| x.into()).collect(), } -} - -unsafe fn c_str_to_string(c_str: *const c_char) -> String { - // inefficient, but simple - CStr::from_ptr(c_str).to_string_lossy().into_owned() -} -fn convert_options(o: &Options) -> Result { - let target = if !o.target.is_null() { - Some(unsafe { c_str_to_string(o.target) }) - } else { - None - }; - let target = target - .as_deref() - .filter(|x| !x.is_empty()) - .unwrap_or("sql.any"); - - let target = Target::from_str(target).map_err(prqlc::ErrorMessages::from)?; - - Ok(prqlc::Options { - format: o.format, - target, - signature_comment: o.signature_comment, - // TODO: add support for this - color: false, - }) + retval } diff --git a/test/Makefile.am b/test/Makefile.am index 1aaba2a0..762dff55 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,7 +13,7 @@ AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) if HAVE_CARGO -RUST_DEPS_CPPFLAGS = -I$(srcdir)/third-party/prqlc-c -DHAVE_RUST_DEPS=1 +RUST_DEPS_CPPFLAGS = -I$(top_srcdir)/src/third-party/prqlc-c -DHAVE_RUST_DEPS=1 PRQLC_DIR = ../src/third-party/prqlc-c/target RUST_DEPS_LIBS = $(PRQLC_DIR)/release/libprqlc_c.a else diff --git a/test/expected/test_prql.sh_451e242cdfa2db9005d4fe752a7b05d1ab5cba29.err b/test/expected/test_prql.sh_451e242cdfa2db9005d4fe752a7b05d1ab5cba29.err index cb0e29d9..1c7eb34f 100644 --- a/test/expected/test_prql.sh_451e242cdfa2db9005d4fe752a7b05d1ab5cba29.err +++ b/test/expected/test_prql.sh_451e242cdfa2db9005d4fe752a7b05d1ab5cba29.err @@ -1,10 +1,10 @@ ✘ error: unable to compile PRQL: from db.access_log | take abc reason: `take` expected int or range, but found this.access_log.abc  = note: Error: - ╭─[:62:27] - │ - 62 │ from db.access_log | take abc - │ ─┬─ - │ ╰─── `take` expected int or range, but found this.access_log.abc - ────╯ + ╭─[:1:27] + │ + 1 │ from db.access_log | take abc + │ ─┬─ + │ ╰─── `take` expected int or range, but found this.access_log.abc + ───╯ diff --git a/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out b/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out index a8182dd7..1f28ffdf 100644 --- a/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out +++ b/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out @@ -218,6 +218,8 @@ The following software packages are required to build lnav: archive files, like zip/tgz. • wireshark - The 'tshark' program is used to interpret pcap files. + • cargo/rust - The Rust language is used to build the + PRQL compiler. Build diff --git a/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out b/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out index 95868d62..3fe29498 100644 --- a/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out +++ b/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out @@ -161,6 +161,8 @@ The following software packages are required to build lnav: archive files, like zip/tgz. • wireshark - The 'tshark' program is used to interpret pcap files. + • cargo/rust - The Rust language is used to build the + PRQL compiler. Build diff --git a/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out b/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out index 95868d62..3fe29498 100644 --- a/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out +++ b/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out @@ -161,6 +161,8 @@ The following software packages are required to build lnav: archive files, like zip/tgz. • wireshark - The 'tshark' program is used to interpret pcap files. + • cargo/rust - The Rust language is used to build the + PRQL compiler. Build