diff --git a/Cargo.lock b/Cargo.lock index ee1ee6f240..d360f9b417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,9 +38,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -78,7 +78,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46f6571ae16ee20c1e9a95b6ba685ca7156d519400f597c5e59f53b641637225" dependencies = [ - "dirs", + "dirs 4.0.0", "tempfile", ] @@ -231,7 +231,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -306,6 +306,207 @@ dependencies = [ "serde", ] +[[package]] +name = "biome_console" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_markup", + "biome_text_size", + "serde", + "termcolor", + "unicode-segmentation", + "unicode-width 0.1.14", +] + +[[package]] +name = "biome_deserialize" +version = "0.6.0" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_json_parser", + "biome_json_syntax", + "biome_rowan", + "enumflags2", +] + +[[package]] +name = "biome_deserialize_macros" +version = "0.6.0" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_string_case", + "proc-macro-error2", + "proc-macro2", + "quote 1.0.41", + "syn 1.0.109", +] + +[[package]] +name = "biome_diagnostics" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "backtrace", + "biome_console", + "biome_diagnostics_categories", + "biome_diagnostics_macros", + "biome_rowan", + "biome_text_edit", + "biome_text_size", + "enumflags2", + "serde", + "serde_json", + "termcolor", + "terminal_size", + "unicode-width 0.1.14", +] + +[[package]] +name = "biome_diagnostics_categories" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "quote 1.0.41", + "serde", +] + +[[package]] +name = "biome_diagnostics_macros" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote 1.0.41", + "syn 1.0.109", +] + +[[package]] +name = "biome_formatter" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_console", + "biome_deserialize", + "biome_deserialize_macros", + "biome_diagnostics", + "biome_rowan", + "biome_string_case", + "camino", + "cfg-if", + "drop_bomb", + "indexmap", + "rustc-hash", + "unicode-width 0.1.14", +] + +[[package]] +name = "biome_json_factory" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_json_syntax", + "biome_rowan", +] + +[[package]] +name = "biome_json_parser" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_json_factory", + "biome_json_syntax", + "biome_parser", + "biome_rowan", + "biome_unicode_table", + "tracing", + "unicode-bom", +] + +[[package]] +name = "biome_json_syntax" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_rowan", + "biome_string_case", + "camino", + "dirs 6.0.0", + "serde", +] + +[[package]] +name = "biome_markup" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote 1.0.41", +] + +[[package]] +name = "biome_parser" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_rowan", + "biome_unicode_table", + "drop_bomb", + "enumflags2", + "unicode-bom", +] + +[[package]] +name = "biome_rowan" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_text_edit", + "biome_text_size", + "hashbrown 0.15.5", + "rustc-hash", + "serde", +] + +[[package]] +name = "biome_string_case" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_rowan", +] + +[[package]] +name = "biome_text_edit" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "biome_text_size", + "serde", + "similar", +] + +[[package]] +name = "biome_text_size" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" +dependencies = [ + "serde", +] + +[[package]] +name = "biome_unicode_table" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome.git?tag=%40biomejs%2Fbiome%402.3.3#fd282fc5f49cee3a62c8a9d5ad1ff734c5188800" + [[package]] name = "bit-set" version = "0.8.0" @@ -356,6 +557,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bs58" version = "0.5.1" @@ -365,6 +575,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -383,6 +604,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" + [[package]] name = "cassowary" version = "0.3.0" @@ -400,9 +627,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.41" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -435,9 +662,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -445,9 +672,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -464,7 +691,7 @@ dependencies = [ "heck", "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -726,11 +953,11 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" +checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" dependencies = [ - "dispatch", + "dispatch2", "nix", "windows-sys 0.61.2", ] @@ -789,7 +1016,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -813,7 +1040,7 @@ dependencies = [ "proc-macro2", "quote 1.0.41", "strsim", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -824,7 +1051,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -839,9 +1066,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -865,7 +1092,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -886,7 +1113,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -920,7 +1147,16 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", ] [[package]] @@ -930,15 +1166,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] [[package]] -name = "dispatch" -version = "0.2.0" +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] [[package]] name = "displaydoc" @@ -948,14 +1202,14 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -966,6 +1220,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "drop_bomb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" + [[package]] name = "dunce" version = "1.0.5" @@ -1075,7 +1335,7 @@ checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1094,6 +1354,27 @@ dependencies = [ "syn 0.11.11", ] +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote 1.0.41", + "syn 2.0.108", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1146,9 +1427,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -1403,11 +1684,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1556,9 +1837,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1569,9 +1850,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1582,11 +1863,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1597,42 +1877,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1695,9 +1971,12 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "instability" @@ -1709,7 +1988,7 @@ dependencies = [ "indoc", "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1720,9 +1999,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -1730,9 +2009,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -1760,9 +2039,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1909,6 +2188,21 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "leo-fmt" +version = "3.3.1" +dependencies = [ + "anyhow", + "biome_formatter", + "colored 2.2.0", + "leo-errors", + "leo-parser", + "leo-parser-lossless", + "leo-span", + "similar", + "walkdir", +] + [[package]] name = "leo-interpreter" version = "3.3.1" @@ -1958,6 +2252,7 @@ dependencies = [ "leo-compiler", "leo-disassembler", "leo-errors", + "leo-fmt", "leo-interpreter", "leo-package", "leo-span", @@ -2118,15 +2413,15 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" @@ -2165,7 +2460,7 @@ dependencies = [ "quote 1.0.41", "regex-syntax", "rustc_version", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2225,14 +2520,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2313,7 +2608,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2360,6 +2655,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + [[package]] name = "object" version = "0.37.3" @@ -2377,9 +2687,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl" @@ -2404,7 +2714,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2425,6 +2735,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "parking_lot" version = "0.12.5" @@ -2515,9 +2831,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2543,11 +2859,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote 1.0.41", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote 1.0.41", +] + [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -2682,6 +3019,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.17", +] + [[package]] name = "regex" version = "1.12.2" @@ -2804,6 +3152,12 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2841,9 +3195,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.33" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", "once_cell", @@ -2865,18 +3219,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -3047,7 +3401,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -3098,7 +3452,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -3155,9 +3509,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio", @@ -3189,6 +3543,16 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +dependencies = [ + "bstr", + "unicode-segmentation", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -3218,9 +3582,9 @@ dependencies = [ [[package]] name = "snarkvm" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbfddf3f0d6a7578dcd4c6a6ebac28117f07b2a623f72d40aedbbde7ec8e39d8" +checksum = "e70d6faed1f12ff9baaac90a741523a70897c9149d863b621968ea0f69fb6a53" dependencies = [ "anyhow", "dotenvy", @@ -3239,9 +3603,9 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0606791227a48fa8982d02032b285a8225d840cd986f1f8343491275cdfbd5a6" +checksum = "0f86971b37e69b5306aef35c69d0f72161a060b1f8b32aca3d212f1ed2d04637" dependencies = [ "aleo-std", "anyhow", @@ -3267,9 +3631,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e61eed7a86ecbdcc67a2f37a5238961eb00c89c24276f96c3e633dc2a5b78ee8" +checksum = "fcf787de3f5a32684c6133dce0d7cc9e60a275e1f8d4693f64ed8c6b440f6607" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3282,9 +3646,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091cdb8c0a4ebe850f7f26d109cfb2b12a70d0b41a1895315991b45b1e7785ed" +checksum = "d949b4afd5d8f82f5b4eb77415992b10946bd9751a39cc2f6a065a6b7a6f5360" dependencies = [ "snarkvm-circuit-network", "snarkvm-circuit-types", @@ -3293,9 +3657,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3c1233594ef0b17834957d6ec00b9eb84f61755eedcd1899a29edca62d03f0" +checksum = "313bcc7cdfedb85fe5be3eb2e15f2e02b68b36ba82fc06d5cf4948518acc057b" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -3304,9 +3668,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a15a5bfc18983765d84f2a00794c607e780403f13766fc2522b182a992921e" +checksum = "fa18201496366b5b4df792b2a8390cd4a3b43fbda450391b53622af519bc8008" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -3315,9 +3679,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d25962a51d2c0cb0a0ded115bbece828bd5eade125a15f5a6e4e7bfdb4da1ba" +checksum = "8604e360ae3af16bdb7d24755260d93c76461b8701dfe1541db1622fa8b106b3" dependencies = [ "indexmap", "itertools 0.14.0", @@ -3334,15 +3698,15 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment-witness" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8eb77178b2a23048d1ccd4adb5ef514d87e59c55b2c472ab6ab812124c8a61" +checksum = "a5d99ae833a7aaddbe07e27ba9670bf2784e5bb50ba0b0e798b2f393dcd989c9" [[package]] name = "snarkvm-circuit-network" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "253af66ac4cd1b61e6f5b5bea869c36233a4a46708ebb5899573f788561e14c1" +checksum = "191442c2657e9331232b5eb4b7dcb2d092b8bbeba62d05e8cf5586a297eedcf1" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -3352,9 +3716,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f623587fb20b26dbb574065f417e01d19452b39c792493659f729bcc674a0473" +checksum = "6838f4bbc73db38e163b9d4da521004e10b051cbb3aadf5d98a132bbb8e5bc7a" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3367,9 +3731,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8f84a58b956c781c425e09fee6634303c7809d554f3ec51eac6bb4cbdcf25c" +checksum = "181b57e5fdfd2c0e727ccbe6235eec867cc99748df725896ec7285478a1bcdf4" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -3383,9 +3747,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "484416709c497ceed0400e16b7cbdc270a8dd4e872b932a1c0fe7fd560f37586" +checksum = "16af5c272f68f6b2ab10cfcc68d8170297a604c4dcaece052b5cd7f3a253600c" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3397,9 +3761,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da847758fd0124ea008bc2e45e33e7c826f0edf10c277be4cf78f4a174b20384" +checksum = "be45db5be35742275f1f59e36c0e8ff56bc117848029636dc64563f18e298ee3" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -3407,9 +3771,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f818f461ab9766995e1867d455d3467961581aa4c6aca89f1fdc743cbd7e14" +checksum = "4a4754c415165409c9e77f8f0f02e60e18b04e6bbfe8aa91b44948b3fd1f45f3" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3418,9 +3782,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f023f6014a427bf13ae17207327fe26a86fc28a9968c37783b1b6217dd9a36" +checksum = "b2fe589b309d79926bca0505a2a9e7978e95fb4b18899f9a0108e1e6e975cdc5" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3431,9 +3795,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "094099e885bb6388f9493004bf710158316a96257e8b3144a61ccbff79682fee" +checksum = "8f4a33327a1f2a2858bf21f9a5ae9afb2f2b85d97494c4bb707e007e822a2c78" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3444,9 +3808,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fae5ddf15b6ddf0bafbdd84072323ae97ca1037c852fde6adfa4ece2261e10b8" +checksum = "2b0ec6bacf1997791fef10d31d7be1c2efdb26b2ef73e05d1c1986b58d62d82f" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3456,9 +3820,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f16a77976a08b0f11aec89d4316567032925925285337635fd289d1aebbe10e" +checksum = "e689dc2153df5a1603cac825e094b9ec3df809c74dda2b6d0b67ee06f56f35cd" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3469,9 +3833,9 @@ dependencies = [ [[package]] name = "snarkvm-console" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278a25f266a0656fcd86ae2d23edf4ec4514102e4797a36427252f8fbee35fbd" +checksum = "9dea6574370cf8ac3c758dc1f0dd1265497af0c1e7f01a8955610a95cf8ec9e4" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -3483,9 +3847,9 @@ dependencies = [ [[package]] name = "snarkvm-console-account" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a6b7512bbce812edfa89964f0847866195025f1a25be913e70287c02fc9484" +checksum = "ea7c6463add8b7625bddd527348eecf8cda97b5a596bdfc7e67206f8c05d2ede" dependencies = [ "bs58", "snarkvm-console-network", @@ -3495,9 +3859,9 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc29540b10d850dda85ed18d55d1e289616a814784cec164686136ad23c9005" +checksum = "2f6669a797f6b8ec7919e359988b1b3ef4f6e1e7900864e4d455f2708708b9a9" dependencies = [ "blake2s_simd", "hex", @@ -3511,9 +3875,9 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0e7c13df3dd2b9b1e548cf686ac5afce750e56c588d141cb5e672c8cbe216b" +checksum = "54f04696546d115687ad110ced1dc517a0cd68c743881ff0bb78821225dd5b06" dependencies = [ "aleo-std", "rayon", @@ -3523,9 +3887,9 @@ dependencies = [ [[package]] name = "snarkvm-console-network" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b21a29cfe4f3db2b983e66d17a0304ea44d2114381389b7a98ebe2dedb9fc0" +checksum = "54edb16375212ce535092cfff04182886929712a6d5530ed4ab586ae00092fa1" dependencies = [ "anyhow", "enum-iterator", @@ -3544,9 +3908,9 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd75285546ba5ad34a7b670cd106993a146fd4648ba83341b57c92103759184" +checksum = "361a00b34d968e01f49c6f8da53119c31b23f779777d1e45762337566d926f58" dependencies = [ "anyhow", "bech32", @@ -3563,9 +3927,9 @@ dependencies = [ [[package]] name = "snarkvm-console-program" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a724b241707906b83dc4705e2d339797c0d7c69ec2d240a9f405d35f426a9b7" +checksum = "2724a0f9c3e07e39ae100fb365f9a54e7d3e572f46ae0d2d709d670d8f0889b8" dependencies = [ "enum-iterator", "enum_index", @@ -3585,9 +3949,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6793dd7c4c6478c159fda55a6d070b883480cf52cac76284833c20b1ac47e2e3" +checksum = "cd89b14c1d1a77f492e07c0b50f77e2d706a7b75d44ab1685a35a01a36fee766" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -3601,9 +3965,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db5700d0b3f8e37b13168f97ea89dbbed7940fd7457c4a6615ce45cf178fb9a" +checksum = "935164389f178ffd7da422263d36661377c21e6ddad4fd9eb24a4700ac44ebe5" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3613,18 +3977,18 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "802355742f003b23d5c8b5cda70c7cf7bb1f9b53073c7f00b936e95b0e2e3e16" +checksum = "910a4367a81f30731c3b0535eceed9a280aaf478b2e9e3298ea32a7ca04d71cf" dependencies = [ "snarkvm-console-network-environment", ] [[package]] name = "snarkvm-console-types-field" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7147389112fce94fdddf8d055333bbf70c98f972396d6cef7460ce1ff2d48d64" +checksum = "b2e9a52034ccfb9308e23b4b236b6d4075ed6bec6566d2d33a51f4f23c4b438c" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3633,9 +3997,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a4fcc6ef8d523d2767f0e313b5425aff5836b8c65cd9d7cf45a0696fbf45408" +checksum = "bb41b75c933082fa878f29070405dacf085c7a5e3b8f066f0524c4eed590d07e" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3645,9 +4009,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "811588494cb9b43c9e01f4864efa7518ba5ed89986cc033ec1af180d0d06ac78" +checksum = "831ffa9a56f9211b58d46080a4c9e3f94eace41c61a71b9303ad21732baf86c7" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3657,9 +4021,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45756f19569786bcdc739f81cd402a63c26b4136446c34805777dc00b6a625e4" +checksum = "ab607e15f5f3cb1eafa1d28d4a40fcef2f75a95034ab1f5defbeca7227c93e46" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3669,9 +4033,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015dd2984f0d4ef4cf348392454ddf6eca95f9bf4fef904302c07b1dc389eb50" +checksum = "f1f505fa474dc70240f9e9331c686f38af82df977e85427cb37b63b68a29666b" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3681,9 +4045,9 @@ dependencies = [ [[package]] name = "snarkvm-curves" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3417507f40657c8239e6fb82ddd73361c69d9cfd8a0bef134786c7047f97b3" +checksum = "2b2adf8d9a2acbafca5575f83a9d78774e6d79bd3526b02b746ee63ec167e7d9" dependencies = [ "rand", "rayon", @@ -3696,9 +4060,9 @@ dependencies = [ [[package]] name = "snarkvm-fields" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209bd033ac7c8cbbff9b0e62ff61deff371960e470d9677b867fe441a9b6a875" +checksum = "e1cc3b1f09847f7da99b556167b64f9eceb3eedc7af0f5917727007c9194123f" dependencies = [ "aleo-std", "anyhow", @@ -3714,9 +4078,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad2637f59c18850a1cb25ff70cc39948fc85a36afe53e776ef6e8ec6a1e1998" +checksum = "75f69d17a1ec56794a9ff46d5be69b68bca86cbb1ec43009a32df6c0bd8f86c7" dependencies = [ "aleo-std", "anyhow", @@ -3740,9 +4104,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-authority" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce477d2af8d466aa7d580fe6ec1c956c60bb2d6015488b03c47801039e1a6a99" +checksum = "002e33a0a88ad237da5c57aca5067a19191acea7ae4488c5476e4ace47babf3e" dependencies = [ "anyhow", "rand", @@ -3753,9 +4117,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-block" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b43eccc11644d93e872a3fb12489a8c111ed7749f9e268604ab0326b1fdb79a" +checksum = "386dc4871c03423e02bf210719a248fdfaca0682d48f5fc97b6d3bd92544a0f3" dependencies = [ "anyhow", "indexmap", @@ -3776,9 +4140,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-committee" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0c8564df9e34e9ae2af048ecb52b42a4c55ee43d9960ee617319cd85a4014e" +checksum = "33028e2cc8325895d30461b7bea220cd7eb824dfcf2587e0d44b638de90d9135" dependencies = [ "indexmap", "rayon", @@ -3789,9 +4153,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db5f21e643fa9763a318ae406b3cb4bfd854a64dc038d947d26222a76168cfb" +checksum = "24fbfa8c77bfa18892ec959e17e7bdd856a4652352c7b70887f464436a01574a" dependencies = [ "snarkvm-ledger-narwhal-batch-certificate", "snarkvm-ledger-narwhal-batch-header", @@ -3803,9 +4167,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-certificate" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ed2fc97807b65dbcd64b926a23efc6682080a81840e2edd84c1c2ba987eff6" +checksum = "67d3d400a147baa29db3a84ad85341efebb12283c3605c164affef165e182d93" dependencies = [ "indexmap", "rayon", @@ -3817,9 +4181,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-header" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfbf6ef6f8100803994160c0b18ccb50a95e333d863008b82cbfc2dcbe0d891a" +checksum = "58769eb72fe63f91acf711f4c76693a5fca72064295726f59fcb070c192f06bf" dependencies = [ "indexmap", "rayon", @@ -3830,9 +4194,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-data" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2387a11394f4ac4fe027da2d90ec4b1674226304c583068f3d81befa2f271e" +checksum = "1d6f6e4d203b4596284326c8bc5f31dc9dc5255cbfac3d00d77a2547dce9722f" dependencies = [ "bytes", "serde_json", @@ -3842,9 +4206,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-subdag" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba2891882c9299b315267cfe1bbb66001a74bdb241bdba77efb3a90166383cc" +checksum = "7653bd1c28cfe27718a87e8f6712e3fbd84e2f7f74c055ca2d3501f78b762afa" dependencies = [ "indexmap", "rayon", @@ -3858,9 +4222,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fa4f4091adaec015d8cbdbac68efb700397f4f101b1ec8f6992bbd1df7c6cd" +checksum = "0e46340004b82ed6abd4dbe42e690494b215960ecd64eba4145a8998bca167d6" dependencies = [ "bytes", "serde_json", @@ -3872,9 +4236,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission-id" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43fa7849e5d15e7ecaed1a46b4e12e3cb288ad072e4acce3952f0bf503b0283" +checksum = "0fc3a8e2ca8db6946e741d9b5fca15fb845b6647f1c8f812ef5a909995735cc2" dependencies = [ "snarkvm-console", "snarkvm-ledger-puzzle", @@ -3882,9 +4246,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a12aa22b79f751330cb8119ef559efa9317fcf299f7cebed20d0db8cc2c4452" +checksum = "112817b750d364635271c73cb057ce87b93c7e7ed4f90ff07c2e7502aaf89b1b" dependencies = [ "aleo-std", "anyhow", @@ -3902,9 +4266,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle-epoch" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be3ae1abb546466b9f061e83ab28b4e3655e8df16d9d69d4b1df8bb382c89550" +checksum = "8189964b8431b596ca13c205ad75a06955724d7944b61260496c5008e416843b" dependencies = [ "aleo-std", "anyhow", @@ -3925,9 +4289,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-query" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3e27386cf904135df0e667de520435c1e2df9381ec5aed751e831c9e0d5f54" +checksum = "3d498ad741971e12b904a6f8352cf574a63df52bde4e1b4e947a7bde9e735d92" dependencies = [ "anyhow", "async-trait", @@ -3943,9 +4307,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger-store" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef37e97b6f61947982c51abb4f67e22dbde9f10b1384c76166bd6f72b479cd38" +checksum = "128f2bce363f115e18db532f5d62cd86854d92b88520734a606969f94233ebcc" dependencies = [ "aleo-std-storage", "anyhow", @@ -3968,9 +4332,9 @@ dependencies = [ [[package]] name = "snarkvm-parameters" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55971406e99e74d427a22525e6f7e1bccd02de35b24d2f77d0f8dab6bbf90b54" +checksum = "25165b3f146ed21d737ab1077dac1b011d6d845f0026bd86771a79077661c875" dependencies = [ "aleo-std", "anyhow", @@ -3991,9 +4355,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e4452b9b0517e73daea7f8e89e5e07f81546d3d887992448bd3df3afd066dd" +checksum = "6181e0c1cbfc89bae764cd5f627a0663ca0e321f153f32233e63cc21a2defee1" dependencies = [ "aleo-std", "anyhow", @@ -4023,9 +4387,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-process" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90d40cd0ad6737ce54092636f3251160d5b835c6863ea20ccf9eb6e1220f55aa" +checksum = "5c8ba692ccaa27582ca0499e84d9162837b22c5a1bb98588e2c55006fbda0631" dependencies = [ "aleo-std", "colored 3.0.0", @@ -4048,9 +4412,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-program" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f144a0df16c0ce72a6ead9943ea00b1aaebddff39d1bb002c651f7d5e3f0bc22" +checksum = "4700d448ce9c5591b5d7de628e9a8c450096cc09796c08e2e10254e1def6123d" dependencies = [ "enum-iterator", "indexmap", @@ -4068,9 +4432,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-snark" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9b08d9097c476e878eff221bb5d3e2c8f885aa3234308746fdc44d29bd4e1f" +checksum = "581b7f70cf5a53ace9a99d6c126d1d17d0c659d568484cb3dc64ae10c37bf89f" dependencies = [ "bincode", "serde_json", @@ -4082,9 +4446,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06276676035bac7fe1a3f8141f0849d9998a22e032070c3a75816a8719f4573" +checksum = "0abfb48a504c75ce3860aefcea4b7c67143087810e88cb0d25533bb183fc4958" dependencies = [ "aleo-std", "anyhow", @@ -4105,13 +4469,13 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad221af8d6c8bcfea7b1050c65dc835850780c42fb46cadd92d933fb0717c285" +checksum = "b7d2b40fbea924467662de1deeb3ca6e4c1b7c0d49bb3eccebb6d982e5d39535" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4183,7 +4547,7 @@ dependencies = [ "proc-macro2", "quote 1.0.41", "rustversion", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4216,9 +4580,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote 1.0.41", @@ -4251,7 +4615,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4316,6 +4680,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix 1.1.2", + "windows-sys 0.60.2", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -4342,7 +4716,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4353,7 +4727,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4407,9 +4781,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -4466,9 +4840,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -4541,7 +4915,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4591,11 +4965,17 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -4767,9 +5147,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -4778,25 +5158,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote 1.0.41", - "syn 2.0.107", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -4807,9 +5173,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote 1.0.41", "wasm-bindgen-macro-support", @@ -4817,31 +5183,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote 1.0.41", - "syn 2.0.107", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -4859,9 +5225,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -4930,7 +5296,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4941,7 +5307,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5176,17 +5542,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5194,13 +5559,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] @@ -5221,7 +5586,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5241,7 +5606,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] @@ -5262,14 +5627,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -5278,9 +5643,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -5289,13 +5654,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote 1.0.41", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5328,9 +5693,9 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index e4edd684aa..d83ac5667a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ members = [ "compiler/span", "docs/grammar", "errors", + "formatter", "interpreter", "leo/package", "test-framework", @@ -61,6 +62,10 @@ version = "=3.3.1" path = "./errors" version = "=3.3.1" +[workspace.dependencies.leo-fmt] +path = "./formatter" +version = "=3.3.1" + [workspace.dependencies.leo-interpreter] path = "./interpreter" version = "=3.3.1" @@ -192,6 +197,9 @@ workspace = true [dependencies.leo-errors] workspace = true +[dependencies.leo-fmt] +workspace = true + [dependencies.leo-interpreter] workspace = true diff --git a/compiler/parser/src/lib.rs b/compiler/parser/src/lib.rs index e596a28308..c64446ec7a 100644 --- a/compiler/parser/src/lib.rs +++ b/compiler/parser/src/lib.rs @@ -34,7 +34,7 @@ use leo_span::{ sym, }; -mod conversions; +pub mod conversions; #[cfg(test)] mod test; diff --git a/formatter/Cargo.toml b/formatter/Cargo.toml new file mode 100644 index 0000000000..5fd187e3b2 --- /dev/null +++ b/formatter/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "leo-fmt" +version = "3.3.1" +authors = [ "The Leo Team " ] +description = "Formatter for Leo programming language" +homepage = "https://leo-lang.org" +repository = "https://github.com/ProvableHQ/leo" +keywords = [ + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge" +] +categories = [ "compilers", "cryptography", "web-programming" ] +include = [ "Cargo.toml", "src", "LICENSE.md" ] +license = "GPL-3.0" +edition = "2024" +rust-version = "1.88.0" + +[dependencies.leo-errors] +workspace = true + +[dependencies.leo-parser] +workspace = true + +[dependencies.leo-parser-lossless] +workspace = true + +[dependencies.leo-span] +workspace = true + +[dependencies.anyhow] +workspace = true + +[dependencies.biome_formatter] +git = "https://github.com/biomejs/biome.git" +package = "biome_formatter" +tag = "@biomejs/biome@2.3.3" + +[dependencies.colored] +workspace = true + +[dependencies.similar] +version = "2.7.0" + +[dependencies.walkdir] +workspace = true diff --git a/formatter/LICENSE.md b/formatter/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/formatter/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright © 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 General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is 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. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +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. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +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 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. Use with the GNU Affero General Public License + +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 Affero +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 special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +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 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 +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 +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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an “about box”. + +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 GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/formatter/src/composite.rs b/formatter/src/composite.rs new file mode 100644 index 0000000000..5d87549f36 --- /dev/null +++ b/formatter/src/composite.rs @@ -0,0 +1,70 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_composite(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::StructDeclaration); + + let [struct_or_record, i, maybe_const_list @ .., members] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(struct_or_record, 0)?; + self.space()?; + self.node_with_trivia(i, 0)?; + + if let Some(const_list) = maybe_const_list.first() { + self.format_const_list(const_list)?; + } + + let format_func = |slf: &mut Formatter<'_, '_>, member: &SyntaxNode<'_>| { + assert_eq!(member.kind, SyntaxKind::StructMemberDeclaration); + let [k @ .., i, c, t] = &member.children[..] else { + panic!("Can't happen"); + }; + + if let Some(k) = k.first() { + slf.node_with_trivia(k, 0)?; + slf.space()?; + } + + slf.node_with_trivia(i, 0)?; + slf.node_with_trivia(c, 0)?; + slf.space()?; + slf.format_type(t)?; + + Ok(()) + }; + + self.space()?; + self.format_collection(&members.children, true, true, format_func)?; + + Ok(()) + } +} + +impl_tests!( + test_format_composite, + src = "struct A{a:u32}", + exp = "struct A { + a: u32, +}", + Kind::Module +); diff --git a/formatter/src/consts.rs b/formatter/src/consts.rs new file mode 100644 index 0000000000..c9d8ee1805 --- /dev/null +++ b/formatter/src/consts.rs @@ -0,0 +1,94 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_const_general(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert!(matches!(node.kind, SyntaxKind::GlobalConst | SyntaxKind::Statement(StatementKind::Const))); + let [const_, name, c, type_, a, rhs, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(const_, 1)?; + + self.space()?; + + self.node_with_trivia(name, 1)?; + self.node_with_trivia(c, 1)?; + + self.space()?; + + self.format_type(type_)?; + + self.space()?; + + self.node_with_trivia(a, 1)?; + + self.group(|slf| { + slf.soft_indent_or_space(|slf| { + slf.format_expression(rhs)?; + Ok(()) + })?; + + slf.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + })?; + + Ok(()) + } +} + +impl<'a, 'b> Formatter<'a, 'b> +where + 'b: 'a, +{ + pub(super) fn format_const_list(&mut self, node: &SyntaxNode<'_>) -> Output { + let [c, s_ps_r @ ..] = &node.children[..] else { panic!("Can't happen") }; + self.node_with_trivia(c, 0)?; + let format_func = match node.kind { + SyntaxKind::ConstParameterList => |slf: &mut Formatter<'a, 'b>, node: &SyntaxNode<'_>| { + assert_eq!(node.kind, SyntaxKind::ConstParameter); + let [i, c, t] = node.children[..].as_ref() else { panic!("Can't happen") }; + slf.node_with_trivia(i, 1)?; + slf.node_with_trivia(c, 1)?; + slf.space()?; + slf.format_type(t)?; + Ok(()) + }, + SyntaxKind::ConstArgumentList => Self::format_expression, + _ => panic!("Can't happen"), + }; + + self.format_collection(s_ps_r, false, false, format_func)?; + self.space()?; + Ok(()) + } +} + +impl_tests!( + test_format_const_param_list, + src = "struct Example::[M: u32, N: u32] {}", + exp = "struct Example::[M: u32, N: u32] {}", + Kind::Module, + test_format_const_arg_list, + src = "Example::[M, N] {}", + exp = "Example::[M, N] {}", + Kind::Expression +); diff --git a/formatter/src/expressions/array.rs b/formatter/src/expressions/array.rs new file mode 100644 index 0000000000..184d8b8927 --- /dev/null +++ b/formatter/src/expressions/array.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_array(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Array)); + self.format_collection(&node.children, false, false, Self::format_expression)?; + Ok(()) + } +} + +impl_tests!( + test_format_array, + src = "[a, b, c, // ddd + d, e, f]", + exp = "[ + a, + b, + c, // ddd + d, + e, + f, +]", + Kind::Expression +); diff --git a/formatter/src/expressions/array_access.rs b/formatter/src/expressions/array_access.rs new file mode 100644 index 0000000000..7e9c44cca7 --- /dev/null +++ b/formatter/src/expressions/array_access.rs @@ -0,0 +1,37 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_array_access(&mut self, node: &SyntaxNode) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::ArrayAccess)); + let [array, left, index, right] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(array)?; + self.node_with_trivia(left, 0)?; + self.format_expression(index)?; + self.node_with_trivia(right, 0)?; + + Ok(()) + } +} + +impl_tests!(test_format_array_access, src = "a[ i ] [ i ]", exp = "a[i][i]", Kind::Expression); diff --git a/formatter/src/expressions/associated_constant.rs b/formatter/src/expressions/associated_constant.rs new file mode 100644 index 0000000000..177a548de1 --- /dev/null +++ b/formatter/src/expressions/associated_constant.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_associated_constant(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::AssociatedConstant)); + self.node_with_trivia(&node.children[0], 1)?; + Ok(()) + } +} + +impl_tests!(test_format_associated_constant, src = "group::GEN", exp = "group::GEN", Kind::Expression); diff --git a/formatter/src/expressions/associated_function_call.rs b/formatter/src/expressions/associated_function_call.rs new file mode 100644 index 0000000000..888a036428 --- /dev/null +++ b/formatter/src/expressions/associated_function_call.rs @@ -0,0 +1,35 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_associated_function_call(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::AssociatedFunctionCall)); + self.node_with_trivia(&node.children[0], 1)?; + self.format_collection(&node.children[1..], false, false, Self::format_expression)?; + Ok(()) + } +} + +impl_tests!( + test_format_associated_function_call, + src = "Pedersen64::hash(a, b, 2)", + exp = "Pedersen64::hash(a, b, 2)", + Kind::Expression +); diff --git a/formatter/src/expressions/async_expression.rs b/formatter/src/expressions/async_expression.rs new file mode 100644 index 0000000000..0c2925ca4e --- /dev/null +++ b/formatter/src/expressions/async_expression.rs @@ -0,0 +1,43 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_async(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Async)); + + let [a, block] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(a, 1)?; + self.space()?; + self.format_block(block, false)?; + Ok(()) + } +} + +impl_tests!( + test_format_async, + src = "async {return a;}", + exp = "async { + return a; +}", + Kind::Expression +); diff --git a/formatter/src/expressions/binary.rs b/formatter/src/expressions/binary.rs new file mode 100644 index 0000000000..dcc823e3c7 --- /dev/null +++ b/formatter/src/expressions/binary.rs @@ -0,0 +1,48 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_binary(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Binary)); + let [lhs, op, rhs] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(lhs)?; + self.space()?; + self.soft_indent_or_space(|slf| { + slf.node_with_trivia(op, 0)?; + slf.space()?; + slf.format_expression(rhs)?; + Ok(()) + })?; + + Ok(()) + } +} + +impl_tests!( + test_format_binary, + src = "(a + b + c + d) + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d)", + exp = "(a + b + c + d) + (a + b + c + d) * (a + b + c + d) + + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d) + + (a + b + c + d) * (a + b + c + d) + (a + b + c + d) * (a + b + c + d)", + Kind::Expression +); diff --git a/formatter/src/expressions/call.rs b/formatter/src/expressions/call.rs new file mode 100644 index 0000000000..5349f8ea05 --- /dev/null +++ b/formatter/src/expressions/call.rs @@ -0,0 +1,41 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_call(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Call)); + + let [name, rest @ ..] = &node.children[..] else { panic!("Can't happen") }; + + self.node_with_trivia(name, 1)?; + + let mut args_len = 0; + if matches!(rest[0].kind, SyntaxKind::ConstArgumentList) { + self.format_const_list(&rest[0])?; + args_len += 1; + } + + self.format_collection(&rest[args_len..], false, false, Self::format_expression)?; + + Ok(()) + } +} + +impl_tests!(test_format_call, src = "a\t\t(a,\n\n\n\n\nb)", exp = "a(a, b)", Kind::Expression); diff --git a/formatter/src/expressions/cast.rs b/formatter/src/expressions/cast.rs new file mode 100644 index 0000000000..3d33d23ced --- /dev/null +++ b/formatter/src/expressions/cast.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_cast(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Cast)); + + let [expression, as_, type_] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(expression)?; + self.space()?; + self.node_with_trivia(as_, 0)?; + self.space()?; + self.format_type(type_)?; + + Ok(()) + } +} + +impl_tests!(test_format_cast, src = "2 as\n\t\t\nu32", exp = "2 as u32", Kind::Expression); diff --git a/formatter/src/expressions/literal.rs b/formatter/src/expressions/literal.rs new file mode 100644 index 0000000000..1c8f9b2a21 --- /dev/null +++ b/formatter/src/expressions/literal.rs @@ -0,0 +1,71 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_literal(&mut self, node: &SyntaxNode) -> Output { + let SyntaxKind::Expression(ExpressionKind::Literal(kind)) = node.kind else { panic!("Can't happen") }; + let kind_text = match kind { + leo_parser_lossless::LiteralKind::Address => "", + leo_parser_lossless::LiteralKind::Boolean => "", + leo_parser_lossless::LiteralKind::Field => "field", + leo_parser_lossless::LiteralKind::Group => "group", + leo_parser_lossless::LiteralKind::Integer(integer_literal_kind) => match integer_literal_kind { + leo_parser_lossless::IntegerLiteralKind::U8 => "u8", + leo_parser_lossless::IntegerLiteralKind::U16 => "u16", + leo_parser_lossless::IntegerLiteralKind::U32 => "u32", + leo_parser_lossless::IntegerLiteralKind::U64 => "u64", + leo_parser_lossless::IntegerLiteralKind::U128 => "u128", + leo_parser_lossless::IntegerLiteralKind::I8 => "i8", + leo_parser_lossless::IntegerLiteralKind::I16 => "i16", + leo_parser_lossless::IntegerLiteralKind::I32 => "i32", + leo_parser_lossless::IntegerLiteralKind::I64 => "i64", + leo_parser_lossless::IntegerLiteralKind::I128 => "i128", + }, + leo_parser_lossless::LiteralKind::Scalar => "scalar", + leo_parser_lossless::LiteralKind::Unsuffixed => "", + leo_parser_lossless::LiteralKind::String => "", + leo_parser_lossless::LiteralKind::None => "", + }; + + self.push_snippet(format!("{}{}", node.text, kind_text).as_str())?; + self.consolidate_trivia(&node.children, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_literal_boolean, + src = "false", + exp = "false", + Kind::Expression, + test_format_literal_integer, + src = "4u32", + exp = "4u32", + Kind::Expression, + test_format_literal_scalar, + src = "123scalar", + exp = "123scalar", + Kind::Expression, + test_format_literal_unsuffixed, + src = "123", + exp = "123", + Kind::Expression +); diff --git a/formatter/src/expressions/locator.rs b/formatter/src/expressions/locator.rs new file mode 100644 index 0000000000..cf1bba934e --- /dev/null +++ b/formatter/src/expressions/locator.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_locator(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Locator)); + self.node_with_trivia(&node.children[0], 0)?; + Ok(()) + } +} + +impl_tests!(test_format_locator, src = "a.aleo/a", exp = "a.aleo/a", Kind::Expression); diff --git a/formatter/src/expressions/member_access.rs b/formatter/src/expressions/member_access.rs new file mode 100644 index 0000000000..2cd33812b0 --- /dev/null +++ b/formatter/src/expressions/member_access.rs @@ -0,0 +1,57 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests, utils::IndentMode}; + +impl Formatter<'_, '_> { + pub(super) fn format_member_access(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::MemberAccess)); + + let [struct_, dot, name] = &node.children[..] else { + panic!("Can't happen."); + }; + + self.format_expression(struct_)?; + self.block(IndentMode::SoftLine, |slf| { + slf.node_with_trivia(dot, 0)?; + slf.node_with_trivia(name, 0)?; + Ok(()) + })?; + + Ok(()) + } +} + +impl_tests!( + test_format_member_access, + src = "return a[i]\n\n\n.\n\n\t\naaaaaaaaaaaa\ + .aaaaaaaaaaaaaaa\ + .aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaa.\ + aaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaa.\ + aaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaa;", + exp = "return a[i] + .aaaaaaaaaaaa + .aaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaaaaaaaaaa + .aaaaaaaaaaaaaaaaaaaaaaaa;", + Kind::Statement +); diff --git a/formatter/src/expressions/method_call.rs b/formatter/src/expressions/method_call.rs new file mode 100644 index 0000000000..570b3b65c2 --- /dev/null +++ b/formatter/src/expressions/method_call.rs @@ -0,0 +1,38 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_method_call(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::MethodCall)); + + let [expr, dot, name, args @ ..] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(expr)?; + self.node_with_trivia(dot, 1)?; + self.node_with_trivia(name, 1)?; + self.format_collection(args, false, false, Self::format_expression)?; + + Ok(()) + } +} + +impl_tests!(test_format_method_call, src = "f.await()", exp = "f.await()", Kind::Expression); diff --git a/formatter/src/expressions/mod.rs b/formatter/src/expressions/mod.rs new file mode 100644 index 0000000000..c9d9406d82 --- /dev/null +++ b/formatter/src/expressions/mod.rs @@ -0,0 +1,73 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod array; +mod array_access; +mod associated_constant; +mod associated_function_call; +mod async_expression; +mod binary; +mod call; +mod cast; +mod literal; +mod locator; +mod member_access; +mod method_call; +mod parenthesized; +mod path; +mod repeat; +mod special_access; +mod struct_expression; +mod ternary; +mod tuple; +mod tuple_access; +mod unary; +mod unit; + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(crate) fn format_expression(&mut self, node: &SyntaxNode<'_>) -> Output { + let SyntaxKind::Expression(expression_kind) = node.kind else { panic!("Can't happen") }; + + match expression_kind { + leo_parser_lossless::ExpressionKind::ArrayAccess => self.format_array_access(node), + leo_parser_lossless::ExpressionKind::AssociatedConstant => self.format_associated_constant(node), + leo_parser_lossless::ExpressionKind::AssociatedFunctionCall => self.format_associated_function_call(node), + leo_parser_lossless::ExpressionKind::Async => self.format_async(node), + leo_parser_lossless::ExpressionKind::Array => self.format_array(node), + leo_parser_lossless::ExpressionKind::Binary => self.format_binary(node), + leo_parser_lossless::ExpressionKind::Call => self.format_call(node), + leo_parser_lossless::ExpressionKind::Cast => self.format_cast(node), + leo_parser_lossless::ExpressionKind::Path => self.format_path(node), + leo_parser_lossless::ExpressionKind::Literal(_) => self.format_literal(node), + leo_parser_lossless::ExpressionKind::Locator => self.format_locator(node), + leo_parser_lossless::ExpressionKind::MemberAccess => self.format_member_access(node), + leo_parser_lossless::ExpressionKind::MethodCall => self.format_method_call(node), + leo_parser_lossless::ExpressionKind::Parenthesized => self.format_parenthesized(node), + leo_parser_lossless::ExpressionKind::Repeat => self.format_repeat(node), + leo_parser_lossless::ExpressionKind::SpecialAccess => self.format_special_access(node), + leo_parser_lossless::ExpressionKind::Struct => self.format_struct(node), + leo_parser_lossless::ExpressionKind::Ternary => self.format_ternary(node), + leo_parser_lossless::ExpressionKind::Tuple => self.format_tuple(node), + leo_parser_lossless::ExpressionKind::TupleAccess => self.format_tuple_access(node), + leo_parser_lossless::ExpressionKind::Unary => self.format_unary(node), + leo_parser_lossless::ExpressionKind::Unit => self.format_unit_expression(node), + } + } +} diff --git a/formatter/src/expressions/parenthesized.rs b/formatter/src/expressions/parenthesized.rs new file mode 100644 index 0000000000..664811d5de --- /dev/null +++ b/formatter/src/expressions/parenthesized.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_parenthesized(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Parenthesized)); + let [left, expr, right] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(left, 1)?; + self.format_expression(expr)?; + self.node_with_trivia(right, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_parenthesized, + src = "((a+b+c+d+e+f+g)+\n\n\n\t(a+b+c+d+e+f+g)+(a+b+c+d+e+f+g))", + exp = "((a + b + c + d + e + f + g) + (a + b + c + d + e + f + g) + + (a + b + c + d + e + f + g))", + Kind::Expression +); diff --git a/formatter/src/expressions/path.rs b/formatter/src/expressions/path.rs new file mode 100644 index 0000000000..86fcf4c751 --- /dev/null +++ b/formatter/src/expressions/path.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_path(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Path)); + self.node_with_trivia(&node.children[0], 0)?; + Ok(()) + } +} + +impl_tests!(test_format_path, src = "a/*d*/", exp = "a /*d*/", Kind::Expression); diff --git a/formatter/src/expressions/repeat.rs b/formatter/src/expressions/repeat.rs new file mode 100644 index 0000000000..cdc8d48e3d --- /dev/null +++ b/formatter/src/expressions/repeat.rs @@ -0,0 +1,68 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_repeat(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Repeat)); + let [left, expr, s, count, right] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(left, 0)?; + self.format_expression(expr)?; + self.node_with_trivia(s, 0)?; + self.space()?; + self.format_expression(count)?; + self.node_with_trivia(right, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_repeat, + src = "[(abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde); (abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde,abcde)]", + exp = "[( + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, +); ( + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, + abcde, +)]", + Kind::Expression +); diff --git a/formatter/src/expressions/special_access.rs b/formatter/src/expressions/special_access.rs new file mode 100644 index 0000000000..574f7e3257 --- /dev/null +++ b/formatter/src/expressions/special_access.rs @@ -0,0 +1,37 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_special_access(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::SpecialAccess)); + + let [qualifier, dot, name] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(qualifier, 0)?; + self.node_with_trivia(dot, 0)?; + self.node_with_trivia(name, 0)?; + + Ok(()) + } +} + +impl_tests!(test_format_special_access, src = "block.height", exp = "block.height", Kind::Expression); diff --git a/formatter/src/expressions/struct_expression.rs b/formatter/src/expressions/struct_expression.rs new file mode 100644 index 0000000000..c22d2ffd0e --- /dev/null +++ b/formatter/src/expressions/struct_expression.rs @@ -0,0 +1,59 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_struct(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Struct)); + + let name = &node.children[0]; + self.node_with_trivia(name, 0)?; + + let mut args_len = 1; + if matches!(node.children[1].kind, SyntaxKind::ConstArgumentList) { + args_len += 1; + self.format_const_list(&node.children[1])?; + } + + self.space()?; + + let format_func = |slf: &mut Formatter<'_, '_>, initializer: &SyntaxNode<'_>| match &initializer.children[..] { + [init_name] => slf.node_with_trivia(init_name, 0), + [init_name, c, expr] => { + slf.node_with_trivia(init_name, 0)?; + slf.node_with_trivia(c, 0)?; + slf.space()?; + slf.format_expression(expr)?; + Ok(()) + } + _ => panic!("Can't happen"), + }; + self.format_collection(&node.children[args_len..], false, true, format_func)?; + + Ok(()) + } +} + +impl_tests!( + test_format_struct, + src = "a{a, + b,c: www,d}", + exp = "a { a, b, c: www, d }", + Kind::Expression +); diff --git a/formatter/src/expressions/ternary.rs b/formatter/src/expressions/ternary.rs new file mode 100644 index 0000000000..227d2919d1 --- /dev/null +++ b/formatter/src/expressions/ternary.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_ternary(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Ternary)); + let [cond, q, if_, c, then] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(cond)?; + self.space()?; + self.node_with_trivia(q, 0)?; + self.space()?; + self.format_expression(if_)?; + self.space()?; + self.node_with_trivia(c, 0)?; + self.space()?; + self.format_expression(then)?; + + Ok(()) + } +} + +impl_tests!(test_format_ternary, src = "a ? a : b", exp = "a ? a : b", Kind::Expression); diff --git a/formatter/src/expressions/tuple.rs b/formatter/src/expressions/tuple.rs new file mode 100644 index 0000000000..1245f9da1c --- /dev/null +++ b/formatter/src/expressions/tuple.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_tuple(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Tuple)); + self.format_collection(&node.children, false, false, Self::format_expression)?; + Ok(()) + } +} + +impl_tests!(test_format_tuple, src = "(a,b\n\n,c,3)", exp = "(a, b, c, 3)", Kind::Expression); diff --git a/formatter/src/expressions/tuple_access.rs b/formatter/src/expressions/tuple_access.rs new file mode 100644 index 0000000000..b8dff45516 --- /dev/null +++ b/formatter/src/expressions/tuple_access.rs @@ -0,0 +1,37 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_tuple_access(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::TupleAccess)); + + let [expr, dot, integer] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.format_expression(expr)?; + self.node_with_trivia(dot, 0)?; + self.node_with_trivia(integer, 0)?; + + Ok(()) + } +} + +impl_tests!(test_format_tuple_access, src = "a .\n\n0", exp = "a.0", Kind::Expression); diff --git a/formatter/src/expressions/unary.rs b/formatter/src/expressions/unary.rs new file mode 100644 index 0000000000..c956bdffaf --- /dev/null +++ b/formatter/src/expressions/unary.rs @@ -0,0 +1,35 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_unary(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Unary)); + let [op, operand] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(op, 0)?; + self.format_expression(operand)?; + + Ok(()) + } +} + +impl_tests!(test_format_unary, src = "! \na", exp = "!a", Kind::Expression); diff --git a/formatter/src/expressions/unit.rs b/formatter/src/expressions/unit.rs new file mode 100644 index 0000000000..c2c62f5cb1 --- /dev/null +++ b/formatter/src/expressions/unit.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{ExpressionKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(super) fn format_unit_expression(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Expression(ExpressionKind::Unit)); + self.node_with_trivia(node, 0)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use leo_errors::Result; + + #[test] + fn test_format_unit_expression() -> Result<()> { + let _src = "()"; + let _exp = "()"; + Ok(()) + } +} diff --git a/formatter/src/formatter.rs b/formatter/src/formatter.rs new file mode 100644 index 0000000000..c9b1190bd3 --- /dev/null +++ b/formatter/src/formatter.rs @@ -0,0 +1,201 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use std::{ffi::OsStr, fs, path::Path}; + +use anyhow::Result; +use biome_formatter::{ + IndentStyle, + IndentWidth, + LineWidth, + SimpleFormatContext, + SimpleFormatOptions, + format, + prelude::format_once, +}; +use colored::Colorize; +use leo_errors::Handler; +use leo_parser_lossless::{parse_main, parse_module}; +use similar::{ChangeTag, TextDiff}; +use walkdir::WalkDir; + +const DEFAULT_LINE_WIDTH: u16 = 80; +const UNIFIED_DIFF_HUNK_RADIUS: usize = 3; + +pub struct Formatter<'a, 'b> { + pub(crate) last_lines: u32, + pub(crate) formatter: &'a mut biome_formatter::formatter::Formatter<'b, SimpleFormatContext>, +} + +impl Formatter<'_, '_> { + pub fn format_context(line_width: u16, indent_width: u8, should_indent_style_tabs: bool) -> SimpleFormatContext { + SimpleFormatContext::new(SimpleFormatOptions { + line_width: LineWidth::try_from(line_width).unwrap(), + indent_width: IndentWidth::try_from(indent_width).unwrap(), + indent_style: if should_indent_style_tabs { IndentStyle::Tab } else { IndentStyle::Space }, + ..SimpleFormatOptions::default() + }) + } + + pub fn default_format_context() -> SimpleFormatContext { + SimpleFormatContext::new(SimpleFormatOptions { + line_width: LineWidth::try_from(DEFAULT_LINE_WIDTH).unwrap(), + indent_width: IndentWidth::try_from(4).unwrap(), + indent_style: IndentStyle::Space, + ..SimpleFormatOptions::default() + }) + } + + pub fn format_directory( + entry_file_path: impl AsRef, + modules_directory: Option>, + context_provider: impl Fn() -> SimpleFormatContext, + check_diff: bool, + ) -> Result<()> { + // Read the contents of the main source file. + let source = if entry_file_path.as_ref().exists() { Some(fs::read_to_string(&entry_file_path)?) } else { None }; + + // Walk all files under source_directory recursively, excluding the main source file itself. + let files = if let Some(dir) = modules_directory { + WalkDir::new(dir) + .into_iter() + .filter_map(Result::ok) + .filter(|e| { + e.file_type().is_file() + && e.path() != entry_file_path.as_ref() + && e.path().extension() == Some(OsStr::new("leo")) + }) + .collect::>() + } else { + Vec::new() + }; + + let mut module_sources = Vec::new(); // Keep Strings alive for valid borrowing + //let mut modules = Vec::new(); // Parsed (source, filename) tuples for compilation + let mut module_file_paths = Vec::new(); + + // Read all module files and store their contents + for file in &files { + let path = file.path(); + let source = fs::read_to_string(path)?; + module_sources.push(source); // Keep the String alive + module_file_paths.push(path); + } + + let (formatted_main, formatted_modules) = Self::format(&source, &module_sources, context_provider)?; + + assert_eq!(module_sources.len(), formatted_modules.len(), "This should not happpen."); + + let (main_diff, module_diffs) = Self::diff(&source, &module_sources, &formatted_main, &formatted_modules); + + if check_diff { + if entry_file_path.as_ref().exists() { + Self::print_diff(&main_diff.unwrap(), entry_file_path.as_ref()); + } + + for (diff, path) in module_diffs.iter().zip(module_file_paths) { + Self::print_diff(diff, path); + } + } else { + // Todo: maybe writing to disk can be optimized by the incremental thingy. + if entry_file_path.as_ref().exists() + && main_diff.unwrap().iter_all_changes().any(|c| !matches!(c.tag(), ChangeTag::Equal)) + { + fs::write(entry_file_path, formatted_main.as_ref().unwrap())?; + } + + for ((formatted_module, path), diff) in formatted_modules.iter().zip(module_file_paths).zip(module_diffs) { + if diff.iter_all_changes().any(|c| !matches!(c.tag(), ChangeTag::Equal)) { + fs::write(path, formatted_module)?; + } + } + } + + Ok(()) + } + + fn format( + main: &Option, + modules: &Vec, + context_provider: impl Fn() -> SimpleFormatContext, + ) -> Result<(Option, Vec)> { + let formatted_main = if let Some(m) = main { + let node = parse_main(Handler::default(), m, 0)?; + let fm = format!(context_provider(), [format_once(|f| { + Formatter { last_lines: 0, formatter: f }.format_main(&node) + })])?; + + Some(fm.print()?.into_code()) + } else { + None + }; + + let mut formatted_modules = Vec::new(); + for module in modules { + let node = parse_module(Handler::default(), module, 0)?; + let fm = format!(context_provider(), [format_once(|f| { + Formatter { last_lines: 0, formatter: f }.format_module(&node) + })])?; + + formatted_modules.push(fm.print()?.into_code()); + } + + Ok((formatted_main, formatted_modules)) + } + + fn diff<'a>( + main_source: &'a Option, + module_sources: &'a [String], + formatted_main: &'a Option, + formatted_modules: &'a Vec, + ) -> (Option>, Vec>) { + let main_diff = match (main_source, formatted_main) { + (Some(s), Some(f)) => Some(TextDiff::from_lines(s.as_str(), f.as_str())), + (None, None) => None, + _ => panic!("This should not happpen."), + }; + + assert_eq!(module_sources.len(), formatted_modules.len(), "This should not happpen."); + + let module_diffs = module_sources + .iter() + .zip(formatted_modules) + .map(|(s, f)| TextDiff::from_lines(s.as_str(), f.as_str())) + .collect(); + + (main_diff, module_diffs) + } + + fn print_diff<'a>(diff: &TextDiff<'a, 'a, 'a, str>, path: &Path) { + for hunk in diff.unified_diff().context_radius(UNIFIED_DIFF_HUNK_RADIUS).iter_hunks() { + let mut hunk_to_print = String::new(); + let mut diff_line = None; + for change in hunk.iter_changes() { + match change.tag() { + ChangeTag::Delete => hunk_to_print.push_str(&std::format!("{}{}", change.tag(), change).red()), + ChangeTag::Equal => hunk_to_print.push_str(std::format!("{}{}", change.tag(), change).as_str()), + ChangeTag::Insert => hunk_to_print.push_str(&std::format!("{}{}", change.tag(), change).green()), + } + if diff_line.is_none() && change.tag() != ChangeTag::Equal { + diff_line = change.old_index(); + } + } + + println!("Diff in {:?}:{}", path, diff_line.map(|i| ToString::to_string(&i)).unwrap_or("".to_string())); + println!("{hunk_to_print}"); + } + } +} diff --git a/formatter/src/functions/annotation.rs b/formatter/src/functions/annotation.rs new file mode 100644 index 0000000000..deabca1f7e --- /dev/null +++ b/formatter/src/functions/annotation.rs @@ -0,0 +1,100 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use biome_formatter::prelude::{if_group_breaks, soft_line_break_or_space, text}; +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_annotation(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Annotation); + match node.children.len() { + 2 | 3 => { + let [at, ann_name] = &node.children[..2] else { panic!("Can't happen") }; + + self.push_snippet(at.text)?; + self.push_snippet(ann_name.text)?; + + if let Some(ann_list) = node.children.get(2).filter(|list| list.children.len() > 2) { + assert_eq!(ann_list.kind, SyntaxKind::AnnotationList); + + let left = ann_list.children.first().unwrap(); + + self.node_with_trivia(left, 0)?; + + let right = ann_list.children.last().unwrap(); + + self.soft_scope(|slf| { + for (index, member) in + ann_list.children.iter().filter(|m| m.kind == SyntaxKind::AnnotationMember).enumerate() + { + let [key, assign, value] = &member.children[..] else { + panic!("Can't happen"); + }; + + if index > 0 { + slf.push_snippet(",")?; + slf.push(&soft_line_break_or_space())?; + } + slf.node_with_trivia(key, 0)?; + slf.space()?; + slf.node_with_trivia(assign, 0)?; + slf.space()?; + slf.node_with_trivia(value, 0)?; + } + + slf.push(&if_group_breaks(&text(",")))?; + + Ok(()) + })?; + + self.node_with_trivia(right, 1)?; + } + + self.consolidate_trivia(&at.children, 1)?; + self.consolidate_trivia(&ann_name.children, 1)?; + } + _ => panic!("Can't happen"), + } + Ok(()) + } +} + +impl_tests!( + test_format_annotation, + src = "program a.aleo { + @checksum(mapping = + + \"test.aleo/expected_checksum\", + + key = \"true\") + async constructor () { + let a = 4; + b = a; + } +} +", + exp = "program a.aleo { + @checksum(mapping = \"test.aleo/expected_checksum\", key = \"true\") + async constructor() { + let a = 4; + b = a; + } +} +", + Kind::Main +); diff --git a/formatter/src/functions/constructor.rs b/formatter/src/functions/constructor.rs new file mode 100644 index 0000000000..8baeb6e575 --- /dev/null +++ b/formatter/src/functions/constructor.rs @@ -0,0 +1,67 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_constructor(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Constructor); + + for ann in node.children.iter().filter(|child| child.kind == SyntaxKind::Annotation) { + self.format_annotation(ann)?; + self.maybe_bump_line()?; + } + + let [async_, cons, l, r, b] = &node.children[node.children.len() - 5..] else { panic!("Can't happen") }; + + self.node_with_trivia(async_, 0)?; + + self.space()?; + self.node_with_trivia(cons, 0)?; + + self.node_with_trivia(l, 0)?; + self.node_with_trivia(r, 0)?; + + self.space()?; + self.format_block(b, true)?; + + Ok(()) + } +} + +impl_tests!( + test_format_constructor, + src = "program a.aleo { + async constructor() { + let a = 4u32 ; + b = a + + + ; + + } + }", + exp = "program a.aleo { + async constructor() { + let a = 4u32; + b = a; + } +} +", + Kind::Main +); diff --git a/formatter/src/functions/function.rs b/formatter/src/functions/function.rs new file mode 100644 index 0000000000..2bb03ff59a --- /dev/null +++ b/formatter/src/functions/function.rs @@ -0,0 +1,131 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_function(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Function); + + let mut ann_len = 0; + while let Some(ann) = node.children.get(ann_len).filter(|child| child.kind == SyntaxKind::Annotation) { + self.format_annotation(ann)?; + self.maybe_bump_line()?; + ann_len += 1; + } + + let children = &node.children[ann_len..]; + + let (a, k, i, c, p, ar, o, b) = match children { + [k, name, p, b] => (None, k, name, None, p, None, None, b), + + [a, k, name, p, b] if a.text == "async" => (Some(a), k, name, None, p, None, None, b), + [k, name, c, p, b] => (None, k, name, Some(c), p, None, None, b), + + [a, k, name, c, p, b] if a.text == "async" => (Some(a), k, name, Some(c), p, None, None, b), + [k, name, p, ar, o, b] => (None, k, name, None, p, Some(ar), Some(o), b), + + [a, k, name, p, ar, o, b] if a.text == "async" => (Some(a), k, name, None, p, Some(ar), Some(o), b), + [k, name, c, p, ar, o, b] => (None, k, name, Some(c), p, Some(ar), Some(o), b), + + [a, k, name, c, p, ar, o, b] => (Some(a), k, name, Some(c), p, Some(ar), Some(o), b), + _ => panic!("Unexpected number of children"), + }; + + if let Some(a_) = a { + self.node_with_trivia(a_, 0)?; + self.space()?; + } + + self.node_with_trivia(k, 0)?; + self.space()?; + + self.node_with_trivia(i, 0)?; + + if let Some(c_) = c { + self.format_const_list(c_)?; + } + + let format_func = |slf: &mut Formatter<'_, '_>, node: &SyntaxNode<'_>| { + assert_eq!(node.kind, SyntaxKind::Parameter); + let [pk @ .., i, c, t] = &node.children[..] else { panic!("Can't happen") }; + if let Some(pk_) = pk.first() { + slf.node_with_trivia(pk_, 0)?; + slf.space()?; + } + + slf.node_with_trivia(i, 0)?; + slf.node_with_trivia(c, 0)?; + slf.space()?; + + slf.format_type(t)?; + + Ok(()) + }; + + self.format_collection(&p.children, false, false, format_func)?; + + if let Some(ar) = ar { + self.space()?; + self.node_with_trivia(ar, 0)?; + self.space()?; + let o = o.unwrap(); + let format_func = |slf: &mut Formatter<'_, '_>, node: &SyntaxNode<'_>| { + let [pk @ .., t] = &node.children[..] else { panic!("Can't happen") }; + if let Some(pk) = pk.first() { + slf.node_with_trivia(pk, 0)?; + slf.space()?; + } + slf.format_type(t)?; + Ok(()) + }; + match o.children.len() { + 1 | 2 => format_func(self, o), + 3 => self.format_collection(&o.children, false, false, format_func), + _ => panic!("Can't happen"), + }? + } + + self.space()?; + self.format_block(b, true)?; + + Ok(()) + } +} + +impl_tests!( + test_format_function, + src = "program a.aleo { + transition main() { + let a = 4u32 ; + b = a + + + ; + + } + }", + exp = "program a.aleo { + transition main() { + let a = 4u32; + b = a; + } +} +", + Kind::Main +); diff --git a/formatter/src/functions/mod.rs b/formatter/src/functions/mod.rs new file mode 100644 index 0000000000..466d706919 --- /dev/null +++ b/formatter/src/functions/mod.rs @@ -0,0 +1,19 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod annotation; +mod constructor; +mod function; diff --git a/formatter/src/global_const.rs b/formatter/src/global_const.rs new file mode 100644 index 0000000000..0886d506b4 --- /dev/null +++ b/formatter/src/global_const.rs @@ -0,0 +1,34 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_global_const(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::GlobalConst); + self.format_const_general(node, true)?; + Ok(()) + } +} + +impl_tests!( + test_format_global_const, + src = "const a : u32 /*f*/= 5;", + exp = "const a: u32 /*f*/ = 5;", + Kind::Module +); diff --git a/formatter/src/lib.rs b/formatter/src/lib.rs new file mode 100644 index 0000000000..a5cbcd98df --- /dev/null +++ b/formatter/src/lib.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod composite; +mod consts; +mod expressions; +mod formatter; +mod functions; +mod global_const; +mod main_entrypoint; +mod mapping; +mod module; +mod non_semantics; +mod program; +mod statements; +mod storage; +mod test_macro; +#[cfg(test)] +mod test_utils; +mod types; +mod utils; + +use biome_formatter::FormatResult; + +pub use formatter::*; + +type Output = FormatResult<()>; diff --git a/formatter/src/main_entrypoint/imports.rs b/formatter/src/main_entrypoint/imports.rs new file mode 100644 index 0000000000..7e21df7297 --- /dev/null +++ b/formatter/src/main_entrypoint/imports.rs @@ -0,0 +1,62 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_import(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Import); + let [imp, pid, smc] = &node.children[..] else { panic!("Can't happen") }; + + self.push_snippet(imp.text)?; + self.space()?; + self.push_snippet(pid.text)?; + self.push_snippet(smc.text)?; + self.space()?; + self.consolidate_trivia(&imp.children[..], 1)?; + self.consolidate_trivia(&pid.children[..], 1)?; + self.consolidate_trivia(&smc.children[..], 1) + } +} + +impl_tests!( + test_format_import, + src = "import + a.aleo + + ; + + import + a.aleo + + ; + + import //sdd + a.aleo + + ; + program a.aleo {} + ", + exp = "import a.aleo; +import a.aleo; +import a.aleo; //sdd + +program a.aleo {} +", + Kind::Main +); diff --git a/formatter/src/main_entrypoint/main.rs b/formatter/src/main_entrypoint/main.rs new file mode 100644 index 0000000000..e90705f2a3 --- /dev/null +++ b/formatter/src/main_entrypoint/main.rs @@ -0,0 +1,64 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(crate) fn format_main(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::MainContents); + + let mut trivia_start = 0; + let mut trivia_end = 0; + let mut empty_lines = true; + + for child in &node.children { + match child.kind { + SyntaxKind::Linebreak | SyntaxKind::Whitespace if empty_lines => { + trivia_start += 1; + trivia_end += 1; + } + SyntaxKind::Linebreak | SyntaxKind::Whitespace | SyntaxKind::CommentBlock | SyntaxKind::CommentLine => { + empty_lines = false; + trivia_end += 1; + } + _ => break, + } + } + + if !empty_lines && trivia_end > trivia_start { + self.consolidate_trivia(&node.children[trivia_start..trivia_end], 2)?; + self.maybe_bump_line()?; + } + + let [imports @ .., program_node] = &node.children[trivia_end..] else { panic!("can't happen") }; + + let mut import_empty_line = false; + for import in imports { + self.format_import(import)?; + self.maybe_bump_line()?; + import_empty_line = true; + } + + if import_empty_line { + self.maybe_bump_lines()?; + } + + self.format_program(program_node)?; + self.maybe_bump_line() + } +} diff --git a/formatter/src/main_entrypoint/mod.rs b/formatter/src/main_entrypoint/mod.rs new file mode 100644 index 0000000000..41dc75a45a --- /dev/null +++ b/formatter/src/main_entrypoint/mod.rs @@ -0,0 +1,18 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod imports; +mod main; diff --git a/formatter/src/mapping.rs b/formatter/src/mapping.rs new file mode 100644 index 0000000000..4c145a38f7 --- /dev/null +++ b/formatter/src/mapping.rs @@ -0,0 +1,54 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_mapping(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Mapping); + + let [mapping, name, colon, key_type, arrow, value_type, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(mapping, 0)?; + self.space()?; + self.node_with_trivia(name, 0)?; + self.node_with_trivia(colon, 0)?; + self.space()?; + self.format_type(key_type)?; + self.space()?; + self.node_with_trivia(arrow, 0)?; + self.space()?; + self.format_type(value_type)?; + self.node_with_trivia(s, 2)?; + + Ok(()) + } +} + +impl_tests!( + test_format_mapping, + src = "program a.aleo { + mapping users: u32 => u32;}", + exp = "program a.aleo { + mapping users: u32 => u32; +} +", + Kind::Main +); diff --git a/formatter/src/module.rs b/formatter/src/module.rs new file mode 100644 index 0000000000..28eb7e91b3 --- /dev/null +++ b/formatter/src/module.rs @@ -0,0 +1,59 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(super) fn format_module(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::ModuleContents); + + let mut trivia_start = 0; + let mut trivia_end = 0; + let mut empty_lines = true; + + for child in &node.children { + match child.kind { + SyntaxKind::Linebreak | SyntaxKind::Whitespace if empty_lines => { + trivia_start += 1; + trivia_end += 1; + } + SyntaxKind::Linebreak | SyntaxKind::Whitespace | SyntaxKind::CommentBlock | SyntaxKind::CommentLine => { + empty_lines = false; + trivia_end += 1; + } + _ => break, + } + } + + if !empty_lines && trivia_end > trivia_start { + self.consolidate_trivia(&node.children[trivia_start..trivia_end], 2)?; + self.maybe_bump_lines()?; + } + + for child in &node.children[trivia_end..] { + match child.kind { + SyntaxKind::Function => self.format_function(child)?, + SyntaxKind::GlobalConst => self.format_global_const(child)?, + SyntaxKind::StructDeclaration => self.format_composite(child)?, + _ => panic!("can't happen"), + } + } + + Ok(()) + } +} diff --git a/formatter/src/non_semantics.rs b/formatter/src/non_semantics.rs new file mode 100644 index 0000000000..446a8f306d --- /dev/null +++ b/formatter/src/non_semantics.rs @@ -0,0 +1,74 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use biome_formatter::{BufferExtensions, FormatElement}; +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(crate) fn consolidate_trivia(&mut self, nodes: &[SyntaxNode], line_breaks: u32) -> Output { + let mut args = Vec::new(); + let mut nodes_iter = nodes.iter().filter(|n| !matches!(n.kind, SyntaxKind::Whitespace)).peekable(); + while let Some(node) = nodes_iter.next() { + match node.kind { + SyntaxKind::Whitespace => continue, // we don't allow arbitary white spaces, they are handled manually. + SyntaxKind::Linebreak => { + match (self.last_lines, line_breaks) { + (_, 0) => continue, + (1, 1) => continue, + (x, _) if x >= 2 => continue, + _ => {} + } + args.push(FormatElement::Line(biome_formatter::prelude::LineMode::Hard)); + self.bump_lines(); + if line_breaks == 2 && matches!(nodes_iter.peek().map(|n| n.kind), Some(SyntaxKind::Linebreak)) { + args.push(FormatElement::Line(biome_formatter::prelude::LineMode::Empty)); + let _ = nodes_iter.next(); + self.bump_lines(); + } + while matches!(nodes_iter.peek().map(|n| n.kind), Some(SyntaxKind::Linebreak)) { + let _ = nodes_iter.next(); + } + + continue; + } + SyntaxKind::CommentBlock => { + args.push(FormatElement::Space); + args.push(FormatElement::DynamicText { + text: node.text.into(), + source_position: Default::default(), + }); + args.push(FormatElement::Space); + } + SyntaxKind::CommentLine => { + args.push(FormatElement::Space); + args.push(FormatElement::DynamicText { + text: node.text.into(), + source_position: Default::default(), + }); + args.push(FormatElement::Line(biome_formatter::prelude::LineMode::Hard)); + let _ = nodes_iter.next(); + } + _ => panic!("Can't happen"), + } + + self.reset_lines(); + } + + self.group(|slf| slf.formatter.write_elements(args)) + } +} diff --git a/formatter/src/program/mod.rs b/formatter/src/program/mod.rs new file mode 100644 index 0000000000..4b728a1fa9 --- /dev/null +++ b/formatter/src/program/mod.rs @@ -0,0 +1,131 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(super) fn format_program(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::ProgramDeclaration); + let [prgm, pid, left] = &node.children[..3] else { panic!("Can't happen") }; + + let right = node.children.last().unwrap(); + + self.push_snippet(prgm.text)?; + self.space()?; + self.push_snippet(pid.text)?; + self.space()?; + self.push_snippet(left.text)?; + + if prgm + .children + .iter() + .chain(pid.children.iter()) + .chain(left.children.iter()) + .any(|trivia| matches!(trivia.kind, SyntaxKind::CommentBlock | SyntaxKind::CommentLine)) + { + self.space()?; + self.consolidate_trivia(&prgm.children[..], 0)?; + self.consolidate_trivia(&pid.children[..], 0)?; + } + + let mut cons = Vec::new(); + let mut funcs = Vec::new(); + let mut consts = Vec::new(); + let mut maps = Vec::new(); + let mut structs = Vec::new(); + let mut storages = Vec::new(); + + let mut children = false; + for i in 3..node.children.len() - 1 { + children = true; + let child = &node.children[i]; + match child.kind { + SyntaxKind::Constructor => cons.push(child), + SyntaxKind::GlobalConst => consts.push(child), + SyntaxKind::Mapping => maps.push(child), + SyntaxKind::StructDeclaration => structs.push(child), + SyntaxKind::Function => funcs.push(child), + SyntaxKind::Storage => storages.push(child), + _ => panic!("Can't happen"), + } + } + + let mut written = false; + + let func = |slf: &mut Formatter<'_, '_>| { + slf.consolidate_trivia(&left.children[..], 2)?; + for child in consts { + written = true; + slf.format_global_const(child)?; + slf.maybe_bump_line_else_ignore()?; + } + + for (i, child) in maps.into_iter().enumerate() { + if i == 0 && written { + slf.maybe_bump_lines()?; + } + slf.format_mapping(child)?; + slf.maybe_bump_line_else_ignore()?; + written = true; + } + + for (i, child) in storages.into_iter().enumerate() { + if i == 0 && written { + slf.maybe_bump_lines()?; + } + slf.format_storage(child)?; + slf.maybe_bump_line_else_ignore()?; + written = true; + } + + for child in structs { + if written { + slf.maybe_bump_lines()? + } + slf.format_composite(child)?; + written = true; + } + + for child in cons { + if written { + slf.maybe_bump_lines()? + } + slf.format_constructor(child)?; + written = true; + } + + for child in funcs { + if written { + slf.maybe_bump_lines()? + } + slf.format_function(child)?; + written = true; + } + + Ok(()) + }; + + if children { + self.scope(func)?; + } + + self.node_with_trivia(right, 2)?; + + Ok(()) + } +} diff --git a/formatter/src/statements/assert.rs b/formatter/src/statements/assert.rs new file mode 100644 index 0000000000..aad51fa701 --- /dev/null +++ b/formatter/src/statements/assert.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_assert(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Assert)); + + let [a, left, expr, right, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(a, 0)?; + self.node_with_trivia(left, 0)?; + self.format_expression(expr)?; + self.node_with_trivia(right, 0)?; + self.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!(test_assert, src = "assert ( true ) ; /*com*/\n", exp = "assert(true); /*com*/\n", Kind::Statement); diff --git a/formatter/src/statements/assert_eq.rs b/formatter/src/statements/assert_eq.rs new file mode 100644 index 0000000000..bf5f101acf --- /dev/null +++ b/formatter/src/statements/assert_eq.rs @@ -0,0 +1,46 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_assert_eq(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::AssertEq)); + let [a, left, e0, c, e1, right, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(a, 0)?; + self.node_with_trivia(left, 0)?; + self.format_expression(e0)?; + self.node_with_trivia(c, 0)?; + self.space()?; + self.format_expression(e1)?; + self.node_with_trivia(right, 0)?; + self.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!( + test_assert_eq, + src = "assert_eq/*dddd*/(true, false); //444", + exp = "assert_eq /*dddd*/ (true, false); //444\n", + Kind::Statement +); diff --git a/formatter/src/statements/assert_neq.rs b/formatter/src/statements/assert_neq.rs new file mode 100644 index 0000000000..2428c6b445 --- /dev/null +++ b/formatter/src/statements/assert_neq.rs @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_assert_neq(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::AssertNeq)); + + let [a, left, e0, c, e1, right, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(a, 0)?; + self.node_with_trivia(left, 0)?; + self.format_expression(e0)?; + self.node_with_trivia(c, 0)?; + self.space()?; + self.format_expression(e1)?; + self.node_with_trivia(right, 0)?; + self.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!( + test_assert_neq, + src = "assert_neq/*dddd*/(true, false); //444", + exp = "assert_neq /*dddd*/ (true, false); //444\n", + Kind::Statement +); diff --git a/formatter/src/statements/assign.rs b/formatter/src/statements/assign.rs new file mode 100644 index 0000000000..95e5da85e2 --- /dev/null +++ b/formatter/src/statements/assign.rs @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_assign(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Assign)); + let [lhs, a, rhs, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.group(|slf| slf.format_expression(lhs))?; + self.space()?; + self.node_with_trivia(a, 0)?; + + self.group(|slf| { + slf.soft_indent_or_space(|slf| { + slf.format_expression(rhs)?; + Ok(()) + })?; + + slf.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + })?; + + Ok(()) + } +} + +impl_tests!(test_assign, src = "a.2.a.vb.3[a.x].5=/*d*/5;", exp = "a.2.a.vb.3[a.x].5 = /*d*/ 5;", Kind::Statement); diff --git a/formatter/src/statements/block.rs b/formatter/src/statements/block.rs new file mode 100644 index 0000000000..14137ea3c3 --- /dev/null +++ b/formatter/src/statements/block.rs @@ -0,0 +1,46 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(crate) fn format_block(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Block)); + let [l, stms @ .., r] = &node.children[..] else { panic!("Can't happen") }; + self.node_with_trivia(l, 1)?; + + if !stms.is_empty() { + self.scope(|slf| slf.format_statements(stms))?; + } + + self.node_with_trivia(r, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!( + test_format_block, + src = "{ + let a = b; + }", + exp = "{ + let a = b; +}", + Kind::Statement +); diff --git a/formatter/src/statements/condtional.rs b/formatter/src/statements/condtional.rs new file mode 100644 index 0000000000..2f3a0fee9b --- /dev/null +++ b/formatter/src/statements/condtional.rs @@ -0,0 +1,72 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_conditional(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Conditional)); + match &node.children[..] { + [if_, c, block] => { + self.node_with_trivia(if_, 1)?; + self.space()?; + self.format_expression(c)?; + self.space()?; + self.format_block(block, trailing_empty_lines)?; + } + [if_, c, block, else_, otherwise] => { + self.node_with_trivia(if_, 1)?; + self.space()?; + self.format_expression(c)?; + self.space()?; + self.format_block(block, trailing_empty_lines)?; + self.space()?; + self.node_with_trivia(else_, 1)?; + self.space()?; + self.format_block(otherwise, trailing_empty_lines)?; + } + + _ => panic!("Can't happen"), + } + + Ok(()) + } +} + +impl_tests!( + test_format_conditional, + src = "if /*ddd*/a { + ///dddd + + let a = 5; + } //ddd + else //ddddd + { + + b = 6 ; + }", + exp = "if /*ddd*/ a { +///dddd + let a = 5; +} //ddd +else //ddddd +{ + b = 6; +}", + Kind::Statement +); diff --git a/formatter/src/statements/const_.rs b/formatter/src/statements/const_.rs new file mode 100644 index 0000000000..a9b7b5d3a2 --- /dev/null +++ b/formatter/src/statements/const_.rs @@ -0,0 +1,34 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_const(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Const)); + self.format_const_general(node, trailing_empty_lines)?; + Ok(()) + } +} + +impl_tests!( + test_format_const, + src = "const a : u32 /*f*/= 5;", + exp = "const a: u32 /*f*/ = 5;", + Kind::Statement +); diff --git a/formatter/src/statements/definition.rs b/formatter/src/statements/definition.rs new file mode 100644 index 0000000000..0decf4755e --- /dev/null +++ b/formatter/src/statements/definition.rs @@ -0,0 +1,71 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use biome_formatter::prelude::soft_line_break; +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_definition(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Definition)); + let [l, ids @ .., a, e, s] = &node.children[..] else { panic!("Can't happen") }; + + self.node_with_trivia(l, 1)?; + self.space()?; + + let mut split = ids.split(|c| c.text == ":"); + let maybe_ids = split.next().unwrap(); + if maybe_ids.len() == 1 { + self.node_with_trivia(&maybe_ids[0], 1)?; + } else { + self.format_collection(maybe_ids, false, false, |slf, node| slf.node_with_trivia(node, 1))?; + } + + if split.next().is_some() { + let [.., c, t] = ids else { panic!("Can't happen") }; + self.node_with_trivia(c, 1)?; + self.space()?; + self.format_type(t)?; + } + + self.space()?; + self.node_with_trivia(a, 1)?; + + self.group(|slf| { + slf.soft_indent_or_space(|slf| { + slf.format_expression(e)?; + Ok(()) + })?; + + slf.push(&soft_line_break())?; + slf.push_snippet(s.text)?; + + Ok(()) + })?; + + self.consolidate_trivia(&s.children, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!( + test_format_definition, + src = "let(aa, bb, cc):u32= (55==4)+2 \n;\n", + exp = "let (aa, bb, cc): u32 = (55 == 4) + 2;\n", + Kind::Statement +); diff --git a/formatter/src/statements/expression.rs b/formatter/src/statements/expression.rs new file mode 100644 index 0000000000..b4d8ea8e66 --- /dev/null +++ b/formatter/src/statements/expression.rs @@ -0,0 +1,36 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_expression_statement(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Expression)); + let [expr, s] = &node.children[..] else { panic!("Can't happen") }; + self.format_expression(expr)?; + self.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + Ok(()) + } +} + +impl_tests!( + test_format_expression_statement, + src = "call_expression(arg);", + exp = "call_expression(arg);", + Kind::Statement +); diff --git a/formatter/src/statements/iteration.rs b/formatter/src/statements/iteration.rs new file mode 100644 index 0000000000..93fb5211b2 --- /dev/null +++ b/formatter/src/statements/iteration.rs @@ -0,0 +1,52 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_iteration(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Iteration)); + let [f, id @ .., n, low, d, hi, block] = &node.children[..] else { panic!("Can't happen") }; + + self.node_with_trivia(f, 1)?; + self.space()?; + self.node_with_trivia(&id[0], 1)?; + + if id.len() != 1 { + let [_, c, t] = id else { panic!("Can't happen") }; + self.node_with_trivia(c, 1)?; + self.space()?; + self.node_with_trivia(t, 1)?; + } + + self.space()?; + self.node_with_trivia(n, 1)?; + + self.space()?; + self.format_expression(low)?; + self.node_with_trivia(d, 1)?; + self.format_expression(hi)?; + + self.space()?; + self.format_block(block, trailing_empty_lines)?; + + Ok(()) + } +} + +impl_tests!(test_format_iteration, src = "for i in a..3{}", exp = "for i in a..3 {}", Kind::Statement); diff --git a/formatter/src/statements/mod.rs b/formatter/src/statements/mod.rs new file mode 100644 index 0000000000..ff51333208 --- /dev/null +++ b/formatter/src/statements/mod.rs @@ -0,0 +1,63 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod assert; +mod assert_eq; +mod assert_neq; +mod assign; +mod block; +mod condtional; +mod const_; +mod definition; +mod expression; +mod iteration; +mod return_statement; + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(crate) fn format_statements(&mut self, statements: &[SyntaxNode<'_>]) -> Output { + for (i, statement) in statements.iter().enumerate() { + assert!(matches!(statement.kind, SyntaxKind::Statement(_))); + let is_last = i == statements.len() - 1; + self.format_statement(statement, !is_last)?; + self.maybe_bump_line_else_ignore()?; + } + + Ok(()) + } + + pub(crate) fn format_statement(&mut self, statement: &SyntaxNode, trailing_empty_lines: bool) -> Output { + let SyntaxKind::Statement(kind) = statement.kind else { panic!("Can't happen") }; + match kind { + StatementKind::Assert => self.format_assert(statement, trailing_empty_lines)?, + StatementKind::AssertEq => self.format_assert_eq(statement, trailing_empty_lines)?, + StatementKind::AssertNeq => self.format_assert_neq(statement, trailing_empty_lines)?, + StatementKind::Assign => self.format_assign(statement, trailing_empty_lines)?, + StatementKind::Block => self.format_block(statement, trailing_empty_lines)?, + StatementKind::Conditional => self.format_conditional(statement, trailing_empty_lines)?, + StatementKind::Const => self.format_const(statement, trailing_empty_lines)?, + StatementKind::Definition => self.format_definition(statement, trailing_empty_lines)?, + StatementKind::Expression => self.format_expression_statement(statement, trailing_empty_lines)?, + StatementKind::Iteration => self.format_iteration(statement, trailing_empty_lines)?, + StatementKind::Return => self.format_return(statement, trailing_empty_lines)?, + } + + Ok(()) + } +} diff --git a/formatter/src/statements/return_statement.rs b/formatter/src/statements/return_statement.rs new file mode 100644 index 0000000000..735a358e6c --- /dev/null +++ b/formatter/src/statements/return_statement.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{StatementKind, SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_return(&mut self, node: &SyntaxNode<'_>, trailing_empty_lines: bool) -> Output { + assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Return)); + + let [r, e @ .., s] = &node.children[..] else { panic!("Can't happen") }; + + self.node_with_trivia(r, 1)?; + + if let Some(expr) = e.first() { + self.space()?; + self.group(|slf| slf.format_expression(expr))?; + } + + self.node_with_trivia(s, if trailing_empty_lines { 2 } else { 1 })?; + + Ok(()) + } +} + +impl_tests!(test_format_return, src = "return 2 \n;", exp = "return 2;", Kind::Statement); diff --git a/formatter/src/storage.rs b/formatter/src/storage.rs new file mode 100644 index 0000000000..46be63066a --- /dev/null +++ b/formatter/src/storage.rs @@ -0,0 +1,52 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_storage(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Storage); + + let [storage, name, colon, type_, s] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(storage, 0)?; + + self.space()?; + self.node_with_trivia(name, 0)?; + self.node_with_trivia(colon, 0)?; + + self.space()?; + self.format_type(type_)?; + self.node_with_trivia(s, 2)?; + + Ok(()) + } +} + +impl_tests!( + test_format_storage, + src = "program a.aleo { + storage users: [u32];}", + exp = "program a.aleo { + storage users: [u32]; +} +", + Kind::Main +); diff --git a/formatter/src/test_macro.rs b/formatter/src/test_macro.rs new file mode 100644 index 0000000000..737b198907 --- /dev/null +++ b/formatter/src/test_macro.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +#[macro_export] +macro_rules! impl_tests { + ( $($test_name:ident, src = $source:expr, exp = $expected:expr, $kind:expr),* ) => { + #[cfg(test)] + mod test { + use $crate::test_utils::{Kind, run_test}; + use leo_errors::Result; + + $( + #[test] + fn $test_name() -> Result<()> { + run_test($source, $expected, $kind) + } + )* + } + }; +} diff --git a/formatter/src/test_utils.rs b/formatter/src/test_utils.rs new file mode 100644 index 0000000000..5d21a757c6 --- /dev/null +++ b/formatter/src/test_utils.rs @@ -0,0 +1,107 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use biome_formatter::{Formatted, SimpleFormatContext, prelude::format_once}; +use leo_errors::{Handler, Result}; +use leo_parser::conversions::{to_expression, to_main, to_module, to_statement}; +use leo_parser_lossless::SyntaxNode; +//use leo_span::create_session_if_not_set_then; + +use crate::{Formatter, Output}; + +#[derive(Clone, Copy)] +pub(crate) enum Kind { + Expression, + Statement, + Module, + Main, +} + +// The idea is that a formatter must be deterministic and as well as idempotent. +// i.e. fmt(x) = fmt(fmt(x)) for all x. +pub(crate) fn run_test(source: &str, expected: &str, kind: Kind) -> Result<()> { + let tree = parse_cst(source, kind)?; + let formatted = format_kind(&tree, kind); + + let expected_tree = parse_cst(expected, kind)?; + let expected_formatted = format_kind(&expected_tree, kind); + + assert!( + formatted.print().unwrap().as_code() == expected && expected == expected_formatted.print().unwrap().as_code() + ); + + // Todo: uncomment this, we cannot do this yet as the spans will be different. + // create_session_if_not_set_then( |_| _parse_and_check_asts(&tree, &expected_tree, kind))?; + + Ok(()) +} + +fn format_kind(tree: &SyntaxNode, kind: Kind) -> Formatted { + match kind { + Kind::Expression => format(tree, |f, n| f.format_expression(n)), + Kind::Statement => format(tree, |f, n| f.format_statement(n, false)), + Kind::Module => format(tree, |f, n| f.format_module(n)), + Kind::Main => format(tree, |f, n| f.format_main(n)), + } +} + +fn format( + tree: &SyntaxNode, + formatter: impl Fn(&mut Formatter, &SyntaxNode) -> Output, +) -> Formatted { + biome_formatter::format!(Formatter::default_format_context(), [&format_once(|f| { + formatter(&mut Formatter { last_lines: 0, formatter: f }, tree) + })]) + .unwrap() +} + +fn parse_cst(src: &'_ str, kind: Kind) -> Result> { + match kind { + Kind::Expression => leo_parser_lossless::parse_expression(Handler::default(), src, 0), + Kind::Statement => leo_parser_lossless::parse_statement(Handler::default(), src, 0), + Kind::Module => leo_parser_lossless::parse_module(Handler::default(), src, 0), + Kind::Main => leo_parser_lossless::parse_main(Handler::default(), src, 0), + } +} + +fn _parse_and_check_asts(node: &SyntaxNode, expected: &SyntaxNode, kind: Kind) -> Result<()> { + match kind { + Kind::Expression => { + let ast = to_expression(node, &Default::default(), &Default::default())?; + let expected_ast = to_expression(expected, &Default::default(), &Default::default())?; + assert_eq!(ast, expected_ast); + } + Kind::Statement => { + let ast = to_statement(node, &Default::default(), &Default::default())?; + let expected_ast = to_statement(expected, &Default::default(), &Default::default())?; + assert_eq!(ast, expected_ast); + } + Kind::Module => { + let ast = + to_module(node, &Default::default(), Default::default(), Default::default(), &Default::default())?; + let expected_ast = + to_module(expected, &Default::default(), Default::default(), Default::default(), &Default::default())?; + assert_eq!(ast, expected_ast); + } + Kind::Main => { + let ast = to_main(node, &Default::default(), &Default::default())?; + let expected_ast = to_main(expected, &Default::default(), &Default::default())?; + assert_eq!(ast, expected_ast); + } + } + + Ok(()) +} diff --git a/formatter/src/types/array.rs b/formatter/src/types/array.rs new file mode 100644 index 0000000000..eb2abf86f7 --- /dev/null +++ b/formatter/src/types/array.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_array_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Array)); + let [l, type_, s, length, r] = &node.children[..] else { + panic!("Can't happen"); + }; + + self.node_with_trivia(l, 0)?; + self.format_type(type_)?; + self.node_with_trivia(s, 0)?; + self.space()?; + self.format_expression(length)?; + self.node_with_trivia(r, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_array_type, + src = "let a: [(u32,field,group,u32,field,group,u32,field, group, u32, field, group, u32,field,group); 2] = 1;", + exp = "let a: [( + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, +); 2] = 1;", + Kind::Statement +); diff --git a/formatter/src/types/composite.rs b/formatter/src/types/composite.rs new file mode 100644 index 0000000000..7ca5f2008d --- /dev/null +++ b/formatter/src/types/composite.rs @@ -0,0 +1,44 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_composite_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Composite)); + let name = &node.children[0]; + if name.text.split_once(".aleo/").is_some() { + self.node_with_trivia(name, 1)?; + } else { + self.push_snippet(name.text)?; + if let Some(arg_list) = node.children.get(1) { + self.push_snippet(arg_list.children[0].text)?; + self.format_collection(&arg_list.children[1..], false, false, Self::format_expression)?; + } + self.consolidate_trivia(&name.children, 1)?; + } + Ok(()) + } +} + +impl_tests!( + test_format_composite_type, + src = "let a: type ::[2 , 4 ] = 1;", + exp = "let a: type::[2, 4] = 1;", + Kind::Statement +); diff --git a/formatter/src/types/future.rs b/formatter/src/types/future.rs new file mode 100644 index 0000000000..a4b721a60b --- /dev/null +++ b/formatter/src/types/future.rs @@ -0,0 +1,68 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_future_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Future)); + if node.children.len() == 1 { + self.node_with_trivia(&node.children[0], 1)?; + } else { + let [f, lt, fn_, lp_types_rp @ .., rt] = &node.children[..] else { panic!("Can't happen") }; + self.push_snippet(f.text)?; + self.push_snippet(lt.text)?; + self.push_snippet(fn_.text)?; + self.format_collection(lp_types_rp, false, false, Self::format_type)?; + self.push_snippet(rt.text)?; + self.space()?; + self.consolidate_trivia(&f.children, 1)?; + self.space()?; + self.consolidate_trivia(<.children, 1)?; + self.space()?; + self.consolidate_trivia(&fn_.children, 1)?; + self.space()?; + self.consolidate_trivia(&rt.children, 1)?; + } + Ok(()) + } +} + +impl_tests!( + test_format_future_type, + src = + "let a: Future = 1;", + exp = "let a: Future = 1;", + Kind::Statement +); diff --git a/formatter/src/types/mod.rs b/formatter/src/types/mod.rs new file mode 100644 index 0000000000..ef3484b8c1 --- /dev/null +++ b/formatter/src/types/mod.rs @@ -0,0 +1,55 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +mod array; +mod composite; +mod future; +mod option; +mod tuple; +mod vector; + +use leo_parser_lossless::{SyntaxKind, SyntaxNode}; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(super) fn format_type(&mut self, node: &SyntaxNode<'_>) -> Output { + let SyntaxKind::Type(type_kind) = node.kind else { panic!("Can't happen") }; + + match type_kind { + leo_parser_lossless::TypeKind::Address + | leo_parser_lossless::TypeKind::Boolean + | leo_parser_lossless::TypeKind::Field + | leo_parser_lossless::TypeKind::Group + | leo_parser_lossless::TypeKind::Integer(_) + | leo_parser_lossless::TypeKind::Scalar + | leo_parser_lossless::TypeKind::Signature + | leo_parser_lossless::TypeKind::Numeric + | leo_parser_lossless::TypeKind::Unit => self.node_with_trivia(node, 0)?, + leo_parser_lossless::TypeKind::Tuple => self.format_tuple_type(node)?, + leo_parser_lossless::TypeKind::Array => self.format_array_type(node)?, + leo_parser_lossless::TypeKind::Composite => self.format_composite_type(node)?, + leo_parser_lossless::TypeKind::Future => self.format_future_type(node)?, + leo_parser_lossless::TypeKind::Mapping + | leo_parser_lossless::TypeKind::Identifier + | leo_parser_lossless::TypeKind::String => unimplemented!(), + leo_parser_lossless::TypeKind::Optional => self.format_option_type(node)?, + leo_parser_lossless::TypeKind::Vector => self.format_vector_type(node)?, + } + + Ok(()) + } +} diff --git a/formatter/src/types/option.rs b/formatter/src/types/option.rs new file mode 100644 index 0000000000..b89aae4648 --- /dev/null +++ b/formatter/src/types/option.rs @@ -0,0 +1,54 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_option_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Optional)); + let [inner_type, q] = &node.children[..] else { panic!("Can't happen") }; + + self.format_type(inner_type)?; + self.node_with_trivia(q, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_option_type, + src = "let a: [(u32,field,group,u32,field,group,u32,field, group, u32, field, group, u32,field,group); 2]? = 1;", + exp = "let a: [( + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, +); 2]? = 1;", + Kind::Statement +); diff --git a/formatter/src/types/tuple.rs b/formatter/src/types/tuple.rs new file mode 100644 index 0000000000..2ae7e81e7d --- /dev/null +++ b/formatter/src/types/tuple.rs @@ -0,0 +1,50 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_tuple_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Tuple)); + self.format_collection(&node.children, false, false, Self::format_type)?; + Ok(()) + } +} + +impl_tests!( + test_format_tuple_type, + src = "let a: (u32,field,group,u32,field,group,u32,field, group, u32, field, group, u32,field,group) = 1;", + exp = "let a: ( + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, +) = 1;", + Kind::Statement +); diff --git a/formatter/src/types/vector.rs b/formatter/src/types/vector.rs new file mode 100644 index 0000000000..6c5ff46f79 --- /dev/null +++ b/formatter/src/types/vector.rs @@ -0,0 +1,81 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_parser_lossless::{SyntaxKind, SyntaxNode, TypeKind}; + +use crate::{Formatter, Output, impl_tests}; + +impl Formatter<'_, '_> { + pub(super) fn format_vector_type(&mut self, node: &SyntaxNode<'_>) -> Output { + assert_eq!(node.kind, SyntaxKind::Type(TypeKind::Vector)); + + let [l, type_, r] = &node.children[..] else { panic!("Can't happen") }; + + self.node_with_trivia(l, 0)?; + self.format_type(type_)?; + self.node_with_trivia(r, 0)?; + + Ok(()) + } +} + +impl_tests!( + test_format_vector_type, + src = "let a: [(u32,field,group,u32,field,group,u32,field, group, u32, field, group, u32,field,group); 2]? = 1;", + exp = "let a: [( + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, +); 2]? = 1;", + Kind::Statement, + + test_format_vector_types, + src = "program a.aleo { + storage users: [[(u32,field,group,u32,field,group,u32,field, group, u32, field, group, u32,field,group); 2]?];}", + exp = "program a.aleo { + storage users: [[( + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + u32, + field, + group, + ); 2]?]; +} +", + Kind::Main +); diff --git a/formatter/src/utils.rs b/formatter/src/utils.rs new file mode 100644 index 0000000000..39a6bf0b9b --- /dev/null +++ b/formatter/src/utils.rs @@ -0,0 +1,265 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use biome_formatter::{ + Buffer, + Format, + FormatElement, + SimpleFormatContext, + prelude::{ + Tag, + dynamic_text, + empty_line, + hard_line_break, + if_group_breaks, + soft_line_break, + soft_line_break_or_space, + space, + tag::{Group, GroupMode}, + text, + }, + write, +}; +use leo_parser_lossless::SyntaxNode; + +use crate::{Formatter, Output}; + +impl Formatter<'_, '_> { + pub(crate) fn node_with_trivia(&mut self, node: &SyntaxNode<'_>, line_breaks: u32) -> Output { + self.push_snippet(node.text)?; + self.consolidate_trivia(&node.children[..], line_breaks)?; + Ok(()) + } + + pub(crate) fn format_collection( + &mut self, + nodes: &[SyntaxNode<'_>], + always_expand: bool, + spaces: bool, + format_func: impl Fn(&mut Self, &SyntaxNode<'_>) -> Output, + ) -> Output { + let left_delimiter = nodes.first().unwrap(); + self.push_snippet(left_delimiter.text)?; + + let block = if always_expand && nodes.len() > 2 { + Self::scope + } else if spaces { + Self::soft_scope_or_spaces + } else { + Self::soft_scope + }; + + if nodes.len() > 2 { + block(self, |slf: &mut Self| { + let [_, nodes @ .., _] = nodes else { panic!("Can't happen") }; + slf.consolidate_trivia(&left_delimiter.children, 0)?; + if let Some(first) = nodes.first() { + format_func(slf, first)?; + } + + if let Some(rest) = nodes.get(1..) { + let mut chunks = rest.chunks_exact(2); + for comma_with_node in &mut chunks { + slf.node_with_trivia(&comma_with_node[0], 0)?; + if !slf.last_line() { + slf.push(&soft_line_break_or_space())?; + } else { + slf.space()?; + } + format_func(slf, &comma_with_node[1])?; + } + + slf.push(&if_group_breaks(&text(",")))?; + // This can only be a separator + if let Some(rem) = chunks.remainder().first() { + slf.consolidate_trivia(&rem.children, 1)?; + } + } else { + slf.push(&if_group_breaks(&text(",")))?; + } + + Ok(()) + })?; + } else { + self.consolidate_trivia(&left_delimiter.children, 0)?; + } + + let right_delimiter = nodes.last().unwrap(); + self.node_with_trivia(right_delimiter, 1) + } + + pub(crate) fn group(&mut self, func: impl FnOnce(&mut Self) -> Output) -> Output { + self.formatter.write_element(FormatElement::Tag(Tag::StartGroup( + Group::new().with_id(None).with_mode(GroupMode::Flat), + )))?; + + func(self)?; + + self.formatter.write_element(FormatElement::Tag(Tag::EndGroup)) + } + + pub(crate) fn scope(&mut self, func: impl FnOnce(&mut Self) -> Output) -> Output { + self.block(IndentMode::Block, func) + } + + pub(crate) fn soft_scope(&mut self, func: impl FnOnce(&mut Self) -> Output) -> Output { + self.group(|slf| slf.block(IndentMode::Soft, func)) + } + + pub(crate) fn soft_scope_or_spaces(&mut self, func: impl FnOnce(&mut Self) -> Output) -> Output { + self.group(|slf| slf.block(IndentMode::SoftSpace, func)) + } + + pub(crate) fn soft_indent_or_space(&mut self, func: impl FnOnce(&mut Self) -> Output) -> Output { + self.group(|slf| slf.block(IndentMode::SoftLineOrSpace, func)) + } + + pub(crate) fn block(&mut self, mode: IndentMode, func: impl FnOnce(&mut Self) -> Output) -> Output { + let snapshot = self.formatter.snapshot(); + + self.formatter.write_element(FormatElement::Tag(Tag::StartIndent))?; + + match mode { + IndentMode::Soft => write!(self.formatter, [soft_line_break()])?, + IndentMode::Block => write!(self.formatter, [hard_line_break()])?, + IndentMode::SoftLine => write!(self.formatter, [soft_line_break()])?, + IndentMode::SoftLineOrSpace | IndentMode::SoftSpace => { + write!(self.formatter, [soft_line_break_or_space()])? + } + } + + let is_empty = { + let len = self.formatter.elements().len(); + func(self)?; + let new_len = self.formatter.elements().len(); + new_len == len + }; + + if is_empty { + self.formatter.restore_snapshot(snapshot); + return Ok(()); + } + + self.formatter.write_element(FormatElement::Tag(Tag::EndIndent))?; + + match mode { + IndentMode::Soft => write!(self.formatter, [soft_line_break()]), + IndentMode::Block => write!(self.formatter, [hard_line_break()]), + IndentMode::SoftLine => Ok(()), + IndentMode::SoftSpace => write!(self.formatter, [soft_line_break_or_space()]), + IndentMode::SoftLineOrSpace => Ok(()), + } + } + + pub(crate) fn push(&mut self, node: &(impl Format + ?Sized)) -> Output { + node.fmt(self.formatter) + } + + pub(crate) fn space(&mut self) -> Output { + space().fmt(self.formatter) + } + + pub(crate) fn hard_line(&mut self) -> Output { + hard_line_break().fmt(self.formatter)?; + self.bump_lines(); + Ok(()) + } + + pub(crate) fn push_snippet(&mut self, snippet: &str) -> Output { + self.reset_lines(); + self.push(&dynamic_text(snippet, Default::default())) + } + + pub(crate) fn last_line(&self) -> bool { + self.last_lines == 1 + } + + pub(crate) fn _last_double_line(&self) -> bool { + self.last_lines == 2 + } + + pub(crate) fn reset_lines(&mut self) { + self.last_lines = 0; + } + + pub(crate) fn bump_lines(&mut self) { + self.last_lines += 1; + } + + pub(crate) fn maybe_bump_line_else_ignore(&mut self) -> Output { + match self.last_lines { + 0 => self.hard_line()?, + + 1 | 2 => {} + + _ => panic!("not allowed"), + } + + self.reset_lines(); + + Ok(()) + } + + pub(crate) fn maybe_bump_line(&mut self) -> Output { + match self.last_lines { + 0 => self.hard_line()?, + + 1 => {} + + _ => panic!("not allowed"), + } + + self.reset_lines(); + + Ok(()) + } + + pub(crate) fn empty_line(&mut self) -> Output { + empty_line().fmt(self.formatter) + } + + pub(crate) fn maybe_bump_lines(&mut self) -> Output { + match self.last_lines { + 0 | 1 => { + self.empty_line()?; + } + + 2 => {} + + _ => panic!("not allowed"), + } + + self.reset_lines(); + + Ok(()) + } + + pub(crate) fn _line_suffix(&mut self, func: impl Fn(&mut Self) -> Output) -> Output { + self.formatter.write_element(FormatElement::Tag(Tag::StartLineSuffix))?; + func(self)?; + self.formatter.write_element(FormatElement::Tag(Tag::EndLineSuffix))?; + Ok(()) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub(crate) enum IndentMode { + Soft, + Block, + SoftLine, + SoftSpace, + SoftLineOrSpace, +} diff --git a/leo/cli/cli.rs b/leo/cli/cli.rs index 05543b23dc..1e6c12c86e 100644 --- a/leo/cli/cli.rs +++ b/leo/cli/cli.rs @@ -92,6 +92,11 @@ enum Commands { #[clap(flatten)] command: LeoDebug, }, + #[clap(about = "Format the leo code present in the current package.")] + Fmt { + #[clap(flatten)] + command: LeoFormat, + }, #[clap(about = "Add a new on-chain or local dependency to the current package.")] Add { #[clap(flatten)] @@ -182,6 +187,7 @@ pub fn run_with_args(cli: CLI) -> Result<()> { Commands::Synthesize { command } => command.try_execute(context), Commands::Update { command } => command.try_execute(context), Commands::Upgrade { command } => command.try_execute(context), + Commands::Fmt { command } => command.try_execute(context), } } diff --git a/leo/cli/commands/format.rs b/leo/cli/commands/format.rs new file mode 100644 index 0000000000..75c0570d24 --- /dev/null +++ b/leo/cli/commands/format.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2019-2025 Provable Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use super::*; + +use leo_fmt::Formatter; + +use std::path::PathBuf; + +// Formats the leo code in a directory. +#[derive(Parser, Debug)] +pub struct LeoFormat { + #[clap(long)] + check: bool, +} + +impl Command for LeoFormat { + type Input = (); + type Output = (); + + fn log_span(&self) -> Span { + tracing::span!(tracing::Level::INFO, "Leo") + } + + fn prelude(&self, _context: Context) -> Result { + Ok(()) + } + + fn apply(self, context: Context, _input: Self::Input) -> Result { + let _manifest = context.open_manifest()?; // just so that we can be sure that we are in a valid leo project directory. + let path = context.dir()?; + + let context_provider = || Formatter::default_format_context(); + + let source_dir = path.join(leo_package::SOURCE_DIRECTORY); + let main = source_dir.join(leo_package::MAIN_FILENAME); + Formatter::format_directory(main, Some(source_dir), context_provider, self.check)?; + + let tests_dir = path.join(leo_package::TESTS_DIRECTORY); + let tests = leo_package::Package::files_with_extension(&tests_dir, "leo"); + for test in tests { + Formatter::format_directory(test, None::, context_provider, self.check)?; + } + + Ok(()) + } +} diff --git a/leo/cli/commands/mod.rs b/leo/cli/commands/mod.rs index c7b901bda7..d9b0a22db7 100644 --- a/leo/cli/commands/mod.rs +++ b/leo/cli/commands/mod.rs @@ -42,6 +42,9 @@ pub use devnet::LeoDevnet; mod execute; pub use execute::LeoExecute; +mod format; +pub use format::LeoFormat; + pub mod query; pub use query::LeoQuery; diff --git a/leo/package/src/package.rs b/leo/package/src/package.rs index f08a715725..c9fd09448d 100644 --- a/leo/package/src/package.rs +++ b/leo/package/src/package.rs @@ -240,7 +240,7 @@ impl Package { data.into_iter() } - fn files_with_extension(path: &Path, extension: &'static str) -> impl Iterator { + pub fn files_with_extension(path: &Path, extension: &'static str) -> impl Iterator { path.read_dir() .ok() .into_iter()