# HG changeset patch # User Yvan Sraka # Date 1706973208 -3600 # Sat Feb 03 16:13:28 2024 +0100 # Node ID 681eb33e945b9bcbc4adfc74c5e7e4fcf7503f11 # Parent 0000000000000000000000000000000000000000 Initial commit (v0.1.0) Checkout of the project for first public release and talk: https://fosdem.org/2024/schedule/event/fosdem-2024-2186-better-bee-be-better-spot-more-bugs-than-ts-with-less-than-js/ diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,17 @@ +[profile.dev] +lto = "off" + +[profile.release] +codegen-units = 1 +lto = "fat" + +[profile.small] +inherits = "release" +opt-level = "z" +strip = "symbols" + +[build] +rustflags = ["-C", "target-cpu=native"] + +[target.x86_64-unknown-linux-gnu] +rustflags = ["-C", "link-arg=-fuse-ld=mold"] diff --git a/.editorconfig b/.editorconfig new file mode 100644 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.envrc b/.envrc new file mode 100644 --- /dev/null +++ b/.envrc @@ -0,0 +1,1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Build artifacts +node_modules/ +result +target/ + +# Generated files +**/*.rs.bk + +# Operating System specific files +.DS_Store +Thumbs.db + +# https://github.com/nix-community/nix-direnv +.direnv diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,11 @@ +# Build artifacts +node_modules/ +result +target/ + +# Operating System specific files +.DS_Store +Thumbs.db + +# https://github.com/nix-community/nix-direnv +.direnv diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1744 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + +[[package]] +name = "bee-lang" +version = "0.1.0" +dependencies = [ + "clap", + "clap_mangen", + "deno_core", + "directories", + "env_logger", + "exitcode", + "human-panic", + "lazy_static", + "log", + "miette", + "owo-colors 4.0.0", + "pathdiff", + "rayon", + "regex", + "rquickjs", + "thiserror", + "tree-sitter", + "tree-sitter-bee-lang", + "walkdir", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "clap_mangen" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43144ab702c764b0a3ecda5ecd2aba2e6874d8de4b9f56930bbb1e88fcecd84a" +dependencies = [ + "clap", + "roff", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "deno_core" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c18f86123119dffd1f2f016ff5b858b878971c042a18493794b219a33a69dda" +dependencies = [ + "anyhow", + "bit-set", + "bit-vec", + "bytes", + "cooked-waker", + "deno_ops", + "deno_unsync", + "futures", + "libc", + "log", + "memoffset", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "serde_v8", + "smallvec", + "sourcemap", + "static_assertions", + "tokio", + "url", + "v8", +] + +[[package]] +name = "deno_ops" +version = "0.120.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8f888f466c80fdec64d0ec2fb12b0f56b0f1ae4815bb20a1895cc7097fb775" +dependencies = [ + "proc-macro-rules", + "proc-macro2", + "quote", + "strum", + "strum_macros", + "syn 2.0.48", + "thiserror", +] + +[[package]] +name = "deno_unsync" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30dff7e03584dbae188dae96a0f1876740054809b2ad0cf7c9fc5d361f20e739" +dependencies = [ + "tokio", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "exitcode" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fslock" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57eafdd0c16f57161105ae1b98a1238f97645f2f588438b2949c99a2af9616bf" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "human-panic" +version = "1.2.3" +source = "git+https://github.com/yvan-sraka/human-panic.git#07cc1dff71837b8530d1c3606411f21cb2b66c85" +dependencies = [ + "anstream", + "anstyle", + "backtrace", + "os_info", + "serde", + "serde_derive", + "toml", + "uuid", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_ci" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "5.10.0" +source = "git+https://github.com/yvan-sraka/miette.git#1ab33608b2d0c18b0307fbf2035212acde003bd1" +dependencies = [ + "backtrace", + "backtrace-ext", + "is-terminal", + "miette-derive", + "once_cell", + "owo-colors 3.5.0", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "git+https://github.com/yvan-sraka/miette.git#1ab33608b2d0c18b0307fbf2035212acde003bd1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "owo-colors" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +dependencies = [ + "supports-color", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-rules" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" +dependencies = [ + "proc-macro-rules-macros", + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "proc-macro-rules-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207fffb0fe655d1d47f6af98cc2793405e85929bdbc420d685554ff07be27ac7" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + +[[package]] +name = "rquickjs" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511ee02660e19cf451ebcbda6151a4023044293066e9ccd2b0498047203f6ab1" +dependencies = [ + "rquickjs-core", +] + +[[package]] +name = "rquickjs-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10ce0bc11e249e738aadb8119e9a7619125cb866208236d88d2ee3dcdb7a67d" +dependencies = [ + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86030d52fc20e68115f93738c2cb960d6f900f64d99e1013ea0e170381eb0a72" +dependencies = [ + "cc", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.21", +] + +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_v8" +version = "0.153.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a53364678111a47806ca93b8485acd66a4a2d37da733564dcc3e76a91531ba6" +dependencies = [ + "bytes", + "derive_more", + "num-bigint", + "serde", + "smallvec", + "thiserror", + "v8", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "sourcemap" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10da010a590ed2fa9ca8467b00ce7e9c5a8017742c0c09c45450efc172208c4b" +dependencies = [ + "data-encoding", + "debugid", + "if_chain", + "rustc_version 0.2.3", + "serde", + "serde_json", + "unicode-id", + "url", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "supports-unicode" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", +] + +[[package]] +name = "tree-sitter" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" +dependencies = [ + "cc", + "regex", +] + +[[package]] +name = "tree-sitter-bee-lang" +version = "0.1.0" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-id" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "v8" +version = "0.82.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f53dfb242f4c0c39ed3fc7064378a342e57b5c9bd774636ad34ffe405b808121" +dependencies = [ + "bitflags 1.3.2", + "fslock", + "once_cell", + "which", +] + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "bee-lang" +version = "0.1.0" +edition = "2021" +authors = ["Yvan Sraka "] +license = "GPLv2" + +[lib] +name = "bee" +crate-type = ["cdylib", "rlib"] + +[[bin]] +name = "bee" + +[dependencies] +clap = { version = "4.4", features = ["derive"] } +deno_core = { version = "0.244", optional = true } +directories = "5.0" +env_logger = { default-features = false, version = "0.10" } +exitcode = "1.1" +human-panic = { git = "https://github.com/yvan-sraka/human-panic.git", version = "1.2" } +lazy_static = "1.4" +log = "0.4" +miette = { git = "https://github.com/yvan-sraka/miette.git", version = "5.10", features = ["fancy"] } +owo-colors = { version = "4.0", features = ["supports-colors"] } +pathdiff = "0.2" +rayon = { version = "1.8", optional = true } +regex = { default-features = false, version = "1.10" } +rquickjs = { version = "0.4", optional = true , default-features = false } +thiserror = "1.0" +tree-sitter = "0.20" +tree-sitter-bee-lang = { path = "./tree-sitter-bee-lang", version = "0.1" } +walkdir = "2.4" + +[features] +default = ["quickjs", "rayon"] +deno = ["dep:deno_core"] +quickjs = ["dep:rquickjs"] +rayon = ["dep:rayon"] + +[build-dependencies] +clap = { version = "4.4", features = ["derive"] } +clap_mangen = "0.2" diff --git a/LICENSE b/LICENSE new file mode 100644 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Bee programming language + +A small language that is **easy to learn** and that helps you wrote **bug-free** programs. + +The project was introduced at FOSDEM 2024, you can find the slides [here](https://topaz-candle-mimosa.glitch.me). + +```bee +// A quick taste of the Bee syntax: +{ Flower = type ("🌸" | "🌺" | "🌼") + { fmt = args => "${args.animal} is ${args.mood}!" + return x => fmt { animal = "🐝"; mood = if Flower x "happy" else "sad" } + } (read "/dev/stdin") |> print +} +``` + +Check out the [`examples`](./examples) folder, for more code snippets. + +Bee currently compile to JavaScript but aims to suitable for system programming! + +One core design idea to keep the language small is to define most of construct in the [standard library](./src/prelude.bee). + + + +# Usage + +Get a Rust toolchain working on your computer, and then `cargo install --git https://git.sr.ht/~yvan-sraka/bee-lang` to build from source. + +Check out the [Syntax Highlighting Guide](./tree-sitter-bee-lang/README.md) to set-up your code editor. You can also find an [example](examples/webpack-demo) on how to set-up Webpack to work with Bee. + +# Roadmap + +## What Has Been Implemented... + +- Funny **Bugs**! 🐛 +- **Syntax** `grammar.js` with TreeSitter; +- **Semantics** (destructuring, spread operator, implicit function arguments, operator overloading, etc.); +- **Prelude** (minimal standard library); +- **CLI** (that works without `node` in your `PATH`); +- **Build targets** (e.g., `@debug`, `@release` or user-defined); +- **Build cache** (file-based); +- **Basic editor support** (syntax highlighting); + +## What's Left to Do... + +- **Pattern matching** (in lambda definition, let-bindings and branches of a `match` keyword); +- **Constrained mutability** (e.g. needed for `while` loops); +- **Subtyping** (keeping track of the partial order of Types declared within a scope). +- A Language Server Protocol (**LSP**) and Debug Adapter Protocol (**DAP**); +- A **native backend** (C, WASM or LLVM); +- An **incremental typing** algorithm; +- A language **package manager**. + +# Mailing-lists + +- [announce@bee-lang.org](https://groups.google.com/g/bee-lang-announce): Low-volume mailing list for announcements related to the https://bee-lang.org project. +- [devel@bee-lang.org](https://groups.google.com/g/bee-lang-devel): Mailing list for development discussion and patches related to the https://bee-lang.org project. For help sending patches to this list, please consult https://git-send-email.io. +- [discuss@bee-lang.org](https://groups.google.com/g/bee-lang-discuss): Mailing list for end-user discussion and questions related to the https://bee-lang.org project. diff --git a/build.rs b/build.rs new file mode 100644 --- /dev/null +++ b/build.rs @@ -0,0 +1,20 @@ +use clap::CommandFactory; + +#[path = "src/cli.rs"] +mod cli; + +fn main() -> std::io::Result<()> { + let out_dir = + std::path::PathBuf::from(std::env::var_os("OUT_DIR").ok_or(std::io::ErrorKind::NotFound)?); + let cmd = cli::Cli::command(); + + let man = clap_mangen::Man::new(cmd); + let mut buffer: Vec = Default::default(); + man.render(&mut buffer)?; + + // FIXME: use `man` crate for further customization :) + + std::fs::write(out_dir.join("bee.1"), buffer)?; + + Ok(()) +} diff --git a/default.nix b/default.nix new file mode 100644 --- /dev/null +++ b/default.nix @@ -0,0 +1,47 @@ +{ pkgs ? import { }, lib ? pkgs.lib, rustPlatform ? pkgs.rustPlatform +, fetchurl ? pkgs.fetchurl, system ? builtins.currentSystem }: + +rustPlatform.buildRustPackage rec { + pname = "bee-lang"; + version = "0.1.0"; + + src = fetchurl { + url = "https://git.sr.ht/~yvan-sraka/bee-lang/archive/v${version}.tar.gz"; + sha256 = lib.fakeSha256; # You have to put here the Nix "expected" hash :) + }; + + cargoLock = { + lockFile = ./Cargo.lock; + outputHashes = { + "human-panic-1.2.3" = + "sha256-rtRyNQUATcaGJC5RZk5K0ClY0c1aTxccYXCi16h02oY="; + "miette-5.10.0" = "sha256-ru/cKlegkeqq1y/w1O3k50jYOtvwsXod7VCK65/ToP4="; + }; + }; + + nativeBuildInputs = with pkgs; + [ nodejs tree-sitter ] + ++ (if system == "x86_64-linux" then [ mold ] else [ ]); + + buildPhase = '' + runHook preBuild + pushd tree-sitter + tree-sitter generate + popd + cargo build --release + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + install -D target/release/bee -t $out/bin + runHook postInstall + ''; + + meta = with lib; { + description = "The Bee programming language compiler"; + homepage = "https://bee-lang.org"; + license = licenses.gpl2; + maintainers = with maintainers; [ maintainers.yvan-sraka ]; + }; +} diff --git a/examples/arrays.bee b/examples/arrays.bee new file mode 100644 --- /dev/null +++ b/examples/arrays.bee @@ -0,0 +1,5 @@ +{ + x = [ 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 ] + // This will be check (and error) at build-time: + print x.42 +} diff --git a/examples/assert.bee b/examples/assert.bee new file mode 100644 --- /dev/null +++ b/examples/assert.bee @@ -0,0 +1,7 @@ +{ + x = _ => assert false + // This will error at build-time and display a debug "stack-trace" + x {} + // One other way to error is to directly: + panic "Custom error message :$" +} diff --git a/examples/comments.bee b/examples/comments.bee new file mode 100644 --- /dev/null +++ b/examples/comments.bee @@ -0,0 +1,3 @@ +/* Block comments could be /* nested */ */ +// Inline comments disable any */ or /* later in the same line! +"//, /* and /* in strings are (indeed) ignored!" diff --git a/examples/custom_target.bee b/examples/custom_target.bee new file mode 100644 --- /dev/null +++ b/examples/custom_target.bee @@ -0,0 +1,3 @@ +// This will print a different value if `--targets release` is passed as CLI +// argument to `bee build`: +print (if @debug "debug" else "release") diff --git a/examples/greetings.bee b/examples/greetings.bee new file mode 100644 --- /dev/null +++ b/examples/greetings.bee @@ -0,0 +1,5 @@ +// A file/module could contain any arbitrary expression, like a function: +name => print "Hello, ${name}!" +// Strings support interpolation of simple identifiers! + +// FIXME: demonstrate the `import` keyword! diff --git a/examples/if_then_else.bee b/examples/if_then_else.bee new file mode 100644 --- /dev/null +++ b/examples/if_then_else.bee @@ -0,0 +1,7 @@ +{ + // if statement could be assigned and chained: + x = if false 1 else if true 2 else 3 + // the else clause is always required! +} + +// FIXME: better explain boolean and comparison operator diff --git a/examples/infinite_recursion.bee b/examples/infinite_recursion.bee new file mode 100644 --- /dev/null +++ b/examples/infinite_recursion.bee @@ -0,0 +1,2 @@ +// FIXME: This currently fail with an unprecise error ... +{ x = _ => { print ":/"; x {} }; x {} } diff --git a/examples/inherit.bee b/examples/inherit.bee new file mode 100644 --- /dev/null +++ b/examples/inherit.bee @@ -0,0 +1,6 @@ +{ + a = 13 + b = 12 + // This is just syntaxic sugar for: { a = a; b = b } + return { a; b } +} diff --git a/examples/lexical_scoping.bee b/examples/lexical_scoping.bee new file mode 100644 --- /dev/null +++ b/examples/lexical_scoping.bee @@ -0,0 +1,8 @@ +{ + // This fail because x isn't accessible in the definition site of f + f = _ => print x + { + x = 42 + f {} + } +} diff --git a/examples/maths.bee b/examples/maths.bee new file mode 100644 --- /dev/null +++ b/examples/maths.bee @@ -0,0 +1,4 @@ +// Bee is a calculator. But you should not mix BigInt and Float! +(3.14 * 2.0) + 1.0 + +// FIXME: better demonstrate build-time checks, like the "divide by 0" guard diff --git a/examples/op_overloading.bee b/examples/op_overloading.bee new file mode 100644 --- /dev/null +++ b/examples/op_overloading.bee @@ -0,0 +1,13 @@ +{ + a = { + ops = { + // Let's redefine `+`, but for complex numbers: + add = x => y => { r = x.r + y.r ; i = x.i + y.i } + } + x = { r = 1.0; i = 0.0 } + { r = 0.0 ; i = 1.0 } + // This will fail since `-` is now undefined in this scope + // y = { r = 1.0; i = 0.0 } - { r = 0.0 ; i = 1.0 } + } + // But here, everything is back to normal! + b = 3.0 - 2.0 +} diff --git a/examples/parsing_errors.bee b/examples/parsing_errors.bee new file mode 100644 --- /dev/null +++ b/examples/parsing_errors.bee @@ -0,0 +1,6 @@ +// We try to display syntax hints to user when parsing error happens since +// tree-sitter messages are often a bit helpless ... +{ + x = return 42 + import hello +} diff --git a/examples/pipes.bee b/examples/pipes.bee new file mode 100644 --- /dev/null +++ b/examples/pipes.bee @@ -0,0 +1,6 @@ +{ + inc = x => x + 1 + triple = x => x * 3 + // Tho following line is equivalent to: triple (inc 3) + res = 3 |> (inc |> triple) +} diff --git a/examples/ranges.bee b/examples/ranges.bee new file mode 100644 --- /dev/null +++ b/examples/ranges.bee @@ -0,0 +1,1 @@ +2..5 // is equivalent to [2, 3, 4] diff --git a/examples/self.bee b/examples/self.bee new file mode 100644 --- /dev/null +++ b/examples/self.bee @@ -0,0 +1,10 @@ +// `self` is a pointer to the closest block in which a function is defined ... +// ... it's a weird semantic and this will likely change! + +{ + math = { + odd = x => if (x == 1) true else if (x == 0) false else (self.even (x - 1)) + even = x => if (x == 0) true else if (x == 1) false else (self.odd (x - 1)) + } + print (math.even 42) +} diff --git a/examples/spread.bee b/examples/spread.bee new file mode 100644 --- /dev/null +++ b/examples/spread.bee @@ -0,0 +1,4 @@ +{ + x = {a = 2; b = 3} + y = {a = 1; ...x; b = 4} // y now equals {a = 2; b = 4} +} diff --git a/examples/too_many_args.bee b/examples/too_many_args.bee new file mode 100644 --- /dev/null +++ b/examples/too_many_args.bee @@ -0,0 +1,5 @@ +{ + x = _ => { print ":(" } + // This will be check (and error) at build-time: + x 1 2 +} diff --git a/examples/webpack-demo/.gitignore b/examples/webpack-demo/.gitignore new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/examples/webpack-demo/package-lock.json b/examples/webpack-demo/package-lock.json new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/package-lock.json @@ -0,0 +1,1372 @@ +{ + "name": "webpack-demo", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "webpack-demo", + "version": "0.1.0", + "license": "GPLv2", + "dependencies": { + "bee-webpack-loader": "file:../../webpack-loader" + }, + "devDependencies": { + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } + }, + "../../webpack-loader": { + "version": "0.1.0", + "license": "GPLv2" + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", + "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.10.tgz", + "integrity": "sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/bee-webpack-loader": { + "resolved": "../../webpack-loader", + "link": true + }, + "node_modules/browserslist": { + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", + "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001580", + "electron-to-chromium": "^1.4.648", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001581", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", + "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.650", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.650.tgz", + "integrity": "sha512-sYSQhJCJa4aGA1wYol5cMQgekDBlbVfTRavlGZVr3WZpDdOPcp6a6xUnFfrt8TqZhsBYYbDxJZCjGfHuGupCRQ==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.90.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.0.tgz", + "integrity": "sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + } + } +} diff --git a/examples/webpack-demo/package.json b/examples/webpack-demo/package.json new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/package.json @@ -0,0 +1,21 @@ +{ + "name": "webpack-demo", + "version": "0.1.0", + "description": "Demo of bee-webpack-loader", + "private": true, + "source": "src/index.js", + "main": "dist/main.js", + "scripts": { + "build": "webpack", + "start": "node dist/main.js" + }, + "author": "Yvan Sraka ", + "license": "GPLv2", + "devDependencies": { + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "bee-webpack-loader": "file:../../webpack-loader" + } +} diff --git a/examples/webpack-demo/src/greetings.bee b/examples/webpack-demo/src/greetings.bee new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/src/greetings.bee @@ -0,0 +1,1 @@ +name => print "Hello, ${name}!" diff --git a/examples/webpack-demo/src/index.js b/examples/webpack-demo/src/index.js new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/src/index.js @@ -0,0 +1,3 @@ +import greetings from './greetings.bee' + +greetings("World") diff --git a/examples/webpack-demo/webpack.config.js b/examples/webpack-demo/webpack.config.js new file mode 100644 --- /dev/null +++ b/examples/webpack-demo/webpack.config.js @@ -0,0 +1,11 @@ +module.exports = { + mode: 'development', + module: { + rules: [ + { + test: /\.bee$/, + use: 'bee-webpack-loader' + } + ] + } +}; diff --git a/examples/weird_expr.bee b/examples/weird_expr.bee new file mode 100644 --- /dev/null +++ b/examples/weird_expr.bee @@ -0,0 +1,6 @@ +// This expression is evaluated to { a = 42; b = 42 } } +{ a = 42; b = { return a } } +// The return keyword replace the value of the Object in which it's called by +// its argument! + +// FIXME: better explain do-block semantics ... diff --git a/experimental/bootstrap.js b/experimental/bootstrap.js new file mode 100644 --- /dev/null +++ b/experimental/bootstrap.js @@ -0,0 +1,172 @@ +const sexpr = s => + { let i = 0; const rec = () => + { if (/\s/.test(s[i])) { ++i } + else if (s[i] === '(') { ++i; elements.push(rec()) } + else if (s[i] === ')') { ++i; return elements } + else if (s[i]== '"') + { let start = ++i; while (i < s.length && s[i] !== '"') { ++i } + elements.push(s.slice(start - 1, ++i)) } + else + { let start = i; while (i < s.length && !/\s|\(|\)/.test(s[i])) { ++i } + elements.push(s.slice(start, i)) } + return elements } + return rec() } + +const err = msg => { throw new Error(`\x1b[31m\x1b[1m${msg}\x1b[0m`) } +const assert = x => { if (!x) { err('Assertion failed') } } + +const parse = s => + { const sexpr = s => + { let i = 0 + const rec = () => + { let elements = [] + while (i < s.length) + { if (/\s/.test(s[i])) ++i + else if (s[i] === '(') { ++i; elements.push(rec()) } + else if (s[i] === ')') { ++i; return elements } + else if (s[i] == '"') + { let start = ++i + while (i < s.length && s[i] !== '"') ++i + elements.push(s.slice(start - 1, ++i)) } + else + { let start = i + while (i < s.length && !/\s|\(|\)/.test(s[i])) ++i + elements.push(s.slice(start, i)) } } + return elements } + return rec() } + // This parser always return an Array, which can be seen as like the whole + // expression is always implicitly wraped into parenthesis: + // assert(sexpr(``), []); + // This is an S-Expression parser, spaces are ignored: + // assert(sexpr(` (A ( B C ) D `), [ [ 'A', [ 'B', 'C' ] ], 'D' ]); + // Strings are written within " and could contains parenthesis: + // assert(sexpr(`(print "Hello :-)")`), [ [ 'print', '"Hello :-)"' ] ]); + // The parser will implicitly add missing closing parenthesis at the end of + // the input, and will ignore every extra closing parenthesis: + // assert(sexpr(`(((X`), [ [ [ [ 'X' ] ] ] ]); + // assert(sexpr(`X)))`), [ 'X' ]); + // The core design goal of this parser is to never fail, but here (for debug + // purposes) we provide a stricter version of it that only accept a subset of + // "valid" programs: + const x = sexpr(s) + return x.length == 1 ? x[0] : err("Malformed program") } + +const get = (obj, path) => + { const keys = path.split('.') + let current = obj + for (const key of keys) + { if (current[key] === undefined) return undefined + current = current[key] } + return current } + +const arrity = (e, n) => + { if (e.length !== n) err(`Expected ${n} arguments, got ${e.length}`) } + +const NATIVE = + { 'randInt': min => max => min + Math.floor(Math.random() * (max - min + 1)), + '+': a => b => a + b, + '==': a => b => a === b, + '|': a => b => a || b, + '!': a => !a, + // FIXME: function are eager, `if` need to be a keyword + // '?': a => b => c => a ? b : c, + 'print': s => console.log(s), + 'panic': e => console.log("Runtime Type Error:", e) } + +// KEYWORDS: let, do, fn, quote, case, return +const eval = (e, ENV = {}) => + { if (Array.isArray(e)) + { if (e[0] === 'quote') { return e.slice(1) } + else if (e[0] === 'do') + { ENV = { ...ENV } + for (let i = 1; i < e.length; ++i) eval(e[i], ENV) + return ENV } + else if (e[0] === 'let') + { arrity(e, 3); const x = eval(e[2], ENV); ENV[e[1]] = x; return x } + else if (e[0] === 'fn') + { if (e.length > 3) + { const sugar = x => + { if (x.length <= 3) return x + return ["fn", x[1], sugar(["fn", ...x.slice(2)])] } + return eval(sugar(e), ENV) } + arrity(e, 3) + return arg => eval(e[2], { ...ENV, [e[1]]: arg }) } + else if (e[0] === 'if') + { arrity(e, 4) + return eval(e[1], ENV) === true + ? eval(e[2], ENV) + : eval(e[3], ENV) } + else + { if (e.length > 2) + { const sugar = x => + { if (x.length <= 2) return x + return [sugar(x.slice(0, x.length - 1)), x[x.length - 1]] } + return eval(sugar(e), ENV) } + arrity(e, 2) + let fn = e[0] + if (Array.isArray(fn)) fn = eval(fn, ENV) + if (typeof fn !== 'function') + { const x = get(ENV, fn) + if (x !== undefined) fn = x + else + { if (NATIVE[fn]) fn = NATIVE[fn] + else err(`Function ${fn} not found`) } + if (typeof fn !== 'function') err(`${fn} is not a function`) } + return fn(eval(e[1], ENV, true)) } } + else + { if (e === true || e === "true") return true + if (e === false || e === "false") return false + if (/^-?\d+$/.test(e)) return parseInt(e) + if (/^".*"$/.test(e)) return e.slice(1, -1) + else + { const x = get(ENV, e) + if (x !== undefined) return x + else err(`Variable ${e} not found`) } } } +// `let` implicitly return the value assigned: +assert(eval(parse(`(let x 42)`)) == 42) +// ... but used within `do` block, it serve as field identifier: +assert(eval(parse(`(do (let x (do (let y 42))))`)).x.y == 42) +// `let` fields of a `do` struct could be accessed with `.` operator: +assert(eval(parse(`(do (let x (do (let y 42))) (let z x.y))`)).z == 42) +// instructions of a `do` block are evaluated in order: +assert(eval(parse(`(do (let x 42) (let y x) (let z y))`)).z == 42) +// and let definitions could be shadowed: +assert(eval(parse(`(do (let x 40) (let x 41) (let x 42))`)).x == 42) +// `do` blocks work as lexical scopes: +assert(eval(parse(`(do (let x 42) (do (let x 0)))`)).x == 42) +// `do` blocks could contains any instruction: +assert(eval(parse(`(do (+ 2 2) (let x 42))`)).x == 42) +// `fn` (function) support partial application: +assert(eval(parse(`(do (let x (fn x (+ x)))` + // x is (fn x (+ x)) + `(let x (x 2))` + // x is (+ 2) + `(let x (x 40))`) // x is ((+ 2) 40) +).x == 42) +// `fn` also capture their environment (here `y`): +assert(eval(parse(`(do (let x 0) + (let y 1) + (let x ((fn x (+ y x)) 41)))`)).x == 42) +// values: 42 41 1 41 +// `fn` have some nice syntaxic sugar, these 2 expressions are equivalents: +assert(eval(parse(`((fn x (fn y ((+ x) y))) 2 40)`)) == 42) +assert(eval(parse(`((fn x y ( + x y) ) 2 40)`)) == 42) +// ... this is call curryfication! +// Within a `do` block you can break the flow of computation by replacing the +// struct by a specific value: +// FIXME: assert(eval(parse(`(do (let x 42) (return x) (let x 0))`)) == 42) +// n.b. Haskell/Nix/OCaml/Scheme let X (in) Y keywords could be emulate by: +// (do (let X) (return Y)) +// FIXME: console.log(eval(parse(`(do (return (list A B C)))`))) +// TODO: explain and test `quote` ... +// eval(parse(` +// (do +// (let x (randInt 0 1)) +// (let y (if (== x 1) +// "foo" +// "bar")) +// (print y) +// (if (! (| "bar" "foo")) +// (panic "Err") +// (print "Ok"))) +// `)) // Print "foo\nOk" +// +// To be continued ... diff --git a/experimental/gc.h b/experimental/gc.h new file mode 100644 --- /dev/null +++ b/experimental/gc.h @@ -0,0 +1,405 @@ +/* + * This file should build without warning with clang version 14.0.0: + * > clang gc.h -std=c89 + * I tested it also with gcc version 11.3.0: + * > gcc gc.h -std=c89 + */ + +#include /* Needed by strerror_r(errno, ...) */ +#include /* Needed by fprintf(stderr, ...) */ +#include /* Needed by exit(EXIT_FAILURE) */ +#include /* Needed by memset, memmove */ +#include /* Needed by mmap, munmap, mremap */ +#include /* Needed by sysconf(_SC_PAGE_SIZE) */ +/* #include *//* Needed by VirtualAlloc, VirtualFree */ + +/* TODO ... */ +/* #define NDEBUG */ +/* #include */ + +/* Handy panic handlers defined later in this file ... */ +void gc_panic(const char* file, int line); +void* gc_unwrap(void* value, const char* file, int line); +#define panic() gc_panic(__FILE__, __LINE__) +#define unwrap(value) gc_unwrap(value, __FILE__, __LINE__) + +/* + * Memory management primitives + * ---------------------------- + * + * The purpose of this part is to define a gc_sbrk that allow memory allocation + * / liberation in roughly O(1) using internally mmap / munmap when such + * syscalls are OS defined. + * + * The memory is a continuous space of allocated adresse growing such as a heap + * segment would, we have few markers around our pages: + * + * ------ allocated memory adresses ----> + * |zzzzzzzz|yyyyy|xxxxxxxxxx|----------|~~ + * start last used stop + * + * n.b. an alternative noncontinuous (hardened for security concern) version of + * this allocator is just a stack of pointer (and so would require one more + * indirection) ... + * + */ + +static void* start = NULL; +static void* last = NULL; +static void* used = NULL; +static void* stop = NULL; +static size_t page_size = 0; + +/* TODO: This should better be a #define ... */ +void assert_gc_init(void) { + if (page_size == 0) { +#ifdef _WIN32 /* Windows */ + fprintf_s(stderr, "gc_init haven't be call before memory allocation\n"); + ExitProcess(EXIT_FAILURE); +#else /* Unix */ + fprintf(stderr, "gc_init haven't be call before memory allocation\n"); + exit(EXIT_FAILURE); +#endif + } +} + +#ifdef HARD_MODE + +/* + * HARD_MODE means "bring your memory" by giving to init function a start + * address and a size. + * + * TODO: should provide a callback mechanism to let user handle out-of-memory + * scenario gracefully. + */ + +void gc_init_hard_mode(void* ptr, size_t size) { + start = last = used = ptr; + stop = ptr + size; +} + +void* gc_sbrk(int increment) { /* TODO */ } + +/* if mmap() or VirtualAlloc() syscalls are available, then ... */ +#elif defined(_POSIX_MAPPED_FILES) || defined(_WIN32) + +/* gc_init should be call at the top of your main function */ +void gc_init(void) { +#ifdef _WIN32 /* Windows */ + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + page_size = sysInfo.dwPageSize; + start = last = used = + VirtualAlloc(NULL, page_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (start == NULL) { + fprintf_s(stderr, "Fail to initialize memory\n"); + ExitProcess(EXIT_FAILURE); + } +#else /* Unix */ + page_size = sysconf(_SC_PAGE_SIZE); + start = last = used = mmap(NULL, page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, -1, 0); + if (start == MAP_FAILED) { + fprintf(stderr, "Fail to initialize memory\n"); + exit(EXIT_FAILURE); + } +#endif + stop = start + page_size; +} + +/* + * gc_sbrk - Custom implementation of the sbrk function using mmap and munmap + * + * @increment: the number of bytes to increment the break value by. If increment + * is negative, the equivalent amount of memory is deallocated. If increment is + * zero, the current break value is returned. + * + * Returns a pointer to the start of the newly allocated memory block, or NULL + * if the allocation failed. + */ +void* gc_sbrk(int increment) { + assert_gc_init(); + void* current = stop; + if (increment > 0) { + int asked = ((increment / page_size) + 1) * page_size; +#ifdef _WIN32 /* Windows */ + void* ptr = + VirtualAlloc(stop, asked, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (ptr == NULL) + return NULL; +#else /* Unix */ + void* ptr = mmap(stop, asked, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, -1, 0); + if (ptr == MAP_FAILED) + return NULL; +#endif + stop = ptr + asked; + } + if (increment < 0) { + int asked = ((-increment) / page_size) * page_size; +#ifdef _WIN32 /* Windows */ + if (asked > 0 && !VirtualFree(stop - asked, 0, MEM_RELEASE)) + panic(); +#else /* Unix */ + if (asked > 0 && munmap(stop - asked, asked) != 0) + panic(); +#endif + stop -= asked; + } + return current; +} + +#else /* ... else, we rely on brk() ... */ + +/* Warning: brk and sbrk are deprecated on macOS ... */ +void* gc_sbrk(int increment) { + assert_gc_init(); + void* current = stop; + stop += increment; + if (brk(stop) != 0) { + return NULL; + } + return current; +} + +void gc_init(void) { + page_size = sysconf(_SC_PAGE_SIZE); + stop = (void*) (long int) brk(NULL); + start = last = used = gc_sbrk(page_size); + if (start == NULL) { + fprintf(stderr, "Fail to initialize memory\n"); + exit(EXIT_FAILURE); + } +} + +#endif + +/* + * Memory management utilities + * --------------------------- + * + * Memory allocation utilities that behave like you would expect, EXCEPT for the + * gc_free function! The gc_free free all memory allocated since the allocation + * of the pointer given to it (n.b. gc_realloc count as a new allocation). You + * can see pointers as timestamp, in this model if you gc_malloc A, then B, then + * C, and then gc_free B, implicitly it means that you freed C. Another mental + * model around this mechanism is the stack: memory allocated is free in the + * reverse order of allocations. + */ + +/* + * gc_malloc - Allocate memory block of given size + * + * @size: size of the memory block in bytes + * + * Returns a pointer to the allocated memory block + */ +void* gc_malloc(size_t size) { + int needed = used + size - stop; + if (needed > 0) { + if (gc_sbrk(needed) == NULL) { + errno = ENOMEM; + panic(); + } + stop += needed; + } + void* ptr = used; + used += size; + last = ptr; + return ptr; +} + +/* + * gc_calloc - Allocate and initialize memory block of given size + * + * @n: number of elements in the array + * @size: size of each element in bytes + * + * Returns a pointer to the allocated and initialized memory block + */ +void* gc_calloc(size_t n, size_t size) { + size *= n; + return memset(gc_malloc(size), 0, size); +} + +/* + * gc_realloc - Reallocate memory block to a new size + * + * @ptr: pointer to the original memory block + * @size: new size of the memory block in bytes + * + * Returns a pointer to the reallocated memory block + */ +void* gc_realloc(void* ptr, size_t size) { + if (ptr == last) + used = last; + void* new_ptr = gc_malloc(size); + if (ptr != last && ptr != NULL) + memmove(new_ptr, ptr, size); + return new_ptr; +} + +/* + * gc_free - Free allocated memory block + * + * @ptr: pointer to the memory block to be freed + */ +void gc_free(void* ptr) { + if (ptr == NULL || start > ptr || ptr > used) + return; + used = ptr; + int unused = stop - used; + if (gc_sbrk(-unused) != NULL) + stop -= unused; +} + +/* + * Boxed utilities + * --------------- + * + * Keep track of the size of items allocated on the heap could be tiresome, here + * is a simple type and utilities to keep track of the size of memory allocated + * to a pointer in "boxed" fashion. + */ + +typedef struct Box { + void* data; + size_t size; +} Box; + +/* Boxed version of: void* gc_malloc(size_t size) */ +Box boxed_malloc(size_t size) { + Box ret = {gc_malloc(size), size}; + return ret; +} + +/* Boxed version of: void* gc_calloc(size_t n, size_t size) */ +Box boxed_calloc(size_t n, size_t size) { + Box ret = {gc_calloc(n, size), n * size}; + return ret; +} + +/* Boxed version of: void* gc_realloc(void* ptr, size_t size) */ +Box boxed_realloc(Box x, size_t size) { + Box ret = {gc_realloc(x.data, size), size}; + return ret; +} + +/* Boxed version of: void gc_free(void* ptr) */ +void boxed_free(Box x) { + gc_free(x.data); +} + +/* + * Collector + * --------- + * + * TODO: This would be the core logic of the "destructor" mechanism, it should + * work recursively but for now only accept a dumb Box. Thanks to Nao, I will + * reimplement it using an OCaml like Object abstraction + * https://git.naomini.tel/nao/lysp/src/c-interp/object.c + * + * gc_collect take an object (or later a list of objects), and, in increasing + * pointer order, move objects (and compact memory) starting at target pointer + * address: target should be the value of the beginning of the heap region + * associated to your stack frame, you can obtain it using gc_malloc(0) at the + * start of your function definition. + * + * Then gc_collect will gc_free the memory after the last moved value. Collect + * has a heuristic criterion to save on moving values (e.g., the implementation + * doesn’t move overlapping memory). Here is a little schema: + * + * target + * |---------|---A---B----C---| + * *** collect(target, C) *** + * |---------|ABC| + */ + +/* + * Increasing this value could speed up programs while being more greedy on + * memory usage ... + */ +#define HEURISTIC_VALUE 0 + +void gc_collect(void* target, Box x) { + /* TODO: if ptr == NULL ... panic? */ + if (target >= x.data || (x.data - target) < x.size + HEURISTIC_VALUE) + return; + /* + * #ifdef MREMAP_MAYMOVE + * TODO: There is likely a efficient memmove implementation using ... + * mremap(x.data, x.size, x.size, MREMAP_MAYMOVE | MREMAP_FIXED, target) + * ... and the right munmap combination on modern Linux! + */ + memmove(target, x.data, x.size); + gc_free(target + x.size); +} + +/* + * Panic handler + * ------------- + * + * Just as a bonus, panic handler that magical unwind all allocated objects :) + */ + +/* + * panic - Print error message and exit with failure status + * + * @file: file name where the error occurred + * @line: line number where the error occurred + */ +#ifdef _WIN32 /* Windows */ + +void gc_panic(const char* file, int line) { + DWORD errorCode = GetLastError(); + /* + * TODO: Windows syscalls doesn't use errno ... how boring to trigger + * cross-platform errors in my code ... + */ + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, NULL); + fprintf(stderr, "Error: %s\n", (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + gc_free(start); + ExitProcess(EXIT_FAILURE); +} + +#else /* Unix */ + +void gc_panic(const char* file, int line) { + char buffer[256]; + int result = strerror_r(errno, buffer, sizeof buffer); + if (result == 0) { + fprintf(stderr, "Error (%s:%d): %s\n", file, line, buffer); + } else { + fprintf(stderr, "Error (%s:%d): strerror_r() failed with error code %d\n", + file, line, result); + } + gc_free(start); + exit(EXIT_FAILURE); +} + +#endif + +/* + * unwrap - Check if a value is NULL and call panic if it is + * + * @value: value to check + * @file: file name where the error occurred + * @line: line number where the error occurred + * + * Returns the value if it is not NULL + */ +void* gc_unwrap(void* value, const char* file, int line) { + if (value == NULL) + gc_panic(file, line); + return value; +} \ No newline at end of file diff --git a/experimental/playground.html b/experimental/playground.html new file mode 100644 --- /dev/null +++ b/experimental/playground.html @@ -0,0 +1,13 @@ + + diff --git a/flake.lock b/flake.lock new file mode 100644 --- /dev/null +++ b/flake.lock @@ -0,0 +1,130 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1706683685, + "narHash": "sha256-FtPPshEpxH/ewBOsdKBNhlsL2MLEFv1hEnQ19f/bFsQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5ad9903c16126a7d949101687af0aa589b1d7d3d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1706487304, + "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1706753617, + "narHash": "sha256-ZKqTFzhFwSWFEpQTJ0uXnfJBs5Y/po9/8TK4bzssdbs=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "58be43ae223034217ea1bd58c73210644031b687", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 --- /dev/null +++ b/flake.nix @@ -0,0 +1,16 @@ +{ + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; + }; + outputs = { flake-utils, nixpkgs, rust-overlay, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { inherit system overlays; }; + in { + defaultPackage = import ./default.nix { inherit pkgs system; }; + devShell = import ./shell.nix { inherit pkgs system; }; + }); +} diff --git a/index.js b/index.js new file mode 100644 --- /dev/null +++ b/index.js @@ -0,0 +1,14 @@ +// FIXME: implement a LSP and a DAP ... +// https://code.visualstudio.com/api/language-extensions/language-server-extension-guide +// https://microsoft.github.io/debug-adapter-protocol/ + +const Parser = require('tree-sitter'); +const BeeLang = require('./tree-sitter-bee-lang'); + +const parser = new Parser(); +parser.setLanguage(BeeLang); + +// const sourceCode = `{ x = x => y => add x y; y = x 2 3; }`; +// const tree = parser.parse(sourceCode); + +// console.log(tree.rootNode.toString()); diff --git a/package-lock.json b/package-lock.json new file mode 100644 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,475 @@ +{ + "name": "bee-lang", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bee-lang", + "version": "0.1.0", + "license": "GPLv2", + "dependencies": { + "tree-sitter": "^0.20.6", + "tree-sitter-bee-lang": "file:tree-sitter" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/node-abi": { + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", + "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-sitter": { + "version": "0.20.6", + "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.20.6.tgz", + "integrity": "sha512-GxJodajVpfgb3UREzzIbtA1hyRnTxVbWVXrbC6sk4xTMH5ERMBJk9HJNq4c8jOJeUaIOmLcwg+t6mez/PDvGqg==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.18.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/tree-sitter-bee-lang": { + "resolved": "tree-sitter", + "link": true + }, + "node_modules/tree-sitter-cli": { + "version": "0.20.8", + "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.8.tgz", + "integrity": "sha512-XjTcS3wdTy/2cc/ptMLc/WRyOLECRYcMTrSWyhZnj1oGSOWbHLTklgsgRICU3cPfb0vy+oZCC33M43u6R1HSCA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "tree-sitter": "cli.js" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "tree-sitter": { + "version": "0.1.0", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "nan": "^2.18.0" + }, + "devDependencies": { + "tree-sitter-cli": "^0.20.8" + } + }, + "tree-sitter-bee-lang": { + "version": "0.0.1", + "extraneous": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "nan": "^2.18.0" + }, + "devDependencies": { + "tree-sitter-cli": "^0.20.8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "bee-lang", + "version": "0.1.0", + "description": "", + "main": "index.js", + "author": "Yvan Sraka ", + "license": "GPLv2", + "dependencies": { + "tree-sitter": "^0.20.6", + "tree-sitter-bee-lang": "file:tree-sitter" + } +} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1,1 @@ +stable diff --git a/shell.nix b/shell.nix new file mode 100644 --- /dev/null +++ b/shell.nix @@ -0,0 +1,24 @@ +# If you plan to use `nix-shell` you have first to: +# +# $ nix-channel --add https://github.com/oxalica/rust-overlay/archive/master.tar.gz rust-overlay +# $ nix-channel --update +{ pkgs ? import { overlays = [ (import ) ]; } +, system ? builtins.currentSystem }: +with pkgs; +let + toolchain = (rust-bin.fromRustupToolchainFile ./rust-toolchain).override { + extensions = [ "rust-src" "rust-analyzer" "clippy" ]; + }; +in mkShell { + buildInputs = [ nodejs toolchain tree-sitter ] + ++ (if system == "x86_64-linux" then [ mold ] else [ ]); + RUST_BACKTRACE = "full"; + shellHook = '' + if [ ! -f "tree-sitter-bee-lang/src/parser.c" ]; then + pushd tree-sitter-bee-lang + tree-sitter generate + popd + fi + ''; + +} diff --git a/src/bin/bee/build.rs b/src/bin/bee/build.rs new file mode 100644 --- /dev/null +++ b/src/bin/bee/build.rs @@ -0,0 +1,175 @@ +use bee::build::{build, Error, PRELUDE}; +use bee::cache::{cached, relative}; +use bee::cli::BuildArgs; +use bee::codegen::{is_valid_extension, is_valid_filename}; +use bee::parser::Span; +use log::{error, info, warn}; +use miette::miette; +use owo_colors::{OwoColorize, Stream::Stdout, Style}; +use regex::Regex; +use std::cmp::min; +use std::collections::{BTreeSet, HashMap}; +use std::fs::{self, File}; +use std::io::{self, IsTerminal, Read, Write}; + +/// TODO: write documentation... +pub(crate) fn handle(args: &BuildArgs) -> exitcode::ExitCode { + let input_piped = !io::stdin().is_terminal(); + let output_piped = !io::stdout().is_terminal(); + + if args.output.is_none() && !output_piped { + error!("output was not specified with `-o`/`--output` or stdout piped"); + return exitcode::USAGE; + } + if args.input.is_some() && input_piped { + error!("I'm confuse, you specified both an input file and piped stdin"); + return exitcode::USAGE; + } + if args.output.is_some() && output_piped { + error!( + "I'm confuse, you specified both an output file with `-o`/`--output` and piped stdout" + ); + return exitcode::USAGE; + } + + let src = if input_piped { + let mut src = String::new(); + io::stdin().read_to_string(&mut src).unwrap(); + src + } else { + let mut input = match &args.input { + Some(x) => x.clone(), + None => "./main.bee".into(), + }; + if let Ok(metadata) = fs::metadata(&input) { + if metadata.is_dir() { + input = input.join("main.bee"); + } + }; + match fs::read_to_string(&input) { + Ok(src) => src, + Err(err) => { + error!("while reading file `{}`: {err}", input.display()); + return exitcode::NOINPUT; + } + } + }; + // FIXME: This error isn't really meaningful and isn't triggered if an empty + // file is imported ... + // if src.trim() == "" { + // error!("the given input file is empty"); + // return exitcode::NOINPUT; + // } + + let filename = if input_piped { + "/dev/stdin".into() + } else { + let path = match &args.input { + Some(x) => x.clone(), + None => "./main.bee".into(), + }; + if let Ok(metadata) = fs::metadata(&path) { + if metadata.len() > 50000 { + warn!("file `{}` seems big, consider spliting it into modules to better use build cache", path.display()); + } + } + if !is_valid_extension(&path) { + error!("file `{}` extension should be `.bee`", path.display()); + return exitcode::USAGE; + } + if !is_valid_filename(&path) { + error!( + "file path `{}` contains illegal characters: `:`, `.`, `[` or `]`", + path.display() + ); + return exitcode::USAGE; + } + fs::canonicalize(&path).unwrap() + }; + + let mut targets = match &args.targets { + Some(x) => Regex::new(r"[, ]").unwrap().split(x).collect(), + None => BTreeSet::new(), + }; + if targets.contains("debug") && targets.contains("release") { + error!("both @debug and @release mutually exclusive targets are given as arguments"); + return exitcode::USAGE; + } + if !targets.contains("release") { + targets.insert("debug"); + } + + match if input_piped { + warn!("build cache doesn't store piped input"); + build(src.as_bytes(), &filename, &targets) + } else { + cached(src.as_bytes(), &filename, &targets, build) + } { + Ok(output) => { + // FIXME: print the `lazy_static` stack of WARNINGS on stderr + if output_piped { + println!("{}", output); + } else { + let mut file = File::create(args.output.clone().unwrap()).unwrap(); + file.write_all(output.as_bytes()).unwrap(); + } + exitcode::OK + } + Err(err) => { + error(err); + exitcode::DATAERR // FIXME: rather use a custom error > 78 + } + } +} + +fn error(err: Error) { + let Error { + msg, + code, + help, + stacktrace, + } = err; + println!(); + error!( + "{} {}", + code.if_supports_color(Stdout, |text| text.style(Style::new().bold().red())), + msg, // FIXME: color every verbatim content between `` + ); + if let Some(stacktrace) = stacktrace { + let total = min(5, stacktrace.len()); + let stacktrace = &stacktrace[..total]; + let mut map = HashMap::new(); + for (index, span) in stacktrace.iter().enumerate() { + map.entry(span.filename.clone()) + .or_insert_with(Vec::new) + .push((span, index)); + } + let grouped_span_by_filename: Vec> = map.into_values().collect(); + for spans in grouped_span_by_filename { + let filename = &spans[0].0.filename; + let src = if filename.display().to_string() == "prelude" { + PRELUDE.to_owned() + } else { + fs::read_to_string(filename).unwrap() + }; + let named_src = miette::NamedSource::new(relative(filename).display().to_string(), src); + let labels: Vec<_> = spans + .iter() + .map(|span| { + miette::LabeledSpan::at( + span.0.clone().byte_range, + format!("{}/{total}", span.1 + 1), + ) + }) + .collect(); + let report = match help { + Some(ref help) => miette!(help = help, labels = labels, ""), + None => miette!(labels = labels, ""), + }; + eprint!("{:?}", report.with_source_code(named_src)); + } + } else if let Some(help) = help { + info!("help: {help}"); + } + // FIXME: println!("\n... to display a more verbose message use: {}", format!("bee explain {code}")); +} diff --git a/src/bin/bee/cache.rs b/src/bin/bee/cache.rs new file mode 100644 --- /dev/null +++ b/src/bin/bee/cache.rs @@ -0,0 +1,78 @@ +use bee::cache::CACHE_ROOT; +use bee::cli::CacheArgs; +use log::{error, info}; +use std::fs; +use std::path::Path; +use walkdir::WalkDir; + +/// TODO: write documentation... +pub(crate) fn handle(args: &CacheArgs) -> exitcode::ExitCode { + match args { + CacheArgs::Clear(args) => { + if args.all && args.input.is_some() { + error!("I'm confused ... you give to `bee cache` command an input and the `--all` arg, there are mutually exclusive"); + return exitcode::USAGE; + } + if !args.all && args.input.is_none() { + error!("`bee cache` command take either an input or the `--all` arg (that remove all of the global build cache)"); + return exitcode::USAGE; + } + if args.all { + if CACHE_ROOT.exists() { + fs::remove_dir_all(CACHE_ROOT.clone()).unwrap(); + } + info!("The build cache have been globally cleared."); + } + if let Some(input) = &args.input { + // FIXME: be able to remove a file or folder in cache that does not exist on filesystem + if !input.exists() { + error!("file or folder {} does not exist", input.display()); + return exitcode::NOINPUT; + } + let cache_path = &CACHE_ROOT.join(fs::canonicalize(input).unwrap()); + if cache_path.is_dir() { + fs::remove_dir_all(cache_path).unwrap(); + } + if cache_path.is_file() { + fs::remove_file(cache_path).unwrap(); + fs::remove_file(cache_path.with_extension("deps")).unwrap(); + } + } + exitcode::OK + } + CacheArgs::Gc => { + for entry in WalkDir::new(CACHE_ROOT.clone()) { + let entry = entry.unwrap(); + if entry.file_type().is_file() { + let cache_path = entry.path(); + if cache_path.extension().unwrap() == "js" { + let path = cache_path.display().to_string(); + let path = path + .strip_prefix(&CACHE_ROOT.display().to_string()) + .unwrap(); + // FIXME: this will not play well with filename + // containing `.` (other than the `.bee` extension) ... + let path = format!("{}.bee", path.split('.').collect::>()[0]); + let path = Path::new(&path); + // FIXME: understand why it's /.prelude... and not /prelude... + if !path.exists() && !path.display().to_string().starts_with("/.") { + fs::remove_file(cache_path).unwrap(); + fs::remove_file(cache_path.with_extension("deps")).unwrap(); + info!("Cleared `{}` from build cache ...", path.display()) + } + } + } + } + info!("The build cache garbage-collection (GC) is completed."); + exitcode::OK + } + CacheArgs::Prune(_) => { + error!("`bee cache prune` command is not yet implemented"); + info!( + "To keep up-to-date with the project, subscribe to \"announce\" mailing-list: +https://lists.sr.ht/~yvan-sraka/bee-lang-announce" + ); + exitcode::UNAVAILABLE + } + } +} diff --git a/src/bin/bee/explain.rs b/src/bin/bee/explain.rs new file mode 100644 --- /dev/null +++ b/src/bin/bee/explain.rs @@ -0,0 +1,12 @@ +use bee::cli::ExplainArgs; +use log::{error, info}; + +/// TODO: write documentation... +pub(crate) fn handle(_args: &ExplainArgs) -> exitcode::ExitCode { + error!("`bee explain` command is not yet implemented"); + info!( + "To keep up-to-date with the project, subscribe to \"announce\" mailing-list: +https://lists.sr.ht/~yvan-sraka/bee-lang-announce" + ); + exitcode::UNAVAILABLE +} diff --git a/src/bin/bee/main.rs b/src/bin/bee/main.rs new file mode 100644 --- /dev/null +++ b/src/bin/bee/main.rs @@ -0,0 +1,84 @@ +mod build; +mod cache; +mod explain; +mod run; + +use bee::cli::{Cli, Commands}; +use clap::{CommandFactory, Parser}; +#[cfg(debug_assertions)] +use log::warn; +use owo_colors::{OwoColorize, Stream::Stdout, Style}; +use std::io::Write; + +fn main() { + let env = env_logger::Env::default() + .filter_or("BEE_LOG", "info") + .write_style_or("BEE_LOG_STYLE", "auto"); + env_logger::Builder::from_env(env) + .format(|buf, record| { + writeln!( + buf, + "{}{}", + match record.level() { + log::Level::Error => "error: " + .if_supports_color(Stdout, |text| text.style(Style::new().red().bold())) + .to_string(), + log::Level::Warn => "warning: " + .if_supports_color(Stdout, |text| text.style(Style::new().yellow().bold())) + .to_string(), + log::Level::Info => "".to_owned(), + log::Level::Debug => "debug: ".to_owned(), + log::Level::Trace => "trace: ".to_owned(), + }, + record.args() + ) + }) + .init(); + #[cfg(debug_assertions)] + warn!("you use a debug build of bee, the build cache is disabled"); + #[cfg(not(debug_assertions))] + human_panic::setup_panic!(); + // FIXME: I forked `human_panic` to customize the message: + // let prev = std::panic::take_hook(); + // std::panic::set_hook(Box::new(move |info| { + // prev(info); + // })); + + // FIXME: This break NO_COLOR support, so I forked `miette` ... + // miette::set_hook(Box::new(|_| { + // Box::new( + // miette::MietteHandlerOpts::new() + // .graphical_theme(miette::GraphicalTheme { + // characters: miette::ThemeCharacters { + // warning: "".into(), + // error: "".into(), + // advice: "".into(), + // ..miette::ThemeCharacters::unicode() + // }, + // ..Default::default() + // }) + // .build(), + // ) + // })) + // .unwrap(); + + let args = std::env::args().collect::>(); + if args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) { + Cli::command().print_help().unwrap(); + println!( + " +To keep up-to-date with the project, subscribe to \"announce\" mailing-list: +https://lists.sr.ht/~yvan-sraka/bee-lang-announce bzz bzz bzz" + ); + std::process::exit(0); + } + + let cli = Cli::parse(); + + std::process::exit(match &cli.command { + Commands::Build(args) => build::handle(args), + Commands::Cache(args) => cache::handle(args), + Commands::Run(args) => run::handle(args), + Commands::Explain(args) => explain::handle(args), + }); +} diff --git a/src/bin/bee/run.rs b/src/bin/bee/run.rs new file mode 100644 --- /dev/null +++ b/src/bin/bee/run.rs @@ -0,0 +1,12 @@ +use bee::cli::RunArgs; +use log::{error, info}; + +/// TODO: write documentation... +pub(crate) fn handle(_args: &RunArgs) -> exitcode::ExitCode { + error!("`bee run` command is not yet implemented"); + info!( + "To keep up-to-date with the project, subscribe to \"announce\" mailing-list: +https://lists.sr.ht/~yvan-sraka/bee-lang-announce" + ); + exitcode::UNAVAILABLE +} diff --git a/src/build.rs b/src/build.rs new file mode 100644 --- /dev/null +++ b/src/build.rs @@ -0,0 +1,58 @@ +use crate::codegen::{codegen, targets_codegen}; +use crate::eval::eval; +use crate::parser::{parse, Span}; +use log::{trace, warn}; +use std::collections::BTreeSet; +use std::path::Path; +use std::sync::{Arc, Mutex}; + +/// TODO: write documentation... +pub const PRELUDE: &str = include_str!("./prelude.bee"); + +lazy_static! { + /// TODO: write documentation... + static ref WARNINGS: Arc>> = + Arc::new(Mutex::new(vec![])); +} + +/// Custom error type that is use to produce a compiler error +#[derive(Debug)] +pub struct Error { + /// TODO: write documentation... + pub code: String, // FIXME: error code should be an enum! + /// TODO: write documentation... + pub msg: String, + /// TODO: write documentation... + pub stacktrace: Option>, + /// TODO: write documentation... + pub help: Option, +} + +/// TODO: write documentation... +pub fn build(src: &[u8], filename: &Path, targets: &BTreeSet<&str>) -> Result { + // FIXME: give a try to `imbl` crate rather than cloning a BTreeSet ... + let mut targets = targets.clone(); + if targets.contains("abstract") { + warn!("@abstract target is reserved to compiler internals and is ignored when passed as CLI argument") + } + let tree = parse(src); + trace!("Parsing ... done"); + // FIXME: typing (abstract interpretation of program) should not be ran if + // a .bee.t file already exist and is more recent than the .bee file built + targets.insert("abstract"); + let js = codegen(&tree, src, filename, &targets)?; + // ... yes yes ... we run codegen BEFORE typing ... + trace!("Codegen ... done"); + // FIXME: had a --disable-checks CLI arg that remove this step? + eval(format!("{}{js}", targets_codegen(&targets)))?; + targets.remove("abstract"); + trace!("Typing ... done"); + let js = codegen(&tree, src, filename, &targets)?; + // FIXME: have a @release target that minify the output ... + // ... e.g. with https://github.com/wilsonzlin/minify-js + Ok(format!( + "{}{js} +module.exports = __bee_export;", + targets_codegen(&targets) + )) +} diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,139 @@ +use crate::build::Error; +use crate::VERSION; +use directories::ProjectDirs; +use log::info; +use owo_colors::{OwoColorize, Stream::Stdout, Style}; +use std::collections::{BTreeSet, HashMap}; +use std::env; +#[cfg(not(debug_assertions))] +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +lazy_static! { + /// TODO: write documentation... + static ref DEPENDENCIES: Arc>>> = + Arc::new(Mutex::new(HashMap::new())); + /// TODO: write documentation... + pub static ref CACHE_ROOT: PathBuf = ProjectDirs::from("org", "yvan-sraka", "bee-lang") + .unwrap() + .cache_dir() + .join(VERSION); + /// TODO: write documentation... + static ref CURRENT_DIR: PathBuf = env::current_dir().unwrap(); +} + +/// TODO: write documentation... +#[inline(always)] +pub(crate) fn register_dependency(filename: &Path, dependency: &Path) { + DEPENDENCIES + .lock() + .unwrap() + .entry(filename.into()) + .or_default() + .push(dependency.into()); +} + +#[cfg(not(debug_assertions))] +fn dependencies_changed(cache_file: &Path, targets: &BTreeSet<&str>) -> bool { + let mut deps_file = cache_file.to_path_buf(); + deps_file.set_extension("deps"); + for dep in fs::read_to_string(&deps_file).unwrap().lines() { + let dep = Path::new(dep); + match use_cached_version(dep, targets) { + Ok(_) => {} + Err(_) => return true, + } + } + false +} + +#[cfg(not(debug_assertions))] +fn use_cached_version(filename: &Path, targets: &BTreeSet<&str>) -> Result { + let mut cached_file = CACHE_ROOT.join(format!(".{}", filename.display())); + cached_file.set_extension(format!( + "{}.js", + targets + .iter() + .map(|x| x.to_owned()) + .collect::>() + .join(".") + )); + if cached_file.exists() + && (filename.display().to_string() == "prelude" + || (cached_file.metadata().unwrap().modified().unwrap() + > filename.metadata().unwrap().modified().unwrap() + && !dependencies_changed(&cached_file, targets))) + { + Ok(cached_file) + } else { + Err(cached_file) + } +} + +type Builder = fn(&[u8], &Path, &BTreeSet<&str>) -> Result; + +/// TODO: write documentation... +pub fn cached( + src: &[u8], + filename: &Path, + targets: &BTreeSet<&str>, + callback: Builder, +) -> Result { + #[cfg(debug_assertions)] + { + build_log(filename, targets, false); + callback(src, filename, targets) + } + // Disabling caching in debug mode save hours as you may not want to return + // artifacts that doesn't reflect your changes as you're hacking on the + // compiler ;) + #[cfg(not(debug_assertions))] + Ok(match use_cached_version(filename, targets) { + Ok(cached_file) => { + build_log(filename, targets, true); + fs::read_to_string(cached_file).unwrap() + } + Err(cached_file) => { + build_log(filename, targets, false); + let result = callback(src, filename, targets)?; + + fs::create_dir_all(cached_file.parent().unwrap()).unwrap(); + fs::write(&cached_file, &result).unwrap(); + + let mut deps_file = cached_file.to_path_buf(); + deps_file.set_extension("deps"); + let deps = match DEPENDENCIES.lock().unwrap().get(filename) { + Some(x) => x + .iter() + .map(|x| x.display().to_string()) + .collect::>() + .join("\n"), + None => "".to_owned(), + }; + fs::write(&deps_file, deps).unwrap(); + + result + } + }) +} + +/// TODO: write documentation... +#[inline(always)] +fn build_log(filename: &Path, targets: &BTreeSet<&str>, cached: bool) { + if !targets.contains("abstract") { + info!( + "Building {} {}...", + relative(filename) + .display() + .if_supports_color(Stdout, |text| text.style(Style::new().bold().bright_cyan())), + if cached { "(cached) " } else { "" } + ); + } +} + +/// TODO: write documentation... +#[inline(always)] +pub fn relative(path: &Path) -> PathBuf { + pathdiff::diff_paths(path, CURRENT_DIR.to_owned()).unwrap_or(path.to_owned()) +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,87 @@ +use std::path::PathBuf; + +/// 🌸 🌼 🐝 The Bee programming language compiler 🌺 🌼 🌸 +#[derive(clap::Parser, Debug)] +#[clap(author, version, about, long_about = None)] +pub struct Cli { + #[clap(subcommand)] + pub command: Commands, +} + +/// Main list of commands that can take `bee` CLI as argument +#[derive(clap::Subcommand, Debug)] +pub enum Commands { + /// Builds a given file or the `main.bee` within a given folder (by default the current folder) + Build(BuildArgs), + /// Manage build cache used by Bee compiler + #[clap(subcommand)] + Cache(CacheArgs), + /// Print a more verbose explaination for a given compiler error code + Explain(ExplainArgs), + /// Run a given script without compiling it to ECMAScript + Run(RunArgs), + // FIXME: add REPL command ... with cool message explaining the feature is missing :'( +} + +/// Arguments for the `build` command +#[derive(clap::Parser, Debug)] +pub struct BuildArgs { + /// Input file name (.bee), that can also be piped in + pub input: Option, + + /// Output file name (.js), that can also be piped out + #[clap(short, long)] + pub output: Option, + + /// List of (comma or space separated) compiler targets + #[clap(short, long)] + pub targets: Option, +} + +/// Subcommands of the `cache` command +#[derive(clap::Subcommand, Debug)] +pub enum CacheArgs { + /// Clears the cache based on various criteria + Clear(CacheClearArgs), + /// Performs garbage collection on the cache, removing entries for files that no longer exist in the user’s file system + Gc, + /// Removes items from the cache based on age + Prune(CachePruneArgs), +} + +/// TODO: write documentation... +#[derive(clap::Parser, Debug)] +pub struct CacheClearArgs { + /// Clears the cache for a specific path (file or folder) + pub input: Option, + + /// Clears the cache for a specific file and its dependencies + #[clap(short, long)] + pub deps: Option, + + /// Clears the entire build cache + #[clap(short, long)] + pub all: bool, + // FIXME: let user pass a --targets argument to allow more fine grained + // control over cache management? +} + +/// TODO: write documentation... +#[derive(clap::Parser, Debug)] +pub struct CachePruneArgs { + /// Removes cache items that were created before a specific date + #[clap(short, long)] + before: Option, + + /// Removes cache items that are older than a specified duration (e.g., “30d” for 30 days) + #[clap(short, long)] + older_than: Option, +} + +/// TODO: write documentation... +#[derive(clap::Parser, Debug)] +pub struct ExplainArgs; + +/// TODO: write documentation... +#[derive(clap::Parser, Debug)] +pub struct RunArgs; diff --git a/src/codegen.rs b/src/codegen.rs new file mode 100644 --- /dev/null +++ b/src/codegen.rs @@ -0,0 +1,641 @@ +use crate::build::{Error, PRELUDE}; +use crate::cache::{cached, register_dependency}; +#[cfg(feature = "rayon")] +use crate::parser::Nodes; +use crate::parser::{parse, Span}; +#[cfg(feature = "rayon")] +use rayon::prelude::*; +use regex::{Captures, Regex}; +use std::collections::BTreeSet; +use std::fs; +use std::path::{Path, PathBuf}; + +/// This is a naive approach to code generation intended for experimenting with +/// the semantics of a Bee program. +/// +/// The main idea is to generate JS values that can be embedded in a JS script. +/// For example, the Bee expression `[1 2 3]` should produce JS code that, once +/// evaluated, equals `[1, 2, 3]`. +/// +/// The code generation should be capable of taking as input both the AST built +/// by parsing (as it currently does) and an AST augmented with type +/// annotations (and other invariants) inferred from static analysis. These +/// annotations will be cached in a `.bee.t` file, which users are advised to +/// distribute with their script. +/// +/// This setup will enable a fast build mode (without typing if `.bee.t` is +/// missing) and a slow one (typing is required if `.bee.ts` is missing or +/// outdated). The fast compilation mode could be dropped if a Bee VM is +/// implemented, as users who want to quickly evaluate their programs might +/// prefer an interpreter over a compiler. +/// +/// Currently, there is a WIP JavaScript implementation of a VM. One strategy +/// could then be to perform codegen by simply serializing the AST to JSON and +/// appending the JS runtime next to it. The generated JS will likely not be +/// handled efficiently by JavaScript's JIT and tooling, but this approach +/// allows more room for implementing reflexivity features without relying on +/// JS's `eval`. +/// +/// Currently, the codegen always adds debug symbols to the JS output, but this +/// should be made optional. For example, a `--release` mode could omit the +/// symbols and run a JS minification pass. +pub fn codegen( + tree: &tree_sitter::Tree, + src: &[u8], + filename: &Path, + targets: &BTreeSet<&str>, +) -> Result { + let prelude = PRELUDE.as_bytes(); + Ok(format!( + "// RUNTIME +{} +// PRELUDE +__bee_env = {}; +// USER CODE +const __bee_export = {}; +", + include_str!("./runtime.js"), + cached(prelude, Path::new("prelude"), targets, codegen_module)?, + rec_codegen(&tree.root_node(), src, filename, targets)? + )) +} + +/// TODO: write documentation... +#[inline(always)] +pub fn codegen_module( + src: &[u8], + filename: &Path, + targets: &BTreeSet<&str>, +) -> Result { + rec_codegen(&parse(src).root_node(), src, filename, targets) +} + +fn rec_codegen( + node: &tree_sitter::Node, + src: &[u8], + filename: &Path, + targets: &BTreeSet<&str>, +) -> Result { + let kind = node.kind(); + + let span = Span { + byte_range: node.byte_range(), + filename: filename.to_owned(), + }; + + if node.is_error() || node.is_missing() { + // FIXME: have a codegen::Error type + Err(Error { + msg: format!( + "parsing error{}", + if node.is_missing() { + format!(": `{}` is missing", kind) + } else { + "".to_owned() + } + ), + help: hint(node.utf8_text(src).unwrap()), + stacktrace: Some(vec![span.clone()]), + code: "PA001".to_owned(), + })?; + } + + let children = (0..node.child_count()) + .map(|i| node.child(i).unwrap()) + .filter(|x| { + !matches!( + x.kind(), + "," | ";" + | "." + | "..." + | "(" + | ")" + | "[" + | "]" + | "{" + | "}" + | "\n" + | "=" + | "=>" + | "$" + | "block_comment" + | "inline_comment" + | "else" + | "if" + | "import" + | "native" + | "panic" + | "return" + | "then" + ) + }) + .collect::>(); + + Ok(match kind { + "apply" => { + let xs = children_codegen(children, src, filename, targets)?; + let id = &xs[0]; + let args = xs[1..].join(", "); + format!("__bee_fn_apply({id}, [{args}], \"{span}\")") + } + + "arg" | "bool" | "delimiter" | "expr" | "field" | "source_file" | "statement" | "value" => { + children_codegen(children, src, filename, targets)?.join("") + } + + "id" => { + // FIXME: warning if `_` is used as an `id` unless it's an lambda `arg` + let id = children_codegen(children, src, filename, targets)?.join(", "); + format!("__bee_get_id(__bee_env, [{id}], \"{span}\")") + } + + "name" => { + let name = node.utf8_text(src).unwrap(); + let help = if name == "return" { + Some("`return` could be use only directly inside a block. e.g. `{ a = 1; b = 2; return {a} }`".to_owned()) + } else { + None + }; + if is_reserved_keywords(name) { + Err(Error { + msg: format!( + "use of the reserved keyword `{name}` as an identifier is forbidden" + ), + help, + stacktrace: Some(vec![span]), + code: "PA002".to_owned(), + })? + } + format!("\"{name}\"") + } + + "nth" => node.utf8_text(src).unwrap().to_owned(), + + "placeholder" => { + debug_assert!(children.len() == 1); + rec_codegen(&children[0], src, filename, targets)? + } + + "true" => "true".to_owned(), + "false" => "false".to_owned(), + + "target" => { + let x = &node.utf8_text(src).unwrap()[1..]; + format!("__bee_targets.{x}") + } + + "bigint" => { + let x = node.utf8_text(src).unwrap(); + format!("{x}n") + } + + "f64" => { + let x: f64 = node.utf8_text(src).unwrap().parse().unwrap(); + x.to_string() + } + + "string" => { + // FIXME: Rust strings are UTF-8, but JavaScript ones are UTF-16 ... + let haystack = node.utf8_text(src).unwrap(); + let pattern = Regex::new(r"\$\{([^}]+)\}").unwrap(); + for caps in pattern.captures_iter(haystack) { + let name = &caps[1]; + let re = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap(); + if !re.is_match(name) { + return Err(Error { code: "PA008".to_owned(), msg: format!("`{name}` is invalid, only simple identifiers can be interpolated in string."), stacktrace: Some(vec![span]), help: None }); + } + } + pattern + .replace_all(haystack, |caps: &Captures| { + let name = &caps[1]; + format!("\" + __bee_get_id(__bee_env, [\"{name}\"], \"{span}\") + \"") + }) + .to_string() + } + + "do" => { + let block = children_codegen(children, src, filename, targets)?.join(";\n"); + format!( + "(__bee_env => {{ + __bee_env.self = __bee_env; + {block} + return __bee_env_untag(__bee_env); +}})(__bee_env_tag(__bee_env))" + ) + } + + // FIXME: pattern match on arguments! + "fn" => { + debug_assert!(children.len() == 2); + let arg = children[0].utf8_text(src).unwrap(); + let value = rec_codegen(&children[1], src, filename, targets)?; + format!( + "(__bee_env_captured => {{ + __bee_env_captured.self = __bee_env.self; + return __bee_arg => {{ + const __bee_env = __bee_env_captured; + __bee_env.{arg} = __bee_arg; + return {value}; + }}; +}})(__bee_env_copy(__bee_env))", + ) + } + + "if_then_else" => { + debug_assert!(children.len() == 3); + let xs = &children_codegen(children, src, filename, targets)?; + // FIXME: this is a hack ... add @concrete target? do this for any target ... + if targets.contains("abstract") { + return Ok(if xs[0] == "__bee_targets.abstract" { + &xs[1] + } else { + &xs[2] + } + .to_owned()); + } + // FIXME: on @abstract a different codegen should be used! + format!("({} ? {} : {})", xs[0], xs[1], xs[2]) + } + + "let" => { + debug_assert!(children.len() == 2); + let lvalue = children[0].utf8_text(src).unwrap(); + let rvalue = rec_codegen(&children[1], src, filename, targets)?; + let lvalue_span = Span { + byte_range: children[0].byte_range(), + ..span.clone() + }; + if is_reserved_keywords(lvalue) { + Err(Error { + msg: format!("use of the reserved keyword `{lvalue}` as l-value is forbidden"), + help: None, + stacktrace: Some(vec![lvalue_span]), + code: "PA003".to_owned(), + })? + } else if lvalue == "_" || lvalue == "self" { + Err(Error { + msg: format!("`${lvalue}` should not be used as an l-value"), + help: None, + stacktrace: Some(vec![lvalue_span]), + code: "PA004".to_owned(), + })? + } else { + format!("__bee_env.{lvalue} = {rvalue}") + } + } + + // FIXME: code is duplicated form `let` codegen ... + "name_alias" => { + debug_assert!(children.len() == 1); + let lvalue = children[0].utf8_text(src).unwrap(); + let rvalue = format!("__bee_get_id(__bee_env, [\"{lvalue}\"], \"{span}\")"); + if is_reserved_keywords(lvalue) { + Err(Error { + msg: format!("use of the reserved keyword `{lvalue}` as l-value is forbidden"), + help: None, + stacktrace: Some(vec![span]), + code: "PA003".to_owned(), + })? + } else if lvalue == "_" || lvalue == "self" { + Err(Error { + msg: format!("`${lvalue}` should not be used as an l-value"), + help: None, + stacktrace: Some(vec![span]), + code: "PA004".to_owned(), + })? + } else { + format!("__bee_env.{lvalue} = {rvalue}") + } + } + + "spread" => { + debug_assert!(children.len() == 1); + let id = children[0].utf8_text(src).unwrap(); + let rvalue = format!("__bee_get_id(__bee_env, [\"{id}\"], \"{span}\")"); + format!("__bee_env = {{...__bee_env, ...{rvalue}}}") + } + + "array" => { + let array = children_codegen(children, src, filename, targets)?.join(", "); + format!("[{array}]") + } + + "panic_" => { + debug_assert!(children.len() == 1); + let rvalue = rec_codegen(&children[0], src, filename, targets)?; + format!("__bee_error(\"RT001\", {rvalue}, \"{span}\")") + } + + "return_" => { + debug_assert!(children.len() == 1); + let rvalue = rec_codegen(&children[0], src, filename, targets)?; + format!("return {rvalue}") + } + + // FIXME: a warning should be displayed to user when `native` keyword + // is used outside of prelude + "native_" => { + debug_assert!(children.len() == 1); + // FIXME: forbid the use of `native` in @abstract mode, this will + // force a better separation of concerns ... + // if targets.contains("abstract") { + // "{}".to_owned() + // } else ... + let haystack = children[0].utf8_text(src).unwrap().replace("\\\"", "\""); + let pattern = Regex::new(r"\$\{([^}]+)\}").unwrap(); + for caps in pattern.captures_iter(&haystack) { + let name = &caps[1]; + let re = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap(); + if !re.is_match(name) { + return Err(Error { code: "PA008".to_owned(), msg: format!("`{name}` is invalid, only simple identifiers can be interpolated in string."), stacktrace: Some(vec![span]), help: None }); + } + } + let interpolated = pattern.replace_all(&haystack, |caps: &Captures| { + let name = &caps[1]; + format!("__bee_get_id(__bee_env, [\"{name}\"], \"{span}\")") + }); + strip_quotes(&interpolated) + } + + "import_" => { + // FIXME: support URLs (pointing e.g. to a git repository or a code + // archive). This is not trivial to implement as it should require + // e.g. some TOFU mechanism that store a checksum of the remote + // ressource in a .lock file that could be distributed with user + // sources. + debug_assert!(children.len() == 1); + let mut import = PathBuf::from(filename) + .parent() + .unwrap() + .join(strip_quotes(children[0].utf8_text(src).unwrap())); + if let Ok(metadata) = fs::metadata(&import) { + if metadata.is_dir() { + import = import.join("main.bee"); + } + }; + if !is_valid_extension(&import) { + Err(Error { + msg: format!("File `{}` extension should be `.bee`", import.display()), + help: None, + stacktrace: Some(vec![Span { + byte_range: children[0].byte_range(), + ..span.clone() + }]), + code: "PA006".to_owned(), + })? + } + if !is_valid_filename(&import) { + Err(Error { + msg: format!( + "File path `{}` contains illegal characters: `:`, `.`, `[` or `]`", + import.display() + ), + help: None, + stacktrace: Some(vec![Span { + byte_range: children[0].byte_range(), + ..span.clone() + }]), + code: "PA007".to_owned(), + })? + } + match std::fs::read_to_string(&import) { + Ok(src) => { + let src = src.as_bytes(); + let import = fs::canonicalize(import).unwrap(); + register_dependency(filename, &import); + cached(src, &import, targets, codegen_module)? + } + Err(err) => Err(Error { + msg: format!("error while reading file {}: {err}", &import.display()), + help: None, + stacktrace: Some(vec![Span { + byte_range: children[0].byte_range(), + ..span.clone() + }]), + code: "PA005".to_owned(), + })?, + } + } + + "prefix" => { + debug_assert!(children.len() == 2); + let op = children[0].utf8_text(src).unwrap(); + let op_span = Span { + byte_range: children[0].byte_range(), + ..span.clone() + }; + let right = rec_codegen(&children[1], src, filename, targets)?; + format!("__bee_fn_apply(__bee_get_id(__bee_env, [\"ops\", \"{}\"], \"{op_span}\"), [{right}], \"{span}\")", + match op { + "!" => "not", + "-" => "unary_minus", + _ => unimplemented!( + "`{}' prefix operator handling is missing in `codegen.rs` implentation", + op + ), + }) + } + + "infix" => { + debug_assert!(children.len() == 3); + let left = rec_codegen(&children[0], src, filename, targets)?; + let op = children[1].utf8_text(src).unwrap(); + let op_span = Span { + byte_range: children[1].byte_range(), + ..span.clone() + }; + let right = rec_codegen(&children[2], src, filename, targets)?; + format!("__bee_fn_apply(__bee_get_id(__bee_env, [\"ops\", \"{}\"], \"{op_span}\"), [{left}, {right}], \"{span}\")", + match op { + "==" => "eq", + "!=" => "neq", + "/" => "div", + "*" => "mul", + "%" => "mod", + "+" => "add", + "-" => "sub", + "<" => "lt", + ">" => "gt", + "<=" => "lte", + ">=" => "gte", + "|" => "or", + "&" => "and", + "|>" => "pipe", + "<|" => "reverse_pipe", + ".." => "range", + _ => unimplemented!( + "`{}' infix operator handling is missing in `codegen.rs` implentation", + op + ), + }) + } + + _ => unimplemented!( + "`{}' token kind handling is missing in `codegen.rs` implentation", + kind + ), + }) +} + +/// TODO: write documentation... +#[inline(always)] +pub fn is_valid_extension(path: &Path) -> bool { + if let Some(ext) = path.extension() { + ext == "bee" + } else { + false + } +} + +/// TODO: write documentation... +#[inline(always)] +pub fn is_valid_filename(path: &Path) -> bool { + !path.file_stem().unwrap().to_string_lossy().contains('.') + && !path.to_string_lossy().contains(':') + && !path.to_string_lossy().contains('[') + && !path.to_string_lossy().contains(']') +} + +/// TODO: write documentation... +#[inline(always)] +pub fn hint(keyword: &str) -> Option { + match keyword { + "import" => Some( + "`import` take one string argument which is a path, e.g. `import \"my_module.bee\"`" + .to_owned(), + ), + _ => None, + } +} + +/// TODO: write documentation... +#[inline(always)] +pub fn strip_quotes(x: &str) -> String { + debug_assert!(x.starts_with('\"') && x.chars().nth(x.len() - 1).unwrap() == '"'); + x[1..x.len() - 1].to_owned() +} + +#[inline(always)] +fn children_codegen( + children: Vec, + src: &[u8], + filename: &Path, + targets: &BTreeSet<&str>, +) -> Result, Error> { + #[cfg(feature = "rayon")] + { + let nodes: Nodes = children.into(); + return nodes + .par_iter() + .map(|x| rec_codegen(x.into(), src, filename, targets)) + .collect::, _>>(); + } + #[cfg(not(feature = "rayon"))] + return children + .iter() + .map(|x| rec_codegen(x, src, filename, targets)) + .collect::, _>>(); +} + +/// TODO: write documentation... +pub(crate) fn targets_codegen(targets: &BTreeSet<&str>) -> String { + let targets = targets + .iter() + .map(|x| format!("__bee_targets.{x} = true;")) + .collect::>() + .join("\n"); + format!( + "// TARGETS +const __bee_targets = {{}}; +{targets} +" + ) +} + +/// TODO: write documentation... +#[inline(always)] +pub fn is_reserved_keywords(x: &str) -> bool { + matches!( + x, + "abstract" + | "__proto__" + | "arguments" + | "as" + | "async" + | "await" + | "boolean" + | "break" + | "byte" + | "case" + | "catch" + | "char" + | "class" + | "concrete" + | "const" + | "constructor" + | "continue" + | "debugger" + | "default" + | "delete" + | "do" + | "double" + | "else" + | "enum" + | "eval" + | "export" + | "extends" + | "false" + | "final" + | "finally" + | "float" + | "for" + | "from" + | "function" + | "get" + | "goto" + | "hasOwnProperty" + | "if" + | "implements" + | "import" + | "in" + | "instanceof" + | "int" + | "interface" + | "isPrototypeOf" + | "let" + | "long" + | "native" + | "new" + | "null" + | "of" + | "package" + | "private" + | "propertyIsEnumerable" + | "protected" + | "public" + | "return" + | "set" + | "short" + | "static" + | "super" + | "switch" + | "synchronized" + | "then" + | "this" + | "throw" + | "throws" + | "toLocaleString" + | "toString" + | "transient" + | "true" + | "try" + | "typeof" + | "valueOf" + | "var" + | "void" + | "volatile" + | "while" + | "with" + | "yield" + ) || (x.len() >= 5 && &x[..5] == "__bee") +} diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,107 @@ +use crate::build::Error; +use crate::parser::Span; +use log::debug; +use regex::Regex; + +/// Wow, what the !@#$ is this? +/// +/// You've guessed it right – this evaluates a variant of the codegen at +/// compile-time, one that uses a different prelude. When `prelude.bee` is +/// compiled with the `@abstract` target, it provides users with a function +/// that doesn't produce any side effects. Instead, it offers the abstract, +/// type-as-values, equivalent of the expected result. +/// +/// E.g., the `randint` function returns the `Range` of possible values when +/// the program is built with the `@abstract` target, rather than generating +/// native code: +/// ```ignore +/// randint = min => max => +/// if @abstract Range min max +/// else native "${min} + Math.floor(Math.random() * ${max})" +/// ``` +/// This approach means that the _soundness_ of a program's typing is linked to +/// the _soundness_ of the Bee standard library constructs. You can find more +/// details about how this is implemented in the Prelude documentation. +/// +/// However, there is a downside. By embedding `deno_core`, a large crate, as a +/// dependency of our compiler, `bee` has become a self-contained binary of +/// ~60Mb. So, what's the alternative? The solution could be to implement our +/// own VM that directly interprets the AST: `eval(s: &S) -> Result<(), Error>` +/// +/// Such a VM implementation could also be repurposed to build, for example, a +/// REPL! +pub fn eval(src: String) -> Result<(), Error> { + #[cfg(all(feature = "quickjs", feature = "deno"))] + return Err(compile_error!( + "cargo features `deno` and `quickjs` are mutually exclusive" + )); + #[cfg(all(not(feature = "quickjs"), not(feature = "deno")))] + todo!(); // FIXME: use an external program (set in BEE_RUNTIME env + // variable) to perform the evaluation? + #[cfg(all(not(feature = "quickjs"), feature = "deno"))] + { + let mut rt = deno_core::JsRuntime::new(deno_core::RuntimeOptions::default()); + Ok(if let Err(err) = rt.execute_script("", src.into()) { + debug!("Deno error: {err}"); + read_debug_symbols(&err.to_string())? + }) + } + #[cfg(all(feature = "quickjs", not(feature = "deno")))] + { + let rt = rquickjs::Runtime::new().unwrap(); + rt.set_max_stack_size(1024 * 1024); + let ctx = rquickjs::Context::full(&rt).unwrap(); + ctx.with(|ctx| { + if let Err(rquickjs::Error::Exception) = ctx.eval::<(), _>(src) { + let err = ctx.catch().as_exception().unwrap().message().unwrap(); + debug!("QuickJS error: {err}"); + read_debug_symbols(&err)? + } + Ok(()) + }) + } +} + +/// TODO: write documentation... +#[inline(always)] +pub fn read_debug_symbols(trace: &str) -> Result<(), Error> { + if trace == "stack overflow" { + // FIXME: use `__bee_stacktrace` to give user a more semantic error! + // ctx.globals().get::<_, rquickjs::Array>("__bee_stacktrace").unwrap(); + return Err(Error { + help: None, + msg: "a stack overflow was encountered, it's likely caused by an infinite recursion" + .to_owned(), + code: "TY007".to_owned(), + stacktrace: None, + }); + } + let pattern = Regex::new(r"(\[.+:\d+:\d+\])* ([A-Z]{2}\d{3}) (.+)").unwrap(); + let cap = pattern.captures_iter(trace).next().unwrap(); + debug_assert!(cap.len() == 4); + let mut spans = cap[1].split("][").collect::>(); + let last = spans.len() - 1; + spans[0] = spans[0].strip_prefix('[').unwrap(); + spans[last] = spans[last].strip_suffix(']').unwrap(); + let stacktrace: Option> = Some( + (0..=last) + .map(|i| { + let pattern = Regex::new(r"(.+):(\d+):(\d+)").unwrap(); + let cap = pattern.captures_iter(spans[i]).next().unwrap(); + debug_assert!(cap.len() == 4); + Span { + byte_range: cap[2].parse().unwrap()..cap[3].parse().unwrap(), + filename: cap[1].into(), + } + }) + .collect(), + ); + let code = cap[2].to_owned(); + let msg = cap[3].to_owned(); + Err(Error { + help: None, + msg, + code, + stacktrace, + }) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,25 @@ +//! TODO: write documentation... +//! +//! FIXME: use `cargo-sync-readme` to turn "to-be-written" crate top doc comment +//! into a proper `README.md`! +//! +//! MSRV 1.70.0 + +#[macro_use] +extern crate lazy_static; + +/// TODO: write documentation... +pub mod build; +/// TODO: write documentation... +pub mod cache; +/// TODO: write documentation... +pub mod cli; +/// TODO: write documentation... +pub mod codegen; +/// TODO: write documentation... +pub mod eval; +/// TODO: write documentation... +pub mod parser; + +/// TODO: write documentation... +pub const VERSION: &str = "0.0.1"; diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,79 @@ +use std::fmt::Display; +use std::ops::Range; +use std::path::PathBuf; + +// FIXME: use https://codeberg.org/xlambein/ts-typed-ast +// include!(concat!(env!("OUT_DIR"), "/ast.rs")); + +/// TODO: write documentation... +pub fn parse(src: &[u8]) -> tree_sitter::Tree { + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(tree_sitter_bee_lang::language()) + .unwrap(); + parser.parse(src, None).unwrap() +} + +/// TODO: write documentation... +#[derive(Debug, Clone)] +pub struct Span { + /// TODO: write documentation... + pub byte_range: Range, + /// TODO: write documentation... + pub filename: PathBuf, +} + +impl Display for Span { + #[inline(always)] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // FIXME: this Display could cause confusion, since we output the + // `byte_range` and not the `line:column` ... + write!( + f, + "[{}:{}:{}]", + self.filename.display(), + self.byte_range.start, + self.byte_range.end + )?; + Ok(()) + } +} + +// FIXME: this was fixed in the `master` branch of TreeSitter, so this will +// soon no longer be needed :) + +#[cfg(feature = "rayon")] +pub(crate) struct NodeWrapper<'a>(tree_sitter::Node<'a>); + +#[cfg(feature = "rayon")] +unsafe impl<'a> Sync for NodeWrapper<'a> {} + +#[cfg(feature = "rayon")] +pub(crate) struct Nodes<'a>(Vec>); + +#[cfg(feature = "rayon")] +impl<'a> From>> for Nodes<'a> { + #[inline(always)] + fn from(nodes: Vec>) -> Self { + Self(nodes.into_iter().map(NodeWrapper).collect()) + } +} + +#[cfg(feature = "rayon")] +impl<'a, 'b> From<&'b NodeWrapper<'a>> for &'b tree_sitter::Node<'a> { + #[inline(always)] + fn from(safe_node: &'b NodeWrapper<'a>) -> Self { + &safe_node.0 + } +} + +#[cfg(feature = "rayon")] +impl<'a> rayon::iter::IntoParallelRefIterator<'a> for Nodes<'a> { + type Iter = rayon::slice::Iter<'a, NodeWrapper<'a>>; + type Item = &'a NodeWrapper<'a>; + + #[inline(always)] + fn par_iter(&'a self) -> Self::Iter { + self.0.par_iter() + } +} diff --git a/src/prelude.bee b/src/prelude.bee new file mode 100644 --- /dev/null +++ b/src/prelude.bee @@ -0,0 +1,208 @@ +{ + // assert :: Bool -> () + assert = x => if x {} else panic "assertion failed" + // FIXME: add an "assert?" runtime primitive + + // FIXME: add an UNSAFE "require"? + + // show :: Any -> String + show = x => native "__bee_debug_display(${x})" // FIXME: use in print ... + + // print :: Any -> () + print = x => if @abstract {} else { x = show x; native "console.log(${x})"; return {} } + + console = { log = print } + + // parse :: String -> Any + parse = str => native "JSON.parse(${str})" + + // length :: Object -> Number + length = obj => native "${obj}.length" + + // reverse :: Object -> Object + reverse = obj => native "Array.isArray(${obj}) ? ${obj}.reverse() : Array.from(${obj}).reverse().join('')" + + maths = { + // pow :: Number -> Number -> Number + pow = base => exponent => native "Math.pow(${base}, ${exponent})" + + // sqrt :: Number -> Number + sqrt = x => native "Math.sqrt(${x})" + + // abs :: Number -> Number + abs = x => native "Math.abs(${x})" + + // round :: Number -> Number + round = x => native "Math.round(${x})" + + // floor :: Number -> Number + floor = x => native "Math.floor(${x})" + + // ceil :: Number -> Number + ceil = x => native "Math.ceil(${x})" + } + + array = { + // all :: Array a -> (a -> Bool) -> Bool + all = arr => predicate => native "Array.isArray(${arr}) && ${arr}.every(${predicate})" + + // any :: Array a -> (a -> Bool) -> Bool + any = arr => predicate => native "Array.isArray(${arr}) && ${arr}.some(${predicate})" + + // push :: Array a -> a -> Array a + push = arr => item => native "(() => { ${arr}.push(${item}); return ${arr}; })()" + + // pop :: Array a -> a + pop = arr => native "(() => { return ${arr}.pop(); })()" + + // sort :: Array a -> (a -> a -> Number) -> Array a + sort = arr => compareFunction => native "(() => { ${arr}.sort(${compareFunction}); return ${arr}; })()" + + // filter :: Array a -> (a -> Bool) -> Array a + filter = arr => predicate => native "${arr}.filter(${predicate})" + + // map :: Array a -> (a -> b) -> Array b + map = arr => mapper => native "${arr}.map(${mapper})" + + // reduce :: Array a -> (b -> a -> b) -> b -> b + reduce = arr => reducer => initialValue => native "${arr}.reduce(${reducer}, ${initialValue})" + + // forEach :: Array a -> (a -> ()) -> Array a + forEach = arr => action => native "(() => { ${arr}.forEach(${action}); return ${arr}; })()" + + // find :: Array a -> (a -> Bool) -> a + find = arr => predicate => native "(${arr}.find(${predicate}) || null)" + + // indexOf :: Array a -> a -> Number + indexOf = arr => item => native "${arr}.indexOf(${item})" + + // slice :: Array a -> Number -> Number -> Array a + slice = arr => begin => end => native "${arr}.slice(${begin}, ${end})" + + // reduceRight :: Array a -> (b -> a -> b) -> b -> b + reduceRight = arr => reducer => initialValue => native "${arr}.reduceRight(${reducer}, ${initialValue})" + } + + string = { + // match :: String -> String -> Bool + match = str => pattern => native "${str}.match(${pattern})" + + // chars :: String -> Array String + chars = str => native "Array.from(${str})" + + // concat :: String -> String -> String + concat = str1 => str2 => native "${str1}.concat(${str2})" + + // substring :: String -> Number -> Number -> String + substring = str => start => end => native "${str}.substring(${start}, ${end})" + + // split :: String -> String -> Array String + split = str => delimiter => native "${str}.split(${delimiter})" + + // trim :: String -> String + trim = str => native "${str}.trim()" + + // toUpper :: String -> String + toUpper = str => native "${str}.toUpperCase()" + + // toLower :: String -> String + toLower = str => native "${str}.toLowerCase()" + + // indexOf :: String -> String -> Number + indexOf = str => searchStr => native "${str}.indexOf(${searchStr})" + + // endsWith :: String -> String -> Bool + endsWith = str => searchStr => native "${str}.endsWith(${searchStr})" + + // startsWith :: String -> String -> Bool + startsWith = str => searchStr => native "${str}.startsWith(${searchStr})" + + // replace :: String -> String -> String -> String + replace = str => search => replacement => native "${str}.replace(${search}, ${replacement})" + + // regexMatch :: String -> RegExp -> Array String + regexMatch = str => pattern => native "${str}.match(${pattern})" + + // regexTest :: String -> RegExp -> Bool + regexTest = str => pattern => native "${pattern}.test(${str})" + } + + object = { + // values :: Object -> Array Any + values = obj => native "Object.values(${obj})" + + // keys :: Object -> Array String + keys = obj => native "Object.keys(${obj})" + + // drop :: Object -> String -> Object + drop = obj => key => native "(() => { delete ${obj}[${key}]; return ${obj}; })()" + + // merge :: Object -> Object -> Object + merge = obj1 => obj2 => native "Object.assign({}, ${obj1}, ${obj2})" + } + + os = { + // UNSAFE readFile :: String -> String + readFile = path => encoding => native "require('fs').readFileSync(${path}, ${encoding})" + + // UNSAFE writeFile :: String -> String -> () + writeFile = path => data => native "require('fs').writeFileSync(${path}, ${data})" + + // UNSAFE getenv :: String -> String + getenv = variable => native "process.env[${variable}]" + + // UNSAFE setenv :: String -> String -> () + setenv = variable => value => { native "(() => { process.env[${variable}] = ${value}; })()" } + } + + // UNSAFE random :: () -> Number + random = _ => native "Math.random()" + // FIXME: add a randInt :: () -> BigInt + + // UNSAFE getCurrentDate :: () -> String + getCurrentDate = _ => native "new Date().toISOString()" + + // Explicit type-casting utils between Number (double / f64) and BigInt + toNumber = x => native "__bee_cast_to_number(${x})" + toBigInt = x => native "__bee_cast_to_bigint(${x})" + + // Operators (infix and prefix) that can be overloaded by user :) + ops = { + // !x + not = x => native "__bee_op_not(${x})" + // -x + unary_minus = x => native "__bee_op_unary_minus(${x})" + // x == y + eq = x => y => native "__bee_op_eq(${x}, ${y})" + // x != y + neq = x => y => native "__bee_op_neq(${x}, ${y})" + // x / y + div = x => y => native "__bee_op_div(${x}, ${y})" + // x * y + mul = x => y => native "__bee_op_mul(${x}, ${y})" + // x % y + mod = x => y => native "__bee_op_mod(${x}, ${y})" + // x + y + add = x => y => native "__bee_op_add(${x}, ${y})" + // x - y + sub = x => y => native "__bee_op_sub(${x}, ${y})" + // x < y + lt = x => y => native "__bee_op_lt(${x}, ${y})" + // x > y + gt = x => y => native "__bee_op_gt(${x}, ${y})" + // x <= y + lte = x => y => native "__bee_op_lte(${x}, ${y})" + // x >= y + gte = x => y => native "__bee_op_gte(${x}, ${y})" + // x | y + or = x => y => native "__bee_op_or(${x}, ${y})" + // x & y + and = x => y => native "__bee_op_and(${x}, ${y})" + // x |> y + pipe = x => y => native "__bee_op_pipe(${x}, ${y})" + // x <| y + reverse_pipe = x => y => native "__bee_op_reverse_pipe(${x}, ${y})" + // x..y + range = start => end => native "__bee_op_range(${start}, ${end})" + } +} diff --git a/src/runtime.js b/src/runtime.js new file mode 100644 --- /dev/null +++ b/src/runtime.js @@ -0,0 +1,165 @@ +const __bee_error = (__bee_error_code, __bee_msg, __bee_debug_symbol) => { + throw new Error(`${__bee_debug_symbol}${__bee_stacktrace.slice(0, 4).join("")} ${__bee_error_code} ${__bee_msg}`); +}; + +let __bee_env = {}; // FIXME: use a `Map()` instead? + +const __bee_env_tag = __bee_env => { return { __bee_env_cow: __bee_env }; }; + +const __bee_env_untag = __bee_env => { + delete __bee_env.self; + delete __bee_env.__bee_env_cow; + return __bee_env; +}; + +// FIXME: add a an `unsafe` wrapper that check for undefined values! +// __bee_env = (typeof __bee_env === 'undefined' ? {} : __bee_env); + +const __bee_env_error = (__bee_env, __bee_id, __bee_debug_symbol) => + (typeof __bee_id === "string" && Array.isArray(__bee_env) + ? __bee_error("TY001", `you can't access the property \`${__bee_id}\` of the Array \`${__bee_debug_display(__bee_env)}\``, __bee_debug_symbol) + : (typeof __bee_id === "number" ? (Array.isArray(__bee_env) + // FIXME: add support for inverse index: [1 2 3].(-1) == 3 ? + ? (__bee_id >= __bee_env.length ? __bee_error("TY005", `out of bound access: try to access position \`${__bee_id}\` while \`${__bee_debug_display(__bee_env)}\` have a lenght of \`${__bee_env.length}\``, __bee_debug_symbol) : {}) + : __bee_error("TY002", `you can't access the \`${__bee_id}\` element of the Object \`${__bee_debug_display(__bee_env)}\``, __bee_debug_symbol)) + : __bee_error("TY003", `identifier \`${__bee_id}\` is not defined`, __bee_debug_symbol))); + +const __bee_get_id = (__bee_env, __bee_id, __bee_debug_symbol, __bee_in_self = false) => { + const __bee_get_name = (__bee_env, __bee_id, __bee_debug_symbol) => + typeof __bee_env === "object" ? (__bee_id in __bee_env ? __bee_env[__bee_id] + : (/* !__bee_in_self && */ "__bee_env_cow" in __bee_env ? __bee_get_name(__bee_env.__bee_env_cow, __bee_id, __bee_debug_symbol) + : __bee_env_error(__bee_env, __bee_id, __bee_debug_symbol))) + : __bee_error("TY004", `\`${__bee_debug_display(__bee_env)}\` is neither an Array or Object, you can't use \`.\` operator on it`, __bee_debug_symbol); + const id = __bee_id.shift(); + const value = __bee_get_name(__bee_env, id, __bee_debug_symbol); + return __bee_id.length ? __bee_get_id(value, __bee_id, __bee_debug_symbol, __bee_in_self || id == "self") : __bee_env_untag(value); +}; + +const __bee_env_copy = __bee_env => { + if (typeof __bee_env !== "object") { return __bee_env; } + if (Array.isArray(__bee_env)) { return __bee_env.map(x => __bee_env_copy(x)); } + const { self, __bee_env_cow, ...xs } = __bee_env; + const x = typeof __bee_env_cow === 'undefined' ? {} : __bee_env_copy(__bee_env_cow) + return { + ...x, ...Object.keys(xs).reduce((acc, key) => { + acc[key] = __bee_env_copy(xs[key]); + return acc; + }, {}) + }; +}; + +const __bee_stacktrace = []; + +const __bee_fn_apply = (__bee_ret, __bee_args, __bee_debug_symbol) => { + __bee_stacktrace.unshift(__bee_debug_symbol); + for (let i = 0; i < __bee_args.length; ++i) { + const __bee_arg = __bee_args[i] + __bee_ret = (typeof __bee_ret === "function" ? __bee_ret(__bee_arg) + : __bee_error("TY006", "function is called with too many arguments...", __bee_debug_symbol)); + } + __bee_stacktrace.shift(); + return __bee_ret; +}; + +const __bee_op_not = x => !x; + +const __bee_op_unary_minus = x => -x; + +const __bee_op_eq = (x, y) => x === y; + +const __bee_op_neq = (x, y) => x !== y; + +const __bee_op_add = (x, y) => { + __bee_check_types(x, y); + return x + y; +}; + +const __bee_op_sub = (x, y,) => { + __bee_check_types(x, y); + return x - y; +}; + +const __bee_op_mul = (x, y) => { + __bee_check_types(x, y); + return x * y; +}; + +const __bee_op_div = (x, y) => { + y == 0 ? __bee_error("TY009", `division by 0 is forbidden`, "") : {}; + __bee_check_types(x, y); + return x / y; +}; + +const __bee_op_mod = (x, y) => { + __bee_check_types(x, y); + return x % y; +}; + +const __bee_check_types = (x, y) => { + // FIXME: check !isNan() and isFinite() ? + (typeof x == typeof y) ? {} : __bee_error("TY009", `can't mix ${typeof x} (${x}) and ${typeof y} (${y})`, ""); + // FIXME: advice to use explicit type casting! +}; + +const __bee_op_lt = (x, y) => x < y; + +const __bee_op_gt = (x, y) => x > y; + +const __bee_op_lte = (x, y) => x <= y; + +const __bee_op_gte = (x, y) => x >= y; + +const __bee_op_and = (x, y) => x && y; + +const __bee_op_or = (x, y) => x || y; + +const __bee_op_pipe = (f, g) => typeof f == "function" ? x => g(f(x)) : g(f); + +const __bee_op_reverse_pipe = (f, g) => typeof f == "function" ? x => f(g(x)) : f(g); + +const __bee_op_range = (x, y) => { + // FIXME: should check that the conversion is safe ... + const start = __bee_cast_to_number(x); + const end = __bee_cast_to_number(y); + return Array.from({ length: end - start }, (_, i) => start + i); +} + +const __bee_cast_to_number = x => Number.isSafeInteger(x) ? Number(x) : __bee_error("TY010", `${x} can't be safely convert to Number`, ""); + +const __bee_cast_to_bigint = x => Number.isSafeInteger(x) ? BigInt(x) : __bee_error("TY011", `${x} can't be safely convert to BigInt`, ""); + +const __bee_debug_display = (x, truncateLargeCollections = true) => { + const __bee_truncate_if_needed = (collection, truncate) => { + if (truncate && collection.length > 8) { + return [...collection.slice(0, 6), '...', collection[collection.length - 1]]; + } + return collection; + }; + if (typeof x === 'number') { + if (Number.isInteger(x)) { + return x + '.0'; + } else { + return x.toString(); + } + } else if (typeof x === 'bigint') { + return x.toString(); + } else if (typeof x === 'string') { + return '"' + x + '"'; + } else if (Array.isArray(x)) { + const arrayString = x.map(item => __bee_debug_display(item, truncateLargeCollections)); + return '[' + __bee_truncate_if_needed(arrayString, truncateLargeCollections).join(', ') + ']'; + } else if (typeof x === 'object' && x !== null) { + const objectString = Object.entries(x).map(([key, value]) => `${key} = ${__bee_debug_display(value, truncateLargeCollections)}`); + return '{' + __bee_truncate_if_needed(objectString, truncateLargeCollections).join('; ') + '}'; + } else { + return x.toString(); + } +}; + +// FIXME: write an alternative JS `.toString()` that turn any JS value into the +// code that would be interpreted such as this value! + +// FIXME: __functor and __toString special attributes, e.g.: +// let add = { __functor = self: x: x + self.x; }; +// inc = add // { x = 1; }; +// in inc 1 diff --git a/tree-sitter-bee-lang/.gitattributes b/tree-sitter-bee-lang/.gitattributes new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/tree-sitter-bee-lang/.gitignore b/tree-sitter-bee-lang/.gitignore new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/.gitignore @@ -0,0 +1,15 @@ +# Build artifacts +build/ +src/parser.c +src/scanner.c + +# Dependency directories +node_modules/ + +# IDE/Editor specific files +.vscode/ +.idea/ + +# Operating System specific files +.DS_Store +Thumbs.db diff --git a/tree-sitter-bee-lang/Cargo.toml b/tree-sitter-bee-lang/Cargo.toml new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tree-sitter-bee-lang" +description = "Bee grammar for the tree-sitter parsing library" +version = "0.1.0" +keywords = ["incremental", "parsing", "bee"] +categories = ["parsing", "text-editors"] +edition = "2018" +authors = ["Yvan Sraka "] +license = "GPLv2" + +build = "bindings/rust/build.rs" +include = [ + "bindings/rust/*", + "grammar.js", + "queries/*", + "src/*", +] + +[lib] +path = "bindings/rust/lib.rs" + +[dependencies] +tree-sitter = "0.20" + +[build-dependencies] +cc = "1.0" diff --git a/tree-sitter-bee-lang/README.md b/tree-sitter-bee-lang/README.md new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/README.md @@ -0,0 +1,73 @@ +## How to Set Up Bee Syntax Highlighting? + +This tutorial assumes that you have cloned this repository and that you are in the `tree-sitter` subfolder where this `README.md` resides. + +### VSCode + +Press `Ctrl` (`Cmd` on macOS) + `Shift` + `P`, then type "Developer: Install Extension from Location...", and select the `vscode-syntax-highlighting` folder. + +### Vim + +Copy the `bee.vim` file from this folder to `~/.vim/syntax/` (if you're using Neovim, the path is `~/.config/nvim/syntax/`). + +Edit (or create) the `filetype.vim` script, which should be in `~/.vim/` (or `~/.config/nvim/` for Neovim). It should contain the following lines: + +```vim +if exists("did_load_filetypes") + finish +endif + +augroup filetypedetect + au! BufRead,BufNewFile *.bee setfiletype bee +augroup END +``` + +Ensure that your Vim is configured to allow custom syntax files and filetype detection. In your `~/.vimrc` (or `~/.config/nvim/init.vim` for Neovim), you should have syntax highlighting enabled with `syntax on` or `syntax enable`. + +### Emacs + +Copy the `bee-mode.el` file from this folder in a subdirectory of your Emacs configuration directory, e.g. `~/.emacs.d/bee/`. + +To automatically load this mode when opening `.bee` files, add the following lines to your Emacs configuration file (usually `~/.emacs` or `~/.emacs.d/init.el`): + +```elisp +(add-to-list 'load-path "~/.emacs.d/bee/") +(require 'bee-mode) +``` + +### Helix + +First, add the following to your `~/.config/helix/languages.toml` configuration file: + +```toml +[[grammar]] +name = "bee" + +[grammar.source] +path = "/Users/yvan/bee-lang/tree-sitter" # Don't forget to change this line ;) + +[[language]] +comment-token = "//" +file-types = ["bee"] +injection-regex = "bee" +name = "bee" +roots = ["main.bee"] +scope = "source.bee" + +[language.indent] +tab-width = 4 +unit = " " +``` + +Then run the following commands (from the folder containing the `grammar.js` file): + +```bash +mkdir -p ~/.config/helix/runtime/{queries,grammars} +ln -s "$(pwd)/queries" ~/.config/helix/runtime/queries/bee +# /!\ Warning: re-run the next line after each change to grammar.js +cc -shared src/parser.c -o ~/.config/helix/runtime/grammars/bee.so # (yes, .so and not .dylib, even on macOS...) +``` + +--- + +If you still can't get syntax highlighting to work on your machine after following these instructions, please ask for help at discuss@bee-lang.org. diff --git a/tree-sitter-bee-lang/bee-mode.el b/tree-sitter-bee-lang/bee-mode.el new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/bee-mode.el @@ -0,0 +1,51 @@ +;;; bee-mode.el --- Syntax highlighting for Bee language + +; If you discover a way to improve Emacs syntax highlighting support by editing this file, +; please share it with us at devel@bee-lang.org :) + +(defvar bee-font-lock-keywords + (let* ( + ;; Define patterns for basic syntax categories. + (x-constants '("true" "false")) + (x-keywords '("if" "else" "import" "native" "return" "panic")) + (x-operators '("=" "=>" "==" "!=" "/" "*" "%" "+" "-" "<" ">" "<=" ">=" "|" "&" "|>" "<|" "..")) + (x-unary-operators '("!" "-")) + (x-spread-operator '("\\.\\.\\.")) + (x-constants-regexp (regexp-opt x-constants 'words)) + (x-keywords-regexp (regexp-opt x-keywords 'words)) + (x-operators-regexp (regexp-opt x-operators)) + (x-unary-operators-regexp (regexp-opt x-unary-operators)) + (x-spread-operator-regexp (regexp-opt x-spread-operator)) + (single-line-comment "//.*") + (multi-line-comment-start "/\\*") + (multi-line-comment-end "\\*/") + ) + `( + (,x-constants-regexp . font-lock-constant-face) + (,x-keywords-regexp . font-lock-keyword-face) + (,x-operators-regexp . font-lock-operator-face) + (,x-unary-operators-regexp . font-lock-operator-face) + (,x-spread-operator-regexp . font-lock-operator-face) + ("@[a-zA-Z_][a-zA-Z0-9_]*" . font-lock-variable-name-face) + ("\\b[0-9]+\\b" . font-lock-number-face) + ("\".*?\"" . font-lock-string-face) + ("//.*" . font-lock-comment-face) + ("/\\*\\(.\\|\n\\)*?\\*/" . font-lock-comment-face) + (,single-line-comment . font-lock-comment-face) + (,multi-line-comment-start . font-lock-comment-face) + (,multi-line-comment-end . font-lock-comment-face) + )) + "Highlighting expressions for Bee mode") + +(define-derived-mode bee-mode prog-mode "Bee" + "Major mode for editing Bee language files." + (setq font-lock-defaults '((bee-font-lock-keywords))) + (modify-syntax-entry ?/ ". 124b" bee-mode-syntax-table) + (modify-syntax-entry ?* ". 23" bee-mode-syntax-table) + (modify-syntax-entry ?\n "> b" bee-mode-syntax-table)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.bee\\'" . bee-mode)) + +(provide 'bee-mode) +;;; bee-mode.el ends here diff --git a/tree-sitter-bee-lang/bee.vim b/tree-sitter-bee-lang/bee.vim new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/bee.vim @@ -0,0 +1,50 @@ +" Vim syntax file +" Language: bee +" File: bee.vim + +" If you discover a way to improve Vim syntax highlighting support by editing this file, +" please share it with us at devel@bee-lang.org :) + +if exists("b:current_syntax") + finish +endif + +syntax clear + +syntax keyword beeBoolean true false +syntax keyword beeDirective @target +syntax keyword beeControl panic if else +syntax keyword beeConditional if else +syntax keyword beeImport import +syntax keyword beeSpecialFunction native +syntax keyword beeReturn return + +syntax match beeOperator "\v[=!/\*\%+\-<>|&]+" +syntax match beeUnaryOperator "\v[!\-]" +syntax match beeSpreadOperator "\.\.\." +syntax match beeDelimiter "[{}();\[\]]" +syntax match beeNumber "\v\-?\d+(\.\d+)?([eE][\-+]?\d+)?" +syntax match beeString /"[^"\\]*"/ +syntax match beeComment "//.*" contains=beeTodo +syntax region beeComment start="/\*" end="\*/" contains=beeTodo +" FIXME: recursive comments are not highlighted correctly ... + +syntax keyword beeTodo contained TODO FIXME XXX + +hi def link beeBoolean Boolean +hi def link beeDirective Identifier +hi def link beeControl Statement +hi def link beeConditional Conditional +hi def link beeImport Include +hi def link beeSpecialFunction PreProc +hi def link beeReturn Keyword +hi def link beeOperator Operator +hi def link beeUnaryOperator Operator +hi def link beeSpreadOperator Operator +hi def link beeDelimiter Delimiter +hi def link beeNumber Number +hi def link beeString String +hi def link beeComment Comment +hi def link beeTodo Todo + +let b:current_syntax = "bee" diff --git a/tree-sitter-bee-lang/binding.gyp b/tree-sitter-bee-lang/binding.gyp new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/binding.gyp @@ -0,0 +1,19 @@ +{ + "targets": [ + { + "target_name": "tree_sitter_bee_binding", + "include_dirs": [ + " +#include "nan.h" + +using namespace v8; + +extern "C" TSLanguage * tree_sitter_bee(); + +namespace { + +NAN_METHOD(New) {} + +void Init(Local exports, Local module) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("Language").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); + Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); + Nan::SetInternalFieldPointer(instance, 0, tree_sitter_bee()); + + Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("bee").ToLocalChecked()); + Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); +} + +NODE_MODULE(tree_sitter_bee_binding, Init) + +} // namespace diff --git a/tree-sitter-bee-lang/bindings/node/index.js b/tree-sitter-bee-lang/bindings/node/index.js new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/bindings/node/index.js @@ -0,0 +1,19 @@ +try { + module.exports = require("../../build/Release/tree_sitter_bee_binding"); +} catch (error1) { + if (error1.code !== 'MODULE_NOT_FOUND') { + throw error1; + } + try { + module.exports = require("../../build/Debug/tree_sitter_bee_binding"); + } catch (error2) { + if (error2.code !== 'MODULE_NOT_FOUND') { + throw error2; + } + throw error1 + } +} + +try { + module.exports.nodeTypeInfo = require("../../src/node-types.json"); +} catch (_) {} diff --git a/tree-sitter-bee-lang/bindings/rust/build.rs b/tree-sitter-bee-lang/bindings/rust/build.rs new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/bindings/rust/build.rs @@ -0,0 +1,40 @@ +fn main() { + let src_dir = std::path::Path::new("src"); + + let mut c_config = cc::Build::new(); + c_config.include(&src_dir); + c_config + .flag_if_supported("-Wno-unused-parameter") + .flag_if_supported("-Wno-unused-but-set-variable") + .flag_if_supported("-Wno-trigraphs"); + let parser_path = src_dir.join("parser.c"); + c_config.file(&parser_path); + + // If your language uses an external scanner written in C, + // then include this block of code: + + /* + let scanner_path = src_dir.join("scanner.c"); + c_config.file(&scanner_path); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + */ + + c_config.compile("parser"); + println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); + + // If your language uses an external scanner written in C++, + // then include this block of code: + + /* + let mut cpp_config = cc::Build::new(); + cpp_config.cpp(true); + cpp_config.include(&src_dir); + cpp_config + .flag_if_supported("-Wno-unused-parameter") + .flag_if_supported("-Wno-unused-but-set-variable"); + let scanner_path = src_dir.join("scanner.cc"); + cpp_config.file(&scanner_path); + cpp_config.compile("scanner"); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + */ +} diff --git a/tree-sitter-bee-lang/bindings/rust/lib.rs b/tree-sitter-bee-lang/bindings/rust/lib.rs new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/bindings/rust/lib.rs @@ -0,0 +1,52 @@ +//! This crate provides bee language support for the [tree-sitter][] parsing library. +//! +//! Typically, you will use the [language][language func] function to add this language to a +//! tree-sitter [Parser][], and then use the parser to parse some code: +//! +//! ``` +//! let code = ""; +//! let mut parser = tree_sitter::Parser::new(); +//! parser.set_language(tree_sitter_bee::language()).expect("Error loading bee grammar"); +//! let tree = parser.parse(code, None).unwrap(); +//! ``` +//! +//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html +//! [language func]: fn.language.html +//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html +//! [tree-sitter]: https://tree-sitter.github.io/ + +use tree_sitter::Language; + +extern "C" { + fn tree_sitter_bee() -> Language; +} + +/// Get the tree-sitter [Language][] for this grammar. +/// +/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html +pub fn language() -> Language { + unsafe { tree_sitter_bee() } +} + +/// The content of the [`node-types.json`][] file for this grammar. +/// +/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types +pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); + +// Uncomment these to include any queries that this grammar contains + +// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); +// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); +// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); +// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm"); + +#[cfg(test)] +mod tests { + #[test] + fn test_can_load_grammar() { + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(super::language()) + .expect("Error loading bee language"); + } +} diff --git a/tree-sitter-bee-lang/grammar.js b/tree-sitter-bee-lang/grammar.js new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/grammar.js @@ -0,0 +1,71 @@ +// This grammar have by design, no conflicts between rules and no need for +// precedence rules, instead it force the use of parenthesis on any ambiguity +// this is a feature! + +const list = (value, delimiter) => optional(seq(value, repeat(seq(delimiter, value)), optional(delimiter))); + +module.exports = grammar({ + name: 'bee', + extras: $ => [/\s/, $.inline_comment, $.block_comment], + // FIXME: https://github.com/tree-sitter/tree-sitter/pull/1635 + // reserved: _ => ['true', 'false', 'if', 'else', 'return', 'native', 'import'], + word: $ => $.name, + rules: { + source_file: $ => $.expr, + expr: $ => choice($.fn, $.statement, $.value, $.prefix, $.infix, seq('(', $.expr, ')')), + value: $ => choice($.array, $.bigint, $.bool, $.id, $.f64, $.string, $.target), + statement: $ => choice($.do, $.if_then_else, $.import_, $.native_, $.panic_, $.let, $.apply), + apply: $ => seq($.arg, repeat1($.arg)), + arg: $ => choice($.value, $.do, seq('(', $.expr, ')')), + array: $ => seq('[', list($.expr, ','), ']'), + delimiter: $ => choice(';', '\n'), + field: $ => choice($.return_, $.statement, $.name_alias, $.spread), + do: $ => seq('{', list($.field, $.delimiter), '}'), + if_then_else: $ => seq('if', $.arg, $.expr, seq('else', $.expr)), + let: $ => seq($.name, '=', $.expr), // FIXME: let use $.id instead of $.name? + fn: $ => seq($.name, '=>', $.expr), + spread: $ => seq("...", $.id), // FIXME: spread arbitrary $.expr? spread in $.array? + return_: $ => seq('return', $.expr), + panic_: $ => seq('panic', $.string), + native_: $ => seq('native', $.string), + import_: $ => seq('import', $.string), + id: $ => seq(choice($.name, $.placeholder), repeat(seq('.', choice($.name, $.nth, $.placeholder)))), + nth: _ => /-?\d+/, + placeholder: $ => seq('$', '{', $.expr, '}'), + bool: _ => choice('true', 'false'), + target: _ => /@[a-zA-Z_][a-zA-Z0-9_]*/, + name_alias: $ => $.name, + name: _ => /[a-zA-Z_][a-zA-Z0-9_]*/, + bigint: _ => /-?\d+([eE]+?\d+)?/, + f64: _ => /-?\d+(\.\d+)?([eE][-+]?\d+)?/, + string: _ => /"([^"\\]|\\.)*"/, + inline_comment: _ => seq('//', /.*/), + block_comment: $ => seq('/*', repeat(choice(/[^*]/, /\*[^/]/, $.block_comment)), '*/'), + prefix: $ => choice( + ...[ + '!', '-' + ].map(operator => + seq( + operator, + $.arg + ) + ) + ), + infix: $ => choice( + ...[ + '==', '!=', '/', '*', '%', '+', '-', '<', '>', '<=', '>=', '|', '&', '|>', '<|', '..' + ].map(operator => + seq( + $.arg, + operator, + $.arg + ) + ) + ), + // FIXME: `.` operator should be callable directly on array or object inline declaration ... + // FIXME: add `async` and `await` support ... in grammar? in prelude? + } +}); + +// FIXME: open a PR to add syntax highlighting support to Zed editor ... +// https://github.com/zed-industries/zed/tree/main/crates/zed/src/languages diff --git a/tree-sitter-bee-lang/package-lock.json b/tree-sitter-bee-lang/package-lock.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/package-lock.json @@ -0,0 +1,32 @@ +{ + "name": "tree-sitter-bee-lang", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tree-sitter-bee-lang", + "version": "0.1.0", + "license": "ISC", + "dependencies": { + "nan": "^2.18.0" + }, + "devDependencies": { + "tree-sitter-cli": "^0.20.8" + } + }, + "node_modules/nan": { + "version": "2.18.0", + "license": "MIT" + }, + "node_modules/tree-sitter-cli": { + "version": "0.20.8", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "tree-sitter": "cli.js" + } + } + } +} diff --git a/tree-sitter-bee-lang/package.json b/tree-sitter-bee-lang/package.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/package.json @@ -0,0 +1,22 @@ +{ + "name": "tree-sitter-bee-lang", + "version": "0.1.0", + "description": "Bee grammar for the tree-sitter parsing library", + "main": "bindings/node", + "author": "Yvan Sraka ", + "license": "ISC", + "dependencies": { + "nan": "^2.18.0" + }, + "devDependencies": { + "tree-sitter-cli": "^0.20.8" + }, + "tree-sitter": [ + { + "scope": "source.bee", + "file-types": [ + "bee" + ] + } + ] +} diff --git a/tree-sitter-bee-lang/queries/highlights.scm b/tree-sitter-bee-lang/queries/highlights.scm new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/queries/highlights.scm @@ -0,0 +1,16 @@ +(bool) @constant.builtin.boolean +(id) @variable.other +(string) @string +(target) @keyword.directive +[";"] @punctuation.delimiter +["!" "-"] @operator.unary +["..."] @operator.spread +["{" "(" "[" "]" ")" "}"] @punctuation.bracket +["=" "=>" "==" "!=" "/" "*" "%" "+" "-" "<" ">" "<=" ">=" "|" "&" "|>" "<|" ".."] @operator +["panic"] @keyword.control +["if" "else"] @keyword.control.conditional +["import"] @keyword.control.import +["native"] @function.special +["return"] @keyword.control.return +[(bigint) (f64)] @number +[(inline_comment) (block_comment)] @comment diff --git a/tree-sitter-bee-lang/queries/injections.scm b/tree-sitter-bee-lang/queries/injections.scm new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/queries/injections.scm @@ -0,0 +1,4 @@ +([(inline_comment)] @injection.content + (#set! injection.language "inline_comment")) +([(block_comment)] @injection.content + (#set! injection.language "block_comment")) diff --git a/tree-sitter-bee-lang/queries/locals.scm b/tree-sitter-bee-lang/queries/locals.scm new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/queries/locals.scm @@ -0,0 +1,5 @@ +(do (field) @scope) +(let (name) @variable) +(fn (name) @parameter) +(block_comment) @comment +(inline_comment) @comment diff --git a/tree-sitter-bee-lang/queries/tags.scm b/tree-sitter-bee-lang/queries/tags.scm new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/queries/tags.scm @@ -0,0 +1,5 @@ +(do) @foldable +(block_comment) @foldable +(array) @foldable +(if_then_else) @foldable +(fn) @foldable diff --git a/tree-sitter-bee-lang/src/grammar.json b/tree-sitter-bee-lang/src/grammar.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/src/grammar.json @@ -0,0 +1,926 @@ +{ + "name": "bee", + "word": "name", + "rules": { + "source_file": { + "type": "SYMBOL", + "name": "expr" + }, + "expr": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "fn" + }, + { + "type": "SYMBOL", + "name": "statement" + }, + { + "type": "SYMBOL", + "name": "value" + }, + { + "type": "SYMBOL", + "name": "prefix" + }, + { + "type": "SYMBOL", + "name": "infix" + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "(" + }, + { + "type": "SYMBOL", + "name": "expr" + }, + { + "type": "STRING", + "value": ")" + } + ] + } + ] + }, + "value": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "array" + }, + { + "type": "SYMBOL", + "name": "bigint" + }, + { + "type": "SYMBOL", + "name": "bool" + }, + { + "type": "SYMBOL", + "name": "id" + }, + { + "type": "SYMBOL", + "name": "f64" + }, + { + "type": "SYMBOL", + "name": "string" + }, + { + "type": "SYMBOL", + "name": "target" + } + ] + }, + "statement": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "do" + }, + { + "type": "SYMBOL", + "name": "if_then_else" + }, + { + "type": "SYMBOL", + "name": "import_" + }, + { + "type": "SYMBOL", + "name": "native_" + }, + { + "type": "SYMBOL", + "name": "panic_" + }, + { + "type": "SYMBOL", + "name": "let" + }, + { + "type": "SYMBOL", + "name": "apply" + } + ] + }, + "apply": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "REPEAT1", + "content": { + "type": "SYMBOL", + "name": "arg" + } + } + ] + }, + "arg": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "value" + }, + { + "type": "SYMBOL", + "name": "do" + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "(" + }, + { + "type": "SYMBOL", + "name": "expr" + }, + { + "type": "STRING", + "value": ")" + } + ] + } + ] + }, + "array": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "[" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "expr" + }, + { + "type": "REPEAT", + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "SYMBOL", + "name": "expr" + } + ] + } + }, + { + "type": "CHOICE", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "BLANK" + } + ] + } + ] + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": "]" + } + ] + }, + "delimiter": { + "type": "CHOICE", + "members": [ + { + "type": "STRING", + "value": ";" + }, + { + "type": "STRING", + "value": "\n" + } + ] + }, + "field": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "return_" + }, + { + "type": "SYMBOL", + "name": "statement" + }, + { + "type": "SYMBOL", + "name": "name_alias" + }, + { + "type": "SYMBOL", + "name": "spread" + } + ] + }, + "do": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "{" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "field" + }, + { + "type": "REPEAT", + "content": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "delimiter" + }, + { + "type": "SYMBOL", + "name": "field" + } + ] + } + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "delimiter" + }, + { + "type": "BLANK" + } + ] + } + ] + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": "}" + } + ] + }, + "if_then_else": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "if" + }, + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "SYMBOL", + "name": "expr" + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "else" + }, + { + "type": "SYMBOL", + "name": "expr" + } + ] + } + ] + }, + "let": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "name" + }, + { + "type": "STRING", + "value": "=" + }, + { + "type": "SYMBOL", + "name": "expr" + } + ] + }, + "fn": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "name" + }, + { + "type": "STRING", + "value": "=>" + }, + { + "type": "SYMBOL", + "name": "expr" + } + ] + }, + "spread": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "..." + }, + { + "type": "SYMBOL", + "name": "id" + } + ] + }, + "return_": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "return" + }, + { + "type": "SYMBOL", + "name": "expr" + } + ] + }, + "panic_": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "panic" + }, + { + "type": "SYMBOL", + "name": "string" + } + ] + }, + "native_": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "native" + }, + { + "type": "SYMBOL", + "name": "string" + } + ] + }, + "import_": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "import" + }, + { + "type": "SYMBOL", + "name": "string" + } + ] + }, + "id": { + "type": "SEQ", + "members": [ + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "name" + }, + { + "type": "SYMBOL", + "name": "placeholder" + } + ] + }, + { + "type": "REPEAT", + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "." + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "name" + }, + { + "type": "SYMBOL", + "name": "nth" + }, + { + "type": "SYMBOL", + "name": "placeholder" + } + ] + } + ] + } + } + ] + }, + "nth": { + "type": "PATTERN", + "value": "-?\\d+" + }, + "placeholder": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "$" + }, + { + "type": "STRING", + "value": "{" + }, + { + "type": "SYMBOL", + "name": "expr" + }, + { + "type": "STRING", + "value": "}" + } + ] + }, + "bool": { + "type": "CHOICE", + "members": [ + { + "type": "STRING", + "value": "true" + }, + { + "type": "STRING", + "value": "false" + } + ] + }, + "target": { + "type": "PATTERN", + "value": "@[a-zA-Z_][a-zA-Z0-9_]*" + }, + "name_alias": { + "type": "SYMBOL", + "name": "name" + }, + "name": { + "type": "PATTERN", + "value": "[a-zA-Z_][a-zA-Z0-9_]*" + }, + "bigint": { + "type": "PATTERN", + "value": "-?\\d+([eE]+?\\d+)?" + }, + "f64": { + "type": "PATTERN", + "value": "-?\\d+(\\.\\d+)?([eE][-+]?\\d+)?" + }, + "string": { + "type": "PATTERN", + "value": "\"([^\"\\\\]|\\\\.)*\"" + }, + "inline_comment": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "//" + }, + { + "type": "PATTERN", + "value": ".*" + } + ] + }, + "block_comment": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "/*" + }, + { + "type": "REPEAT", + "content": { + "type": "CHOICE", + "members": [ + { + "type": "PATTERN", + "value": "[^*]" + }, + { + "type": "PATTERN", + "value": "\\*[^/]" + }, + { + "type": "SYMBOL", + "name": "block_comment" + } + ] + } + }, + { + "type": "STRING", + "value": "*/" + } + ] + }, + "prefix": { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "!" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "-" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + } + ] + }, + "infix": { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "==" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "!=" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "/" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "*" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "%" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "+" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "-" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "<" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": ">" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "<=" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": ">=" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "|" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "&" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "|>" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": "<|" + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "arg" + }, + { + "type": "STRING", + "value": ".." + }, + { + "type": "SYMBOL", + "name": "arg" + } + ] + } + ] + } + }, + "extras": [ + { + "type": "PATTERN", + "value": "\\s" + }, + { + "type": "SYMBOL", + "name": "inline_comment" + }, + { + "type": "SYMBOL", + "name": "block_comment" + } + ], + "conflicts": [], + "precedences": [], + "externals": [], + "inline": [], + "supertypes": [] +} + diff --git a/tree-sitter-bee-lang/src/node-types.json b/tree-sitter-bee-lang/src/node-types.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/src/node-types.json @@ -0,0 +1,666 @@ +[ + { + "type": "apply", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "arg", + "named": true + } + ] + } + }, + { + "type": "arg", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "do", + "named": true + }, + { + "type": "expr", + "named": true + }, + { + "type": "value", + "named": true + } + ] + } + }, + { + "type": "array", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": false, + "types": [ + { + "type": "expr", + "named": true + } + ] + } + }, + { + "type": "block_comment", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": false, + "types": [ + { + "type": "block_comment", + "named": true + } + ] + } + }, + { + "type": "bool", + "named": true, + "fields": {} + }, + { + "type": "delimiter", + "named": true, + "fields": {} + }, + { + "type": "do", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": false, + "types": [ + { + "type": "delimiter", + "named": true + }, + { + "type": "field", + "named": true + } + ] + } + }, + { + "type": "expr", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "expr", + "named": true + }, + { + "type": "fn", + "named": true + }, + { + "type": "infix", + "named": true + }, + { + "type": "prefix", + "named": true + }, + { + "type": "statement", + "named": true + }, + { + "type": "value", + "named": true + } + ] + } + }, + { + "type": "field", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "name_alias", + "named": true + }, + { + "type": "return_", + "named": true + }, + { + "type": "spread", + "named": true + }, + { + "type": "statement", + "named": true + } + ] + } + }, + { + "type": "fn", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "expr", + "named": true + }, + { + "type": "name", + "named": true + } + ] + } + }, + { + "type": "id", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "name", + "named": true + }, + { + "type": "nth", + "named": true + }, + { + "type": "placeholder", + "named": true + } + ] + } + }, + { + "type": "if_then_else", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "arg", + "named": true + }, + { + "type": "expr", + "named": true + } + ] + } + }, + { + "type": "import_", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "string", + "named": true + } + ] + } + }, + { + "type": "infix", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "arg", + "named": true + } + ] + } + }, + { + "type": "inline_comment", + "named": true, + "fields": {} + }, + { + "type": "let", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "expr", + "named": true + }, + { + "type": "name", + "named": true + } + ] + } + }, + { + "type": "name_alias", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "name", + "named": true + } + ] + } + }, + { + "type": "native_", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "string", + "named": true + } + ] + } + }, + { + "type": "panic_", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "string", + "named": true + } + ] + } + }, + { + "type": "placeholder", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "expr", + "named": true + } + ] + } + }, + { + "type": "prefix", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "arg", + "named": true + } + ] + } + }, + { + "type": "return_", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "expr", + "named": true + } + ] + } + }, + { + "type": "source_file", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "expr", + "named": true + } + ] + } + }, + { + "type": "spread", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "id", + "named": true + } + ] + } + }, + { + "type": "statement", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "apply", + "named": true + }, + { + "type": "do", + "named": true + }, + { + "type": "if_then_else", + "named": true + }, + { + "type": "import_", + "named": true + }, + { + "type": "let", + "named": true + }, + { + "type": "native_", + "named": true + }, + { + "type": "panic_", + "named": true + } + ] + } + }, + { + "type": "value", + "named": true, + "fields": {}, + "children": { + "multiple": false, + "required": true, + "types": [ + { + "type": "array", + "named": true + }, + { + "type": "bigint", + "named": true + }, + { + "type": "bool", + "named": true + }, + { + "type": "f64", + "named": true + }, + { + "type": "id", + "named": true + }, + { + "type": "string", + "named": true + }, + { + "type": "target", + "named": true + } + ] + } + }, + { + "type": "\n", + "named": false + }, + { + "type": "!", + "named": false + }, + { + "type": "!=", + "named": false + }, + { + "type": "$", + "named": false + }, + { + "type": "%", + "named": false + }, + { + "type": "&", + "named": false + }, + { + "type": "(", + "named": false + }, + { + "type": ")", + "named": false + }, + { + "type": "*", + "named": false + }, + { + "type": "*/", + "named": false + }, + { + "type": "+", + "named": false + }, + { + "type": ",", + "named": false + }, + { + "type": "-", + "named": false + }, + { + "type": ".", + "named": false + }, + { + "type": "..", + "named": false + }, + { + "type": "...", + "named": false + }, + { + "type": "/", + "named": false + }, + { + "type": "/*", + "named": false + }, + { + "type": "//", + "named": false + }, + { + "type": ";", + "named": false + }, + { + "type": "<", + "named": false + }, + { + "type": "<=", + "named": false + }, + { + "type": "<|", + "named": false + }, + { + "type": "=", + "named": false + }, + { + "type": "==", + "named": false + }, + { + "type": "=>", + "named": false + }, + { + "type": ">", + "named": false + }, + { + "type": ">=", + "named": false + }, + { + "type": "[", + "named": false + }, + { + "type": "]", + "named": false + }, + { + "type": "bigint", + "named": true + }, + { + "type": "else", + "named": false + }, + { + "type": "f64", + "named": true + }, + { + "type": "false", + "named": false + }, + { + "type": "if", + "named": false + }, + { + "type": "import", + "named": false + }, + { + "type": "name", + "named": true + }, + { + "type": "native", + "named": false + }, + { + "type": "nth", + "named": true + }, + { + "type": "panic", + "named": false + }, + { + "type": "return", + "named": false + }, + { + "type": "string", + "named": true + }, + { + "type": "target", + "named": true + }, + { + "type": "true", + "named": false + }, + { + "type": "{", + "named": false + }, + { + "type": "|", + "named": false + }, + { + "type": "|>", + "named": false + }, + { + "type": "}", + "named": false + } +] \ No newline at end of file diff --git a/tree-sitter-bee-lang/src/tree_sitter/parser.h b/tree-sitter-bee-lang/src/tree_sitter/parser.h new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/src/tree_sitter/parser.h @@ -0,0 +1,224 @@ +#ifndef TREE_SITTER_PARSER_H_ +#define TREE_SITTER_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define ts_builtin_sym_error ((TSSymbol)-1) +#define ts_builtin_sym_end 0 +#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 + +typedef uint16_t TSStateId; + +#ifndef TREE_SITTER_API_H_ +typedef uint16_t TSSymbol; +typedef uint16_t TSFieldId; +typedef struct TSLanguage TSLanguage; +#endif + +typedef struct { + TSFieldId field_id; + uint8_t child_index; + bool inherited; +} TSFieldMapEntry; + +typedef struct { + uint16_t index; + uint16_t length; +} TSFieldMapSlice; + +typedef struct { + bool visible; + bool named; + bool supertype; +} TSSymbolMetadata; + +typedef struct TSLexer TSLexer; + +struct TSLexer { + int32_t lookahead; + TSSymbol result_symbol; + void (*advance)(TSLexer *, bool); + void (*mark_end)(TSLexer *); + uint32_t (*get_column)(TSLexer *); + bool (*is_at_included_range_start)(const TSLexer *); + bool (*eof)(const TSLexer *); +}; + +typedef enum { + TSParseActionTypeShift, + TSParseActionTypeReduce, + TSParseActionTypeAccept, + TSParseActionTypeRecover, +} TSParseActionType; + +typedef union { + struct { + uint8_t type; + TSStateId state; + bool extra; + bool repetition; + } shift; + struct { + uint8_t type; + uint8_t child_count; + TSSymbol symbol; + int16_t dynamic_precedence; + uint16_t production_id; + } reduce; + uint8_t type; +} TSParseAction; + +typedef struct { + uint16_t lex_state; + uint16_t external_lex_state; +} TSLexMode; + +typedef union { + TSParseAction action; + struct { + uint8_t count; + bool reusable; + } entry; +} TSParseActionEntry; + +struct TSLanguage { + uint32_t version; + uint32_t symbol_count; + uint32_t alias_count; + uint32_t token_count; + uint32_t external_token_count; + uint32_t state_count; + uint32_t large_state_count; + uint32_t production_id_count; + uint32_t field_count; + uint16_t max_alias_sequence_length; + const uint16_t *parse_table; + const uint16_t *small_parse_table; + const uint32_t *small_parse_table_map; + const TSParseActionEntry *parse_actions; + const char * const *symbol_names; + const char * const *field_names; + const TSFieldMapSlice *field_map_slices; + const TSFieldMapEntry *field_map_entries; + const TSSymbolMetadata *symbol_metadata; + const TSSymbol *public_symbol_map; + const uint16_t *alias_map; + const TSSymbol *alias_sequences; + const TSLexMode *lex_modes; + bool (*lex_fn)(TSLexer *, TSStateId); + bool (*keyword_lex_fn)(TSLexer *, TSStateId); + TSSymbol keyword_capture_token; + struct { + const bool *states; + const TSSymbol *symbol_map; + void *(*create)(void); + void (*destroy)(void *); + bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); + unsigned (*serialize)(void *, char *); + void (*deserialize)(void *, const char *, unsigned); + } external_scanner; + const TSStateId *primary_state_ids; +}; + +/* + * Lexer Macros + */ + +#define START_LEXER() \ + bool result = false; \ + bool skip = false; \ + bool eof = false; \ + int32_t lookahead; \ + goto start; \ + next_state: \ + lexer->advance(lexer, skip); \ + start: \ + skip = false; \ + lookahead = lexer->lookahead; + +#define ADVANCE(state_value) \ + { \ + state = state_value; \ + goto next_state; \ + } + +#define SKIP(state_value) \ + { \ + skip = true; \ + state = state_value; \ + goto next_state; \ + } + +#define ACCEPT_TOKEN(symbol_value) \ + result = true; \ + lexer->result_symbol = symbol_value; \ + lexer->mark_end(lexer); + +#define END_STATE() return result; + +/* + * Parse Table Macros + */ + +#define SMALL_STATE(id) id - LARGE_STATE_COUNT + +#define STATE(id) id + +#define ACTIONS(id) id + +#define SHIFT(state_value) \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .state = state_value \ + } \ + }} + +#define SHIFT_REPEAT(state_value) \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .state = state_value, \ + .repetition = true \ + } \ + }} + +#define SHIFT_EXTRA() \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .extra = true \ + } \ + }} + +#define REDUCE(symbol_val, child_count_val, ...) \ + {{ \ + .reduce = { \ + .type = TSParseActionTypeReduce, \ + .symbol = symbol_val, \ + .child_count = child_count_val, \ + __VA_ARGS__ \ + }, \ + }} + +#define RECOVER() \ + {{ \ + .type = TSParseActionTypeRecover \ + }} + +#define ACCEPT_INPUT() \ + {{ \ + .type = TSParseActionTypeAccept \ + }} + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_PARSER_H_ diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitattributes b/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitattributes new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitattributes @@ -0,0 +1,2 @@ +# Set default behavior to automatically normalize line endings. +* text=auto diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitignore b/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitignore new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.vsix \ No newline at end of file diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/.vscodeignore b/tree-sitter-bee-lang/vscode-syntax-highlighting/.vscodeignore new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/.vscodeignore @@ -0,0 +1,4 @@ +.vscode/** +.vscode-test/** +.gitignore +vsc-extension-quickstart.md diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/language-configuration.json b/tree-sitter-bee-lang/vscode-syntax-highlighting/language-configuration.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/language-configuration.json @@ -0,0 +1,28 @@ +{ + // If you discover a way to improve VSCode syntax highlighting support by editing this file (or syntaxes/bee.tmLanguage.json), + // please share it with us at devel@bee-lang.org :) + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ], + // symbols that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ] +} diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/package.json b/tree-sitter-bee-lang/vscode-syntax-highlighting/package.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/package.json @@ -0,0 +1,25 @@ +{ + "name": "bee-syntax-highlighting", + "displayName": "Bee Syntax Highlighting", + "description": "Syntax highlighting for the Bee programming language", + "version": "0.0.1", + "engines": { + "vscode": "^1.85.0" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [{ + "id": "bee", + "aliases": ["Bee", "bee"], + "extensions": [".bee"], + "configuration": "./language-configuration.json" + }], + "grammars": [{ + "language": "bee", + "scopeName": "source.bee", + "path": "./syntaxes/bee.tmLanguage.json" + }] + } +} diff --git a/tree-sitter-bee-lang/vscode-syntax-highlighting/syntaxes/bee.tmLanguage.json b/tree-sitter-bee-lang/vscode-syntax-highlighting/syntaxes/bee.tmLanguage.json new file mode 100644 --- /dev/null +++ b/tree-sitter-bee-lang/vscode-syntax-highlighting/syntaxes/bee.tmLanguage.json @@ -0,0 +1,89 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Bee", + "patterns": [ + { + "include": "#keywords" + }, + { + "include": "#strings" + }, + { + "include": "#comments" + }, + { + "include": "#operators" + }, + { + "include": "#identifiers" + } + ], + "repository": { + "keywords": { + "patterns": [{ + "name": "keyword.control.bee", + "match": "\\b(if|else|import|return|native|panic)\\b" + }] + }, + "strings": { + "name": "string.quoted.double.bee", + "begin": "\"", + "end": "\"", + "patterns": [ + { + "name": "constant.character.escape.bee", + "match": "\\\\." + }, + { + "name": "variable.string.interpolated.bee", + "begin": "\\$\\{", + "end": "\\}", + "patterns": [ + { + "include": "#variables" + } + ] + } + ] + }, + "variables": { + "patterns": [ + { + "name": "variable.name.bee", + "match": "[a-zA-Z_][a-zA-Z0-9_]*" + } + ] + }, + "comments": { + "patterns": [ + { + "name": "comment.line.double-slash.bee", + "match": "//.*" + }, + { + "begin": "/\\*", + "end": "\\*/", + "name": "comment.block.bee", + "patterns": [ + { + "include": "#comments" + } + ] + } + ] + }, + "operators": { + "patterns": [ + { + "name": "keyword.operator.arrow.bee", + "match": "=>" + }, + { + "name": "keyword.operator.assignment.bee", + "match": "=" + } + ] + } + }, + "scopeName": "source.bee" +} diff --git a/webpack-loader/index.js b/webpack-loader/index.js new file mode 100644 --- /dev/null +++ b/webpack-loader/index.js @@ -0,0 +1,11 @@ +const execSync = require('child_process').execSync; + +module.exports = function(_source) { + const callback = this.async(); + try { + const output = execSync(`bee build < ${this.resourcePath}`); + callback(null, output.toString()); + } catch (error) { + callback(error); + } +}; diff --git a/webpack-loader/package-lock.json b/webpack-loader/package-lock.json new file mode 100644 --- /dev/null +++ b/webpack-loader/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "bee-webpack-loader", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bee-webpack-loader", + "version": "0.1.0", + "license": "GPLv2" + } + } +} diff --git a/webpack-loader/package.json b/webpack-loader/package.json new file mode 100644 --- /dev/null +++ b/webpack-loader/package.json @@ -0,0 +1,8 @@ +{ + "name": "bee-webpack-loader", + "version": "0.1.0", + "description": "Webpack loader for Bee programming language .bee files", + "main": "index.js", + "author": "Yvan Sraka ", + "license": "GPLv2" +}