diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..479e21f5 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,49 @@ +name: Documentation + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust toolchain + run: rustup show + - uses: Swatinem/rust-cache@v2 + - name: Generate Base documentation + run: cargo run -p nash-cli -- docs --base --out target/base-docs + - name: Save documentation preview + uses: actions/upload-artifact@v4 + with: + name: base-documentation + path: target/base-docs + - name: Prepare Pages artifact + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v4 + with: + path: target/base-docs + + deploy: + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + concurrency: + group: pages + cancel-in-progress: false + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy documentation + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.sampo/changesets/async-format-command.md b/.sampo/changesets/async-format-command.md new file mode 100644 index 00000000..325cc87d --- /dev/null +++ b/.sampo/changesets/async-format-command.md @@ -0,0 +1,5 @@ +--- +cargo/nash-cli: patch +--- + +Process format inputs concurrently with asynchronous filesystem and stream I/O, and keep formatting work off Tokio executor threads. diff --git a/.sampo/changesets/docs-extraction.md b/.sampo/changesets/docs-extraction.md new file mode 100644 index 00000000..5542e9e5 --- /dev/null +++ b/.sampo/changesets/docs-extraction.md @@ -0,0 +1,6 @@ +--- +cargo/nash-docs: minor +cargo/nash-driver: patch +--- + +Extract public documentation from source comments and solved interfaces, and document the compiler-bundled Base API. diff --git a/.sampo/changesets/docs-rendering.md b/.sampo/changesets/docs-rendering.md new file mode 100644 index 00000000..14507a3e --- /dev/null +++ b/.sampo/changesets/docs-rendering.md @@ -0,0 +1,5 @@ +--- +cargo/nash-docs: minor +cargo/nash-cli: minor +--- +Render searchable HTML and Markdown API documentation with `nash docs`, including compiler-bundled Base documentation. diff --git a/.sampo/changesets/formatter-compact-layout.md b/.sampo/changesets/formatter-compact-layout.md new file mode 100644 index 00000000..2de5239c --- /dev/null +++ b/.sampo/changesets/formatter-compact-layout.md @@ -0,0 +1,5 @@ +--- +cargo/nash-fmt: patch +--- + +Keep short definitions and arithmetic compact, and place do blocks after assignment and bind operators without extra indentation. diff --git a/.sampo/changesets/formatter-constraint-breaks.md b/.sampo/changesets/formatter-constraint-breaks.md new file mode 100644 index 00000000..a4801936 --- /dev/null +++ b/.sampo/changesets/formatter-constraint-breaks.md @@ -0,0 +1,5 @@ +--- +cargo/nash-fmt: patch +--- + +Wrap constrained type signatures before the fat arrow, keeping the function type together when it fits. Start multiline exposing lists on the next line. diff --git a/.sampo/changesets/iterative-flat-decoding.md b/.sampo/changesets/iterative-flat-decoding.md new file mode 100644 index 00000000..1db901a8 --- /dev/null +++ b/.sampo/changesets/iterative-flat-decoding.md @@ -0,0 +1,5 @@ +--- +cargo/nash-plutus: patch +--- + +Decode deeply nested Flat terms with an explicit stack, avoiding host stack overflow for large generated programs. diff --git a/.sampo/changesets/list-eq-representation.md b/.sampo/changesets/list-eq-representation.md new file mode 100644 index 00000000..36b7671c --- /dev/null +++ b/.sampo/changesets/list-eq-representation.md @@ -0,0 +1,18 @@ +--- +cargo/nash-ast: minor +cargo/nash-can: minor +cargo/nash-driver: minor +cargo/nash-solve: patch +cargo/nash-report: patch +cargo/nash-docs: patch +--- + +Add Primitive.map as a native pair-list alias with storable key/value types. +Map builtins and library results preserve the alias. Library Eq implementations +use structural Data equality for Big-element lists and Big/Big maps, and retain +selected element equality for Little elements and mixed maps. No optimizer +special case is needed. Generic callers with unknown element representations +must request container Eq directly. Map equality preserves order and duplicates. + +Keep reflexive Lift inference nominal when checking alias identity, so explicit +alias conversions can infer hidden type parameters without a false competitor. diff --git a/.sampo/changesets/logic-boolean-helpers.md b/.sampo/changesets/logic-boolean-helpers.md new file mode 100644 index 00000000..bb82f915 --- /dev/null +++ b/.sampo/changesets/logic-boolean-helpers.md @@ -0,0 +1,10 @@ +--- +cargo/nash-can: minor +cargo/nash-codegen: patch +cargo/nash-driver: minor +--- + +Move boolean helpers and &&/|| into Logic, below Eq and Ord. Preserve fully +applied short-circuit behavior and default application scope. Qualified callers +must use Logic.and/or/not/xor instead of Bool; explicit operator imports use +Logic instead of Prelude. Simplify equality and boolean ordering with the helpers. diff --git a/.sampo/changesets/nash-source-formatter.md b/.sampo/changesets/nash-source-formatter.md new file mode 100644 index 00000000..bf84e366 --- /dev/null +++ b/.sampo/changesets/nash-source-formatter.md @@ -0,0 +1,12 @@ +--- +cargo/nash-fmt: minor +cargo/nash-cli: minor +cargo/nash-report: minor +cargo/nash-parse: patch +--- + +Add an AST-based Nash source formatter with 80-column layout, comment preservation, +and source snapshot tests. Expose `nash format` (`fmt`), in-place and stdin +formatting, and contextual `--check` diffs through the existing report style. +Correct whitespace handling after message keywords and before constructor docs. +Allow aligned explicit continuations inside `do` without merging statements. diff --git a/.sampo/changesets/native-unit-case.md b/.sampo/changesets/native-unit-case.md new file mode 100644 index 00000000..d2b673fb --- /dev/null +++ b/.sampo/changesets/native-unit-case.md @@ -0,0 +1,5 @@ +--- +cargo/nash-codegen: patch +--- + +Lower unused native-unit bindings to a single-branch UPLC case, preserving strict sequencing without a lambda/application pair. diff --git a/.sampo/changesets/preserve-source-comments.md b/.sampo/changesets/preserve-source-comments.md new file mode 100644 index 00000000..ad476dce --- /dev/null +++ b/.sampo/changesets/preserve-source-comments.md @@ -0,0 +1,6 @@ +--- +cargo/nash-source: minor +cargo/nash-parse: minor +--- + +Preserve source comments and documentation in the surface AST for formatting and documentation extraction. Retain comment regions and text through parser backtracking, and attach module and declaration documentation. diff --git a/.sampo/changesets/remove-completed-benchmarks.md b/.sampo/changesets/remove-completed-benchmarks.md new file mode 100644 index 00000000..0f6753a2 --- /dev/null +++ b/.sampo/changesets/remove-completed-benchmarks.md @@ -0,0 +1,6 @@ +--- +cargo/nash-plutus: patch +cargo/nash-codegen: patch +cargo/nash-driver: patch +--- +Remove completed performance experiments, benchmark fixtures and unused benchmark dependencies while retaining functional coverage. diff --git a/Cargo.lock b/Cargo.lock index c8266845..274d56e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,12 +37,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "allocator-api2" version = "0.2.21" @@ -58,12 +52,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - [[package]] name = "anstream" version = "1.0.0" @@ -379,12 +367,6 @@ dependencies = [ "thiserror 2.0.21", ] -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - [[package]] name = "cc" version = "1.5.1" @@ -424,40 +406,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e82d74e6c83060ec269fe9e0d408d6de4a1645d525f9a0bbbb841ba4efd91ac" dependencies = [ "hashbrown 0.15.5", - "regex-automata 0.3.9", + "regex-automata", "serde", "stacker", "unicode-ident", "unicode-segmentation", ] -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - [[package]] name = "cipher" version = "0.4.4" @@ -488,7 +443,6 @@ dependencies = [ "anstyle", "clap_lex", "strsim", - "terminal_size", ] [[package]] @@ -497,7 +451,7 @@ version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 3.0.6", @@ -536,12 +490,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" -[[package]] -name = "condtype" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" - [[package]] name = "console" version = "0.16.6" @@ -614,39 +562,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "criterion" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" -dependencies = [ - "anes", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_json", - "tinytemplate", - "walkdir 2.5.0", -] - -[[package]] -name = "criterion-plot" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" -dependencies = [ - "cast", - "itertools", -] - [[package]] name = "crossbeam-deque" version = "0.8.8" @@ -672,12 +587,6 @@ version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - [[package]] name = "crypto-bigint" version = "0.5.5" @@ -831,31 +740,6 @@ dependencies = [ "syn 3.0.6", ] -[[package]] -name = "divan" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a405457ec78b8fe08b0e32b4a3570ab5dff6dd16eb9e76a5ee0a9d9cbd898933" -dependencies = [ - "cfg-if", - "clap", - "condtype", - "divan-macros", - "libc", - "regex-lite", -] - -[[package]] -name = "divan-macros" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9556bc800956545d6420a640173e5ba7dfa82f38d3ea5a167eb555bc69ac3323" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "ecdsa" version = "0.16.9" @@ -1112,7 +996,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "walkdir 0.1.8", + "walkdir", ] [[package]] @@ -1187,17 +1071,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - [[package]] name = "hamming" version = "0.1.3" @@ -1227,12 +1100,6 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -1623,15 +1490,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1920,9 +1778,12 @@ dependencies = [ "miette", "nash-codegen", "nash-config", + "nash-docs", "nash-driver", + "nash-fmt", "nash-language-server", "nash-plutus", + "nash-region", "nash-report", "nash-test", "octocrab", @@ -1986,6 +1847,29 @@ dependencies = [ "nash-region", ] +[[package]] +name = "nash-docs" +version = "0.1.0" +dependencies = [ + "bumpalo", + "indoc", + "insta", + "nash-ast", + "nash-can", + "nash-config", + "nash-driver", + "nash-parse", + "nash-report", + "nash-source", + "pulldown-cmark", + "serde", + "serde_json", + "tempfile", + "thiserror 2.0.21", + "tokio", + "url", +] + [[package]] name = "nash-driver" version = "0.11.0" @@ -2015,6 +1899,19 @@ dependencies = [ "url", ] +[[package]] +name = "nash-fmt" +version = "0.1.0" +dependencies = [ + "bumpalo", + "indoc", + "insta", + "nash-parse", + "nash-region", + "nash-report", + "nash-source", +] + [[package]] name = "nash-ir" version = "0.3.3" @@ -2071,19 +1968,15 @@ dependencies = [ "blst", "bumpalo", "chumsky", - "criterion", "cryptoxide", - "divan", "hamming", "hex", "insta", - "itertools", "minicbor", "num", "num-bigint", "num-integer", "once_cell", - "ouroboros", "pretty_assertions", "secp256k1", "thiserror 2.0.21", @@ -2111,6 +2004,7 @@ dependencies = [ "nash-source", "serde", "serde_json", + "similar", "unicode-width 0.1.14", ] @@ -2341,12 +2235,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "oorandom" -version = "11.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" - [[package]] name = "openssl-probe" version = "0.2.1" @@ -2359,30 +2247,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ouroboros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.119", -] - [[package]] name = "owo-colors" version = "4.4.0" @@ -2514,34 +2378,6 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - [[package]] name = "potential_utf" version = "0.1.6" @@ -2607,19 +2443,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "version_check", - "yansi", -] - [[package]] name = "psm" version = "0.1.32" @@ -2645,6 +2468,24 @@ dependencies = [ "version-ranges", ] +[[package]] +name = "pulldown-cmark" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" +dependencies = [ + "bitflags", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "quote" version = "1.0.47" @@ -2755,18 +2596,6 @@ dependencies = [ "syn 3.0.6", ] -[[package]] -name = "regex" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.18", - "regex-syntax 0.8.11", -] - [[package]] name = "regex-automata" version = "0.3.9" @@ -2775,38 +2604,15 @@ checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", -] - -[[package]] -name = "regex-automata" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.11", + "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" - [[package]] name = "regex-syntax" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" -[[package]] -name = "regex-syntax" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" - [[package]] name = "rfc6979" version = "0.4.0" @@ -2944,15 +2750,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "schannel" version = "0.1.29" @@ -3202,7 +2999,7 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.119", @@ -3253,12 +3050,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -3465,22 +3256,13 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "tokio" version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ + "bytes", "libc", "mio", "pin-project-lite", @@ -3635,6 +3417,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + [[package]] name = "unicode-ident" version = "1.0.26" @@ -3716,16 +3504,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -3795,16 +3573,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "web-time" version = "1.1.0" @@ -3828,15 +3596,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "windows-core" version = "0.62.2" diff --git a/SPEC.md b/SPEC.md index c348e2b9..c242b9e0 100644 --- a/SPEC.md +++ b/SPEC.md @@ -32,11 +32,11 @@ produce UPLC programs; all dependencies inline into each program. | `nash-codegen` | Can -> Core -> UPLC | new ([plans/07](plans/07-codegen.md)) | | `nash-test` | test runner, generation, shrinking | new ([plans/10](plans/10-testing.md)) | | `nash-macro` | macro expansion, comptime | new ([plans/11](plans/11-macros-comptime.md)) | -| `nash-fmt` / `nash-docs` | formatter, docs | new ([plans/13](plans/13-fmt-docs.md)) | +| `nash-fmt` / `nash-docs` | formatter, docs | formatter and documentation implemented ([plans/13](plans/13-fmt-docs.md)) | | `nash-plutus` | UPLC terms, flat, CEK, cost models | done | | `nash-config` | `nash.jsonc` | done, extend | | `nash-driver` | build graph, caching | done, extend | -| `nash-cli` | `nash` binary | `check`, `lsp`; add `build test fmt docs` | +| `nash-cli` | `nash` binary | `check`, `build`, `test`, `format` (`fmt`), `docs`, `lsp` | | `nash-language-server` | LSP | live compiler diagnostics with UTF-16 ranges | | `crates/nash-driver/base/` | compiler-bundled `nash/base` foundation (Nash source) | implemented; remaining stdlib work ([plans/12](plans/12-stdlib.md)) | @@ -63,14 +63,16 @@ Implementation plans (Plan 08 is deferred; Plans 09 and 10 are complete): - [x] 05 Exhaustiveness (`Nitpick/PatternMatches` port) — [plans/05-nitpick.md](plans/05-nitpick.md) - [x] 06 Diagnostics (`nash-report`, concise source labels, stable codes, JSON/LSP) — [plans/06-diagnostics.md](plans/06-diagnostics.md); [concise diagnostics refactor](plans/diagnostics-refactor.md) complete - [x] 07 Codegen: Core IR, monomorphization, decision trees, recursion, Data casts, UPLC lowering — [plans/07-codegen.md](plans/07-codegen.md) -- [ ] 08 Optimizer: inlining, builtin force caching, DCE, case-of-known-ctor/constant folding — [plans/08-optimizer.md](plans/08-optimizer.md) (deferred) +- [ ] 08 Optimizer: ANF and optimization before recursion rewrite, post-rewrite cleanup, inlining, builtin force caching, DCE, case-of-known-ctor/constant folding — [plans/08-optimizer.md](plans/08-optimizer.md) (deferred) - [x] 09 Validators + `nash build` — [plans/09-validators-build.md](plans/09-validators-build.md) - [x] 10 Testing: `tests` block, props, generators, shrinking, power-assert, `nash test` — [plans/10-testing.md](plans/10-testing.md) -- [ ] 11 Macros + comptime — [plans/11-macros-comptime.md](plans/11-macros-comptime.md) +- [ ] 11 Macros + comptime — [plans/11-macros-comptime.md](plans/11-macros-comptime.md); includes explicit integer-dispatch AST and positional library macro (chunk 13), reusable call/binding/case-shaped macro inputs required in chunk 14 (library semantics deferred) - [ ] 12 Stdlib `nash/base` — [plans/12-stdlib.md](plans/12-stdlib.md) (chunks 1–9 and 11–13 complete; chunk 10 Ast/Derive deferred) -- [ ] 13 `nash fmt`, `nash docs` — [plans/13-fmt-docs.md](plans/13-fmt-docs.md) +- [x] 13 `nash format` (`fmt`), `nash docs` — [plans/13-fmt-docs.md](plans/13-fmt-docs.md) (chunks 1–7 complete) - [x] Representation-classed impl heads: `Big`/`Little` blankets and concrete little impls coexist — [plans/repr-classed-impl-heads.md](plans/repr-classed-impl-heads.md) +- [ ] 14 Explicit Big constructor tags: preserve declared Data tags; little tags remain consecutive from zero — [plans/14-explicit-big-constructor-tags.md](plans/14-explicit-big-constructor-tags.md) + Later: LSP features, web playground, package registry (pubgrub), TypeScript codegen. ## Elm file mappings diff --git a/crates/nash-ast/src/primitives.rs b/crates/nash-ast/src/primitives.rs index cb5bfb52..db3743f3 100644 --- a/crates/nash-ast/src/primitives.rs +++ b/crates/nash-ast/src/primitives.rs @@ -1,5 +1,35 @@ //! Compiler-owned types and representation predicates of `nash/base.Primitive`. +// Native map is an ordinary transparent alias, with nominal impl identity. +macro_rules! native_map_type { + ($key:expr, $value:expr) => { + &nash_region::Located::at_zero(crate::Type::Alias { + reference: crate::QualifiedName { + home: crate::primitives::primitive_home(), + name: "map", + }, + arguments: &[ + crate::AliasArgument { + name: "k", + typ: $key, + }, + crate::AliasArgument { + name: "v", + typ: $value, + }, + ], + remaining: &[], + target: crate::AliasType::Filled { + body: crate::primitives::MAP_BODY, + typ: &crate::primitives::builtins::named( + "list", + &[&crate::primitives::builtins::named("pair", &[$key, $value])], + ), + }, + }) + }; +} + mod builtins; pub use builtins::{BUILTINS, Builtin, COERCE}; @@ -169,6 +199,38 @@ pub struct Primitive { const TYPE: &Kind<'static> = &Kind::Type; const UNARY: &Kind<'static> = &Kind::Arrow(TYPE, TYPE); const BINARY: &Kind<'static> = &Kind::Arrow(TYPE, UNARY); +pub struct PrimitiveAlias { + pub name: &'static str, + pub kind: &'static Kind<'static>, + pub parameters: &'static [&'static str], + pub context: &'static [crate::Pred<'static>], + pub typ: &'static nash_region::Located>, +} + +const MAP_KEY: &nash_region::Located> = + &nash_region::Located::at_zero(crate::Type::Var("k")); +const MAP_VALUE: &nash_region::Located> = + &nash_region::Located::at_zero(crate::Type::Var("v")); +const MAP_BODY: &nash_region::Located> = + &builtins::named("list", &[&builtins::named("pair", &[MAP_KEY, MAP_VALUE])]); + +pub const ALIASES: &[PrimitiveAlias] = &[PrimitiveAlias { + name: "map", + kind: BINARY, + parameters: &["k", "v"], + context: &[ + crate::Pred::Implied { + trait_: ReprTrait::Storable.qualified(), + args: &[MAP_KEY], + }, + crate::Pred::Implied { + trait_: ReprTrait::Storable.qualified(), + args: &[MAP_VALUE], + }, + ], + typ: MAP_BODY, +}]; + const BOOL_CTORS: &[&crate::Ctor<'static>] = &[ &crate::Ctor { labels: None, @@ -203,10 +265,7 @@ const DATA_CTORS: &[&crate::Ctor<'static>] = &[ name: "Map", index: 1, arity: 1, - arguments: &[&builtins::named( - "list", - &[&builtins::named("pair", &[DATA, DATA])], - )], + arguments: &[native_map_type!(DATA, DATA)], }, &crate::Ctor { labels: None, diff --git a/crates/nash-ast/src/primitives/builtins.rs b/crates/nash-ast/src/primitives/builtins.rs index bd2bc5b1..9ca05f47 100644 --- a/crates/nash-ast/src/primitives/builtins.rs +++ b/crates/nash-ast/src/primitives/builtins.rs @@ -261,10 +261,7 @@ pub const BUILTINS: &[Builtin] = &[ Builtin { name: "mapData", free_vars: &["a", "b"], - typ: function!( - &named("list", &[&named("pair", &[A, B])]), - &named("Map", &[A, B]) - ), + typ: function!(native_map_type!(A, B), &named("Map", &[A, B])), variant: "MapData", context: &[ crate::Pred::Trait { @@ -298,10 +295,7 @@ pub const BUILTINS: &[Builtin] = &[ Builtin { name: "unMapData", free_vars: &["a", "b"], - typ: function!( - &named("Map", &[A, B]), - &named("list", &[&named("pair", &[A, B])]) - ), + typ: function!(&named("Map", &[A, B]), native_map_type!(A, B)), variant: "UnMapData", context: &[ crate::Pred::Trait { @@ -359,7 +353,7 @@ pub const BUILTINS: &[Builtin] = &[ "mkNilPairData", "MkNilPairData", [], - function!(UNIT, &named("list", &[&named("pair", &[DATA, DATA])])) + function!(UNIT, native_map_type!(DATA, DATA)) ), builtin!( "bls12_381_g1_add", diff --git a/crates/nash-can/src/defaults.rs b/crates/nash-can/src/defaults.rs index d9eb3ee9..5ab5e2c1 100644 --- a/crates/nash-can/src/defaults.rs +++ b/crates/nash-can/src/defaults.rs @@ -25,7 +25,8 @@ pub const MODULES: &[(&str, &[&str])] = &[ "Literal", &["FromInt", "FromString", "FromBytes", "FromBool", "FromUnit"], ), - ("Bool", &["Bool", "not", "and", "or", "xor"]), + ("Bool", &["Bool"]), + ("Logic", &["*"]), ("Unit", &["Unit"]), ("Option", &["Option", "type option"]), ("Ordering", &["Ordering", "type ordering"]), diff --git a/crates/nash-can/src/environment/foreign.rs b/crates/nash-can/src/environment/foreign.rs index 9f371474..47bd387a 100644 --- a/crates/nash-can/src/environment/foreign.rs +++ b/crates/nash-can/src/environment/foreign.rs @@ -83,6 +83,21 @@ pub fn create_initial_env<'a>( ); } + for alias in nash_ast::primitives::ALIASES { + env.types.insert( + alias.name, + Info::Specific( + builtin_home, + Type::Alias { + arity: alias.parameters.len(), + home: builtin_home, + parameters: alias.parameters, + typ: alias.typ, + }, + ), + ); + } + env.q_types.insert("Primitive", env.types.clone()); for name in ["Primitive", "Builtin"] { @@ -608,5 +623,14 @@ mod tests { other => panic!("Expected primitive {}, got {other:?}", primitive.name), } } + for alias in nash_ast::primitives::ALIASES { + match env.types.get(alias.name) { + Some(Info::Specific(module, Type::Alias { arity, .. })) => { + assert_eq!(*module, nash_ast::primitives::primitive_home()); + assert_eq!(*arity, alias.kind.arity()); + } + other => panic!("Expected primitive alias {}, got {other:?}", alias.name), + } + } } } diff --git a/crates/nash-can/src/kinds.rs b/crates/nash-can/src/kinds.rs index 397e1394..7c758bcd 100644 --- a/crates/nash-can/src/kinds.rs +++ b/crates/nash-can/src/kinds.rs @@ -302,6 +302,21 @@ impl<'a> KindEnv<'a> { .map(|t| (t.qualified(), &[&Kind::Type][..])) .collect(), }; + for alias in primitives::ALIASES { + env.types.insert( + QualifiedName { + home: primitives::primitive_home(), + name: alias.name, + }, + TypeInfo::Defined { + kind: alias.kind, + parameters: alias.parameters, + context: alias.context, + repr: None, + alias: Some(alias.typ), + }, + ); + } // Literal expressions and literal patterns emit these compiler-owned // predicates even before an imported implementation is available. for name in ["FromInt", "FromString", "FromBytes", "FromBool", "FromUnit"] { @@ -1987,7 +2002,16 @@ pub fn primitive_interface(bump: &Bump) -> crate::Interface<'_> { crate::Interface { home: primitives::primitive_home(), impls: &[], - aliases: &[], + aliases: bump.alloc_slice_fill_iter(primitives::ALIASES.iter().map(|alias| { + crate::interface::InterfaceAlias { + name: alias.name, + kind: alias.kind, + parameters: alias.parameters, + context: alias.context, + typ: alias.typ, + visibility: crate::interface::AliasVisibility::Public, + } + })), binops: &[], traits: bump.alloc_slice_fill_iter(ReprTrait::ALL.into_iter().map(|trait_| { InterfaceTrait { diff --git a/crates/nash-can/src/module.rs b/crates/nash-can/src/module.rs index aa302919..41c458b6 100644 --- a/crates/nash-can/src/module.rs +++ b/crates/nash-can/src/module.rs @@ -1564,6 +1564,7 @@ pub(crate) fn canonicalize_typed_value<'a>( let value = bump.alloc(Located::at( definition.region, SourceValue { + docs: None, name, arguments: args, body, diff --git a/crates/nash-can/src/snapshots/nash_can__module__tests__annotation_too_short.snap b/crates/nash-can/src/snapshots/nash_can__module__tests__annotation_too_short.snap index 36f1776b..908828ae 100644 --- a/crates/nash-can/src/snapshots/nash_can__module__tests__annotation_too_short.snap +++ b/crates/nash-can/src/snapshots/nash_can__module__tests__annotation_too_short.snap @@ -15,6 +15,6 @@ nash::names::not_found_type help: Similar names: Map + map Data Int - int diff --git a/crates/nash-can/src/snapshots/nash_can__module__tests__module_shell_reports_unresolved_qualified_named_types.snap b/crates/nash-can/src/snapshots/nash_can__module__tests__module_shell_reports_unresolved_qualified_named_types.snap index 00e140c8..397e2b21 100644 --- a/crates/nash-can/src/snapshots/nash_can__module__tests__module_shell_reports_unresolved_qualified_named_types.snap +++ b/crates/nash-can/src/snapshots/nash_can__module__tests__module_shell_reports_unresolved_qualified_named_types.snap @@ -15,5 +15,5 @@ nash::names::not_found_type string Primitive.Map + Primitive.map Primitive.value - Int diff --git a/crates/nash-can/src/snapshots/nash_can__module__tests__multiple_unbound_union_vars.snap b/crates/nash-can/src/snapshots/nash_can__module__tests__multiple_unbound_union_vars.snap index 68535822..5da34ab5 100644 --- a/crates/nash-can/src/snapshots/nash_can__module__tests__multiple_unbound_union_vars.snap +++ b/crates/nash-can/src/snapshots/nash_can__module__tests__multiple_unbound_union_vars.snap @@ -14,9 +14,9 @@ nash::names::not_found_type help: Similar names: Map + map Data Foo - Int nash::names::not_found_type diff --git a/crates/nash-can/src/snapshots/nash_can__pattern__tests__constr_binds_one_pair.snap b/crates/nash-can/src/snapshots/nash_can__pattern__tests__constr_binds_one_pair.snap index f20e2a1b..d3729674 100644 --- a/crates/nash-can/src/snapshots/nash_can__pattern__tests__constr_binds_one_pair.snap +++ b/crates/nash-can/src/snapshots/nash_can__pattern__tests__constr_binds_one_pair.snap @@ -182,7 +182,7 @@ description: Constr payload column: 0, }, }, - value: Named { + value: Alias { reference: QualifiedName { home: ModuleName { package: Some( @@ -193,10 +193,73 @@ description: Constr payload ), name: "Primitive", }, - name: "list", + name: "map", }, - args: [ - Located { + arguments: [ + AliasArgument { + name: "k", + typ: Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Named { + reference: QualifiedName { + home: ModuleName { + package: Some( + PackageName { + author: "nash", + project: "base", + }, + ), + name: "Primitive", + }, + name: "Data", + }, + args: [], + }, + }, + }, + AliasArgument { + name: "v", + typ: Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Named { + reference: QualifiedName { + home: ModuleName { + package: Some( + PackageName { + author: "nash", + project: "base", + }, + ), + name: "Primitive", + }, + name: "Data", + }, + args: [], + }, + }, + }, + ], + remaining: [], + target: Filled { + body: Located { region: Region { start: Position { line: 0, @@ -218,7 +281,7 @@ description: Constr payload ), name: "Primitive", }, - name: "pair", + name: "list", }, args: [ Located { @@ -243,11 +306,70 @@ description: Constr payload ), name: "Primitive", }, - name: "Data", + name: "pair", }, - args: [], + args: [ + Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Var( + "k", + ), + }, + Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Var( + "v", + ), + }, + ], }, }, + ], + }, + }, + typ: Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Named { + reference: QualifiedName { + home: ModuleName { + package: Some( + PackageName { + author: "nash", + project: "base", + }, + ), + name: "Primitive", + }, + name: "list", + }, + args: [ Located { region: Region { start: Position { @@ -270,15 +392,70 @@ description: Constr payload ), name: "Primitive", }, - name: "Data", + name: "pair", }, - args: [], + args: [ + Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Named { + reference: QualifiedName { + home: ModuleName { + package: Some( + PackageName { + author: "nash", + project: "base", + }, + ), + name: "Primitive", + }, + name: "Data", + }, + args: [], + }, + }, + Located { + region: Region { + start: Position { + line: 0, + column: 0, + }, + end: Position { + line: 0, + column: 0, + }, + }, + value: Named { + reference: QualifiedName { + home: ModuleName { + package: Some( + PackageName { + author: "nash", + project: "base", + }, + ), + name: "Primitive", + }, + name: "Data", + }, + args: [], + }, + }, + ], }, }, ], }, }, - ], + }, }, }, ], diff --git a/crates/nash-can/tests/kinds.rs b/crates/nash-can/tests/kinds.rs index e559d9a1..7c1c6438 100644 --- a/crates/nash-can/tests/kinds.rs +++ b/crates/nash-can/tests/kinds.rs @@ -891,3 +891,19 @@ fn impl_head_rejects_inconsistent_higher_kinded_arguments() { Error::KindMismatch { .. } ); } + +#[test] +fn map_requires_storable_key() { + assert_kind_error_snapshot!( + "type alias invalid = map (int -> int) int", + Error::RepresentationMismatch { .. } + ); +} + +#[test] +fn map_requires_storable_value() { + assert_kind_error_snapshot!( + "type alias invalid = map int (int -> int)", + Error::RepresentationMismatch { .. } + ); +} diff --git a/crates/nash-can/tests/snapshots/kinds__map_requires_storable_key.snap b/crates/nash-can/tests/snapshots/kinds__map_requires_storable_key.snap new file mode 100644 index 00000000..f41158bb --- /dev/null +++ b/crates/nash-can/tests/snapshots/kinds__map_requires_storable_key.snap @@ -0,0 +1,15 @@ +--- +source: crates/nash-can/tests/kinds.rs +description: "module Main exposing (..)\n\nimport Primitive exposing (..)\nimport Builtin exposing (..)\n\ntype alias invalid = map (int -> int) int\n" +info: diagnostic +--- +nash::names::representation_mismatch + + × This position requires `Storable` in the lowercase name of alias `invalid`: + ╭─[src/Main.nash:6:27] + 5 │ + 6 │ type alias invalid = map (int -> int) int + · ────────── + ╰──── + help: The type has `Term` representation, but `Storable` admits Big or Const types. + Change the type or the representation requirement. diff --git a/crates/nash-can/tests/snapshots/kinds__map_requires_storable_value.snap b/crates/nash-can/tests/snapshots/kinds__map_requires_storable_value.snap new file mode 100644 index 00000000..4547e82e --- /dev/null +++ b/crates/nash-can/tests/snapshots/kinds__map_requires_storable_value.snap @@ -0,0 +1,15 @@ +--- +source: crates/nash-can/tests/kinds.rs +description: "module Main exposing (..)\n\nimport Primitive exposing (..)\nimport Builtin exposing (..)\n\ntype alias invalid = map int (int -> int)\n" +info: diagnostic +--- +nash::names::representation_mismatch + + × This position requires `Storable` in the lowercase name of alias `invalid`: + ╭─[src/Main.nash:6:31] + 5 │ + 6 │ type alias invalid = map int (int -> int) + · ────────── + ╰──── + help: The type has `Term` representation, but `Storable` admits Big or Const types. + Change the type or the representation requirement. diff --git a/crates/nash-cli/Cargo.toml b/crates/nash-cli/Cargo.toml index 03b1e65d..ced409cc 100644 --- a/crates/nash-cli/Cargo.toml +++ b/crates/nash-cli/Cargo.toml @@ -16,6 +16,9 @@ name = "nash" path = "src/main.rs" [dependencies] +nash-region = { path = "../nash-region", version = "0.3.0" } +nash-docs = { path = "../nash-docs", version = "0.1.0" } +nash-fmt = { path = "../nash-fmt", version = "0.1.0" } nash-codegen = { path = "../nash-codegen", version = "0.4.2" } clap.workspace = true color-print.workspace = true @@ -31,7 +34,7 @@ nash-driver = { path = "../nash-driver", version = "0.11.0" } nash-language-server = { path = "../nash-language-server", version = "0.4.5" } octocrab.workspace = true tar.workspace = true -tokio = { workspace = true, features = ["rt-multi-thread", "macros", "io-std"] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros", "io-std", "io-util"] } tokio-util = { version = "0.7.18", features = ["compat"] } tower-lsp-server.workspace = true xz2.workspace = true diff --git a/crates/nash-cli/src/cmd/docs.rs b/crates/nash-cli/src/cmd/docs.rs new file mode 100644 index 00000000..77d83dc1 --- /dev/null +++ b/crates/nash-cli/src/cmd/docs.rs @@ -0,0 +1,127 @@ +use miette::{IntoDiagnostic, Result}; +use std::path::PathBuf; +use tokio::{ + io::AsyncWriteExt, + task::{JoinSet, spawn_blocking}, +}; + +#[derive(Clone, Copy, clap::ValueEnum)] +pub enum Format { + Html, + Markdown, +} + +#[derive(clap::Args)] +pub struct Args { + /// Project directory; defaults to the current directory. + #[arg(conflicts_with = "base")] + pub path: Option, + /// Document the compiler-bundled Base modules. + #[arg(long)] + pub base: bool, + /// Documentation output format. + #[arg(long, value_enum, default_value = "html")] + pub format: Format, + /// Directory for generated documentation. + #[arg(long, default_value = "docs")] + pub out: PathBuf, +} + +impl Args { + pub async fn exec(self, color: bool) -> Result<()> { + let path = self.path.unwrap_or_else(|| PathBuf::from(".")); + let input = if self.base { + nash_docs::project::Input::Base + } else { + nash_docs::project::Input::Project(&path) + }; + let docs = nash_docs::project::build(input).await.into_diagnostic()?; + let success = docs.compiler.is_success(); + // Render diagnostics off the executor just like documentation pages. + let (files, diagnostics) = spawn_blocking(move || { + let mut diagnostics = String::new(); + for module in docs.compiler.ordered_reports() { + let source = nash_report::Source::new(&module.source); + for report in &module.reports { + diagnostics.push_str(&format!( + "{:?}\n", + miette::Report::new(report.render(&source, &module.path, color)) + )); + } + } + for (uri, state) in &docs.compiler.modules { + if let nash_driver::ModuleResult::SourceUnavailable { message } = state { + diagnostics.push_str(&format!("Could not read {uri}: {message}\n")); + } + } + for warning in &docs.warnings { + let mut report = nash_report::Report::snippet( + "DOCUMENTATION WARNING", + nash_region::Region::zero(), + None, + nash_report::Doc::text(format!( + "{}.{}: {}", + warning.module, warning.name, warning.message + )), + nash_report::Doc::Empty, + ) + .warning(); + report.primary_label = None; + report.context = None; + diagnostics.push_str(&format!( + "{:?}\n", + miette::Report::new(report.render( + &nash_report::Source::new(""), + &warning.module, + color + )) + )); + } + let format = match self.format { + Format::Html => nash_docs::Format::Html, + Format::Markdown => nash_docs::Format::Markdown, + }; + ( + if success { + nash_docs::render(&docs.modules, format) + } else { + Default::default() + }, + diagnostics, + ) + }) + .await + .into_diagnostic()?; + let mut stderr = tokio::io::stderr(); + stderr + .write_all(diagnostics.as_bytes()) + .await + .into_diagnostic()?; + stderr.flush().await.into_diagnostic()?; + if !success { + return Err(miette::miette!( + "Documentation generation stopped because compilation failed" + )); + } + let mut writes = JoinSet::new(); + for (relative, contents) in files { + let path = self.out.join(relative); + writes.spawn(async move { + if let Some(parent) = path.parent() { + tokio::fs::create_dir_all(parent).await?; + } + tokio::fs::write(path, contents).await + }); + } + let mut result = Ok(()); + while let Some(write) = writes.join_next().await { + if let Err(error) = write + .into_diagnostic() + .and_then(|write| write.into_diagnostic()) + { + result = Err(error); + } + } + result + } +} diff --git a/crates/nash-cli/src/cmd/format.rs b/crates/nash-cli/src/cmd/format.rs new file mode 100644 index 00000000..f7bcc2e1 --- /dev/null +++ b/crates/nash-cli/src/cmd/format.rs @@ -0,0 +1,129 @@ +use miette::{IntoDiagnostic, Result}; +use std::collections::HashSet; +use std::path::PathBuf; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::task::{JoinSet, spawn_blocking}; + +#[derive(clap::Args)] +pub struct Args { + /// Nash files or directories to format recursively. + #[arg(default_value = ".")] + pub paths: Vec, + /// Show formatting differences without changing files. + #[arg(long)] + pub check: bool, + /// Format one module from stdin to stdout. + #[arg(long, conflicts_with_all = ["paths", "check"])] + pub stdin: bool, +} + +impl Args { + pub async fn exec(self, color: bool) -> Result<()> { + if self.stdin { + let mut source = String::new(); + tokio::io::stdin() + .read_to_string(&mut source) + .await + .into_diagnostic()?; + let formatted = spawn_blocking(move || format_source(&source, "", color)) + .await + .into_diagnostic()??; + let mut stdout = tokio::io::stdout(); + stdout + .write_all(formatted.as_bytes()) + .await + .into_diagnostic()?; + stdout.flush().await.into_diagnostic()?; + return Ok(()); + } + let files = collect(self.paths).await?; + let root = std::env::current_dir().into_diagnostic()?; + let links = supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr); + let mut tasks = JoinSet::new(); + for path in files { + let name = crate::reporting::source_name(&root, links, &path.to_string_lossy()); + tasks.spawn(format_file(path, name, self.check, color)); + } + let mut failed = false; + let mut stderr = tokio::io::stderr(); + let mut output = Ok(()); + while let Some(result) = tasks.join_next().await { + if let Err(report) = result.into_diagnostic().and_then(|result| result) { + if output.is_ok() { + output = stderr + .write_all(format!("{report:?}\n").as_bytes()) + .await + .into_diagnostic(); + } + failed = true; + } + } + output?; + stderr.flush().await.into_diagnostic()?; + if failed { + std::process::exit(1); + } + Ok(()) + } +} + +fn format_source(source: &str, name: &str, color: bool) -> Result { + nash_fmt::format(source).map_err(|report| { + miette::Report::new(report.render(&nash_report::Source::new(source), name, color)) + }) +} + +async fn format_file(path: PathBuf, name: String, check: bool, color: bool) -> Result<()> { + let source = tokio::fs::read_to_string(&path).await.into_diagnostic()?; + let formatted = spawn_blocking(move || { + let formatted = format_source(&source, &name, color)?; + if check { + if let Some(report) = nash_report::format::difference(&name, &source, &formatted) { + return Err(miette::Report::new(report.render( + &nash_report::Source::new(&source), + &name, + color, + ))); + } + Ok(None) + } else { + Ok((source != formatted).then_some(formatted)) + } + }) + .await + .into_diagnostic()??; + if let Some(formatted) = formatted { + tokio::fs::write(path, formatted).await.into_diagnostic()?; + } + Ok(()) +} + +async fn collect(paths: Vec) -> Result> { + let mut pending = Vec::new(); + for path in paths { + pending.push(tokio::fs::canonicalize(path).await.into_diagnostic()?); + } + let mut files = HashSet::new(); + while let Some(path) = pending.pop() { + let metadata = tokio::fs::symlink_metadata(&path).await.into_diagnostic()?; + if metadata.is_file() { + if path + .extension() + .is_some_and(|extension| extension == "nash") + { + files.insert(tokio::fs::canonicalize(&path).await.into_diagnostic()?); + } + } else if metadata.is_dir() { + let mut entries = tokio::fs::read_dir(&path).await.into_diagnostic()?; + while let Some(entry) = entries.next_entry().await.into_diagnostic()? { + if !matches!( + entry.file_name().to_str(), + Some(".git" | ".jj" | "target" | "build" | "node_modules") + ) { + pending.push(entry.path()); + } + } + } + } + Ok(files) +} diff --git a/crates/nash-cli/src/cmd/mod.rs b/crates/nash-cli/src/cmd/mod.rs index 6b26e196..8f44be5d 100644 --- a/crates/nash-cli/src/cmd/mod.rs +++ b/crates/nash-cli/src/cmd/mod.rs @@ -1,5 +1,7 @@ pub mod build; pub mod check; +pub mod docs; +pub mod format; pub mod lsp; pub mod test; @@ -14,6 +16,11 @@ pub enum Cmd { /// Compile and execute module tests and properties #[clap(visible_alias = "t")] Test(test::Args), + /// Format Nash source files + #[clap(visible_alias = "fmt")] + Format(format::Args), + /// Generate public API documentation + Docs(docs::Args), /// Start the Nash language server over stdio Lsp(lsp::Args), } @@ -21,9 +28,11 @@ pub enum Cmd { impl Cmd { pub async fn exec(self, color: bool) -> miette::Result<()> { match self { + Cmd::Docs(args) => args.exec(color).await, Cmd::Check(args) => args.exec(color).await, Cmd::Build(args) => args.exec(color).await, Cmd::Test(args) => args.exec(color).await, + Cmd::Format(args) => args.exec(color).await, Cmd::Lsp(args) => lsp::exec(args).await, } } diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_record_and_labeled_constructor_keep_distinct_layouts.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_record_and_labeled_constructor_keep_distinct_layouts.snap index b5f0afe7..a2b1c390 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_record_and_labeled_constructor_keep_distinct_layouts.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_record_and_labeled_constructor_keep_distinct_layouts.snap @@ -3,43 +3,43 @@ source: crates/nash-codegen/src/build/tests.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\ntype alias Record = { owner : Bytes, count : Int }\ntype Datum = Datum { owner : Bytes, count : Int }\nrecord : Record\nrecord = { owner = #\"aa\", count = 1 }\ndatum : Datum\ndatum = Datum { owner = #\"bb\", count = 2 }\nmain = neq record.count datum.count\n" --- --- core -let fromBool#17 : bool -> bool = \value#22 : bool -> value#22 in -let neq#2 : 'erased -> 'erased -> bool = \a#15 : 'erased b#16 : 'erased -> case@Bool equalsData a#15 b#16 of - True -> fromBool#17 false - False -> fromBool#17 true in +let not#17 : 'erased -> bool = \value#22 : 'erased -> case@Bool (\identity#23 : 'erased -> identity#23) value#22 of + True -> false + False -> true in +let neq#2 : 'erased -> 'erased -> bool = \a#15 : 'erased b#16 : 'erased -> not#17 (equalsData a#15 b#16) in let fromBytes#18 : bytes -> Bytes = bData in let fromInt#19 : int -> Int = iData in let record#3 : { _0 : Bytes, _1 : Int } = listData (mkCons (fromBytes#18 (con bytestring #aa)) (mkCons (fromInt#19 1) (con (list data) []))) in let datum#8 : Main.Datum = (\field#20 : Bytes field#21 : Int -> constrData 0 (mkCons field#20 (mkCons field#21 (con (list data) [])))) (fromBytes#18 (con bytestring #bb)) (fromInt#19 2) in -let projection#23 : list Data = unListData record#3 in -case@List projection#23 of +let projection#24 : list Data = unListData record#3 in +case@List projection#24 of Cons head#4 tail#5 -> case@List tail#5 of - Cons head#6 tail#7 -> let projection#24 : pair int (list Data) = unConstrData datum#8 in - case@Pair projection#24 of + Cons head#6 tail#7 -> let projection#25 : pair int (list Data) = unConstrData datum#8 in + case@Pair projection#25 of Pair tag#9 fields#10 -> case@List fields#10 of Cons head#11 tail#12 -> case@List tail#12 of Cons head#13 tail#14 -> let main#1 : bool = neq#2 head#6 head#13 in main#1 --- uplc (program 1.1.0 - [(lam fromBool_17 + [(lam not_17 [(lam neq_2 [(lam fromBytes_18 [(lam fromInt_19 [(lam record_3 [(lam datum_8 - [(lam projection_23 + [(lam projection_24 (case - projection_23 + projection_24 (lam head_4 (lam tail_5 (case tail_5 (lam head_6 (lam tail_7 - [(lam projection_24 + [(lam projection_25 (case - projection_24 + projection_25 (lam tag_9 (lam fields_10 (case @@ -67,16 +67,12 @@ case@List projection#23 of [[(force (builtin mkCons)) [fromInt_19 (con integer 1)]] (con (list data) [])]]]]) (builtin iData)]) (builtin bData)]) - (lam a_15 - (lam b_16 - (case - [[(builtin equalsData) a_15] b_16] - [fromBool_17 (con bool True)] - [fromBool_17 (con bool False)])))]) - (lam value_22 value_22)]) + (lam a_15 (lam b_16 [not_17 [[(builtin equalsData) a_15] b_16]]))]) + (lam value_22 + (case [(lam identity_23 identity_23) value_22] (con bool True) (con bool False)))]) --- result (con bool True) --- logs [] --- budget -cpu: 3195579, memory: 11185 +cpu: 3243579, memory: 11485 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_binds_whole_and_captures_outer.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_binds_whole_and_captures_outer.snap new file mode 100644 index 00000000..7b6e1b85 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_binds_whole_and_captures_outer.snap @@ -0,0 +1,130 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nread : Choice -> int\nread value =\n case value of\n Stop -> 0\n Zero -> 0\n One a -> unIData a\n Two a b -> addInteger (unIData a) (unIData b)\nchoose : int -> Choice -> int\nchoose outer subject =\n case trace \"subject\" subject of\n Stop -> 1\n whole -> trace \"fallback\" (addInteger outer (read whole))\nmain = (choose 10 Stop, choose 10 Zero, choose 10 (One 20), choose 10 (Two 30 40))\n" +--- +--- core +let message#42 : string = "subject" in +let message#43 : string = "fallback" in +let fromInt#3 : int -> int = \value#25 : int -> value#25 in +let fromString#10 : string -> string = \value#26 : string -> value#26 in +let read#12 : Main.Choice -> int = \value#27 : Main.Choice -> let match#31 : Main.Choice = value#27 in +let projection#40 : pair int (list Data) = unConstrData match#31 in +case@Pair projection#40 of + Pair tag#35 fields#36 -> case@Tag tag#35 of + 0 -> fromInt#3 0 + 1 -> fromInt#3 0 + 2 -> case@List fields#36 of + Cons field#32 fieldTail#37 -> let a#28 : Int = field#32 in + unIData a#28 + 3 -> case@List fields#36 of + Cons field#33 fieldTail#38 -> case@List fieldTail#38 of + Cons field#34 fieldTail#39 -> let a#29 : Int = field#33 in + let b#30 : Int = field#34 in + addInteger (unIData a#29) (unIData b#30) in +let choose#2 : int -> Main.Choice -> int = \outer#8 : int subject#9 : Main.Choice -> let match#13 : Main.Choice = trace (fromString#10 message#42) in subject#9 in +let leaf#19 : 'erased = \whole#11 : Main.Choice -> trace (fromString#10 message#43) in addInteger outer#8 (read#12 whole#11) in +let projection#41 : pair int (list Data) = unConstrData match#13 in +case@Pair projection#41 of + Pair tag#23 fields#24 -> case@Tag tag#23 of + 0 -> fromInt#3 1 + 1 -> let whole#11 : Main.Choice = match#13 in + leaf#19 whole#11 + 2 -> let whole#11 : Main.Choice = match#13 in + leaf#19 whole#11 + 3 -> let whole#11 : Main.Choice = match#13 in + leaf#19 whole#11 in +let fromInt#5 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (fromInt#3 10) (constrData 0 (con (list data) []))) (choose#2 (fromInt#3 10) (constrData 1 (con (list data) []))) (choose#2 (fromInt#3 10) ((\field#4 : Int -> constrData 2 (mkCons field#4 (con (list data) []))) (fromInt#5 20))) (choose#2 (fromInt#3 10) ((\field#6 : Int field#7 : Int -> constrData 3 (mkCons field#6 (mkCons field#7 (con (list data) [])))) (fromInt#5 30) (fromInt#5 40))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_42 + [(lam message_43 + [(lam fromInt_3 + [(lam fromString_10 + [(lam read_12 + [(lam choose_2 + [(lam fromInt_5 + [(lam main_1 main_1) + (constr 0 + [[choose_2 [fromInt_3 (con integer 10)]] + [[(builtin constrData) (con integer 0)] (con (list data) [])]] + [[choose_2 [fromInt_3 (con integer 10)]] + [[(builtin constrData) (con integer 1)] (con (list data) [])]] + [[choose_2 [fromInt_3 (con integer 10)]] + [(lam field_4 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_4] (con (list data) [])]]) + [fromInt_5 (con integer 20)]]] + [[choose_2 [fromInt_3 (con integer 10)]] + [[(lam field_6 + (lam field_7 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_6] + [[(force (builtin mkCons)) field_7] (con (list data) [])]]])) + [fromInt_5 (con integer 30)]] + [fromInt_5 (con integer 40)]]])]) + (builtin iData)]) + (lam outer_8 + (lam subject_9 + [(lam match_13 + [(lam leaf_19 + [(lam projection_41 + (case + projection_41 + (lam tag_23 + (lam fields_24 + (case + tag_23 + [fromInt_3 (con integer 1)] + [(lam whole_11 [leaf_19 whole_11]) match_13] + [(lam whole_11 [leaf_19 whole_11]) match_13] + [(lam whole_11 [leaf_19 whole_11]) match_13]))))) + [(builtin unConstrData) match_13]]) + (lam whole_11 + (force + [[(force (builtin trace)) [fromString_10 message_43]] + (delay [[(builtin addInteger) outer_8] [read_12 whole_11]])]))]) + (force [[(force (builtin trace)) [fromString_10 message_42]] (delay subject_9)])]))]) + (lam value_27 + [(lam match_31 + [(lam projection_40 + (case + projection_40 + (lam tag_35 + (lam fields_36 + (case + tag_35 + [fromInt_3 (con integer 0)] + [fromInt_3 (con integer 0)] + (case + fields_36 + (lam field_32 (lam fieldTail_37 [(lam a_28 [(builtin unIData) a_28]) field_32])) + (error)) + (case + fields_36 + (lam field_33 + (lam fieldTail_38 + (case + fieldTail_38 + (lam field_34 + (lam fieldTail_39 + [(lam a_29 + [(lam b_30 + [[(builtin addInteger) [(builtin unIData) a_29]] [(builtin unIData) b_30]]) + field_34]) + field_33])) + (error)))) + (error))))))) + [(builtin unConstrData) match_31]]) + value_27])]) + (lam value_26 value_26)]) + (lam value_25 value_25)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 10) (con integer 30) (con integer 80)) +--- logs +["subject", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 7279353, memory: 37672 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_calls_user_continuation_only_when_selected.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_calls_user_continuation_only_when_selected.snap new file mode 100644 index 00000000..611b3286 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_calls_user_continuation_only_when_selected.snap @@ -0,0 +1,98 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> (int -> int) -> int\nchoose subject continue =\n case trace \"subject\" subject of\n Stop -> 0\n _ -> trace \"fallback\" (continue 9)\nfinish : int -> int\nfinish n = trace \"continue\" (addInteger n 100)\nmain = (choose Stop (\\_ -> trace \"wrong\" fail), choose Zero finish, choose (One 2) finish, choose (Two 3 4) finish)\n" +--- +--- core +let message#30 : string = "subject" in +let message#31 : string = "fallback" in +let message#32 : string = "continue" in +let message#33 : string = "wrong" in +let fromString#4 : string -> string = \value#26 : string -> value#26 in +let fromInt#13 : int -> int = \value#28 : int -> value#28 in +let choose#2 : Main.Choice -> (int -> int) -> int = \subject#11 : Main.Choice (continue#12 : int -> int) -> let match#14 : Main.Choice = trace (fromString#4 message#30) in subject#11 in +let leaf#20 : 'erased = delay (trace (fromString#4 message#31) in continue#12 (fromInt#13 9)) in +let projection#29 : pair int (list Data) = unConstrData match#14 in +case@Pair projection#29 of + Pair tag#24 fields#25 -> case@Tag tag#24 of + 0 -> fromInt#13 0 + 1 -> force leaf#20 + 2 -> force leaf#20 + 3 -> force leaf#20 in +let finish#6 : int -> int = \n#27 : int -> trace (fromString#4 message#32) in addInteger n#27 (fromInt#13 100) in +let fromInt#8 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constrData 0 (con (list data) [])) (\arg#3 : int -> let match#5 : int = arg#3 in +trace (fromString#4 message#33) in error)) (choose#2 (constrData 1 (con (list data) [])) finish#6) (choose#2 ((\field#7 : Int -> constrData 2 (mkCons field#7 (con (list data) []))) (fromInt#8 2)) finish#6) (choose#2 ((\field#9 : Int field#10 : Int -> constrData 3 (mkCons field#9 (mkCons field#10 (con (list data) [])))) (fromInt#8 3) (fromInt#8 4)) finish#6) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_30 + [(lam message_31 + [(lam message_32 + [(lam message_33 + [(lam fromString_4 + [(lam fromInt_13 + [(lam choose_2 + [(lam finish_6 + [(lam fromInt_8 + [(lam main_1 main_1) + (constr 0 + [[choose_2 [[(builtin constrData) (con integer 0)] (con (list data) [])]] + (lam arg_3 + [(lam match_5 + (force [[(force (builtin trace)) [fromString_4 message_33]] (delay (error))])) + arg_3])] + [[choose_2 [[(builtin constrData) (con integer 1)] (con (list data) [])]] + finish_6] + [[choose_2 + [(lam field_7 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_7] (con (list data) [])]]) + [fromInt_8 (con integer 2)]]] + finish_6] + [[choose_2 + [[(lam field_9 + (lam field_10 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_9] + [[(force (builtin mkCons)) field_10] (con (list data) [])]]])) + [fromInt_8 (con integer 3)]] + [fromInt_8 (con integer 4)]]] + finish_6])]) + (builtin iData)]) + (lam n_27 + (force + [[(force (builtin trace)) [fromString_4 message_32]] + (delay [[(builtin addInteger) n_27] [fromInt_13 (con integer 100)]])]))]) + (lam subject_11 + (lam continue_12 + [(lam match_14 + [(lam leaf_20 + [(lam projection_29 + (case + projection_29 + (lam tag_24 + (lam fields_25 + (case + tag_24 + [fromInt_13 (con integer 0)] + (force leaf_20) + (force leaf_20) + (force leaf_20)))))) + [(builtin unConstrData) match_14]]) + (delay + (force + [[(force (builtin trace)) [fromString_4 message_31]] + (delay [continue_12 [fromInt_13 (con integer 9)]])]))]) + (force [[(force (builtin trace)) [fromString_4 message_30]] (delay subject_11)])]))]) + (lam value_28 value_28)]) + (lam value_26 value_26)]) + (con string "wrong")]) + (con string "continue")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 0) (con integer 109) (con integer 109) (con integer 109)) +--- logs +["subject", "subject", "fallback", "continue", "subject", "fallback", "continue", "subject", "fallback", "continue"] +--- budget +cpu: 6484643, memory: 32974 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_does_not_extract_missing_fields.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_does_not_extract_missing_fields.snap new file mode 100644 index 00000000..4f7b03bd --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_does_not_extract_missing_fields.snap @@ -0,0 +1,56 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case subject of\n Stop -> 1\n _ -> trace \"fallback\" 9\nmain = (choose (coerce (constrData 1 [])), choose (coerce (constrData 2 [])))\n" +--- +--- core +let message#23 : string = "fallback" in +let fromInt#4 : int -> int = \value#20 : int -> value#20 in +let fromString#7 : string -> string = \value#21 : string -> value#21 in +let choose#2 : Main.Choice -> int = \subject#6 : Main.Choice -> let match#8 : Main.Choice = subject#6 in +let leaf#14 : 'erased = delay (trace (fromString#7 message#23) in fromInt#4 9) in +let projection#22 : pair int (list Data) = unConstrData match#8 in +case@Pair projection#22 of + Pair tag#18 fields#19 -> case@Tag tag#18 of + 0 -> fromInt#4 1 + 1 -> force leaf#14 + 2 -> force leaf#14 in +let main#1 : (int, int) = constr 0 (choose#2 ((\coerce#3 : 'erased -> coerce#3) (constrData (fromInt#4 1) (con (list data) [])))) (choose#2 ((\coerce#5 : 'erased -> coerce#5) (constrData (fromInt#4 2) (con (list data) [])))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_23 + [(lam fromInt_4 + [(lam fromString_7 + [(lam choose_2 + [(lam main_1 main_1) + (constr 0 + [choose_2 + [(lam coerce_3 coerce_3) + [[(builtin constrData) [fromInt_4 (con integer 1)]] (con (list data) [])]]] + [choose_2 + [(lam coerce_5 coerce_5) + [[(builtin constrData) [fromInt_4 (con integer 2)]] (con (list data) [])]]])]) + (lam subject_6 + [(lam match_8 + [(lam leaf_14 + [(lam projection_22 + (case + projection_22 + (lam tag_18 + (lam fields_19 + (case tag_18 [fromInt_4 (con integer 1)] (force leaf_14) (force leaf_14)))))) + [(builtin unConstrData) match_8]]) + (delay + (force + [[(force (builtin trace)) [fromString_7 message_23]] + (delay [fromInt_4 (con integer 9)])]))]) + subject_6])]) + (lam value_21 value_21)]) + (lam value_20 value_20)]) + (con string "fallback")]) +--- result +(constr 0 (con integer 9) (con integer 9)) +--- logs +["fallback", "fallback"] +--- budget +cpu: 1940574, memory: 11092 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_inline_function_result_consumes_fields.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_inline_function_result_consumes_fields.snap new file mode 100644 index 00000000..03a5ec74 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_inline_function_result_consumes_fields.snap @@ -0,0 +1,65 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Two Int Int\nchoose : Choice -> (int -> int)\nchoose subject =\n case trace \"subject\" subject of\n Stop -> \\n -> n\n _ -> trace \"fallback\" (\\n -> addInteger n 1)\nmain = (choose Stop 10, choose (Two 3 4) 20)\n" +--- +--- core +let message#19 : string = "subject" in +let message#20 : string = "fallback" in +let fromInt#3 : int -> int = \value#16 : int -> value#16 in +let fromString#8 : string -> string = \value#17 : string -> value#17 in +let choose#2 : Main.Choice -> int -> int = \subject#7 : Main.Choice -> let match#11 : Main.Choice = trace (fromString#8 message#19) in subject#7 in +let projection#18 : pair int (list Data) = unConstrData match#11 in +case@Pair projection#18 of + Pair tag#14 fields#15 -> case@Tag tag#14 of + 0 -> \n#9 : int -> n#9 + 1 -> trace (fromString#8 message#20) in \n#10 : int -> addInteger n#10 (fromInt#3 1) in +let fromInt#6 : int -> Int = iData in +let main#1 : (int, int) = constr 0 (choose#2 (constrData 0 (con (list data) [])) (fromInt#3 10)) (choose#2 ((\field#4 : Int field#5 : Int -> constrData 1 (mkCons field#4 (mkCons field#5 (con (list data) [])))) (fromInt#6 3) (fromInt#6 4)) (fromInt#3 20)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_19 + [(lam message_20 + [(lam fromInt_3 + [(lam fromString_8 + [(lam choose_2 + [(lam fromInt_6 + [(lam main_1 main_1) + (constr 0 + [[choose_2 [[(builtin constrData) (con integer 0)] (con (list data) [])]] + [fromInt_3 (con integer 10)]] + [[choose_2 + [[(lam field_4 + (lam field_5 + [[(builtin constrData) (con integer 1)] + [[(force (builtin mkCons)) field_4] + [[(force (builtin mkCons)) field_5] (con (list data) [])]]])) + [fromInt_6 (con integer 3)]] + [fromInt_6 (con integer 4)]]] + [fromInt_3 (con integer 20)]])]) + (builtin iData)]) + (lam subject_7 + [(lam match_11 + [(lam projection_18 + (case + projection_18 + (lam tag_14 + (lam fields_15 + (case + tag_14 + (lam n_9 n_9) + (force + [[(force (builtin trace)) [fromString_8 message_20]] + (delay (lam n_10 [[(builtin addInteger) n_10] [fromInt_3 (con integer 1)]]))])))))) + [(builtin unConstrData) match_11]]) + (force [[(force (builtin trace)) [fromString_8 message_19]] (delay subject_7)])])]) + (lam value_17 value_17)]) + (lam value_16 value_16)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 10) (con integer 21)) +--- logs +["subject", "subject", "fallback"] +--- budget +cpu: 2708602, memory: 13954 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_mixed_arities_trace_order.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_mixed_arities_trace_order.snap new file mode 100644 index 00000000..d4815d67 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_mixed_arities_trace_order.snap @@ -0,0 +1,82 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" 9\nmain = (choose Stop, choose Zero, choose (One 2), choose (Two 3 4))\n" +--- +--- core +let message#25 : string = "subject" in +let message#26 : string = "fallback" in +let message#27 : string = "explicit" in +let fromString#8 : string -> string = \value#22 : string -> value#22 in +let fromInt#9 : int -> int = \value#23 : int -> value#23 in +let choose#2 : Main.Choice -> int = \subject#7 : Main.Choice -> let match#10 : Main.Choice = trace (fromString#8 message#25) in subject#7 in +let leaf#16 : 'erased = delay (trace (fromString#8 message#26) in fromInt#9 9) in +let projection#24 : pair int (list Data) = unConstrData match#10 in +case@Pair projection#24 of + Pair tag#20 fields#21 -> case@Tag tag#20 of + 0 -> trace (fromString#8 message#27) in fromInt#9 1 + 1 -> force leaf#16 + 2 -> force leaf#16 + 3 -> force leaf#16 in +let fromInt#4 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constrData 0 (con (list data) []))) (choose#2 (constrData 1 (con (list data) []))) (choose#2 ((\field#3 : Int -> constrData 2 (mkCons field#3 (con (list data) []))) (fromInt#4 2))) (choose#2 ((\field#5 : Int field#6 : Int -> constrData 3 (mkCons field#5 (mkCons field#6 (con (list data) [])))) (fromInt#4 3) (fromInt#4 4))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_25 + [(lam message_26 + [(lam message_27 + [(lam fromString_8 + [(lam fromInt_9 + [(lam choose_2 + [(lam fromInt_4 + [(lam main_1 main_1) + (constr 0 + [choose_2 [[(builtin constrData) (con integer 0)] (con (list data) [])]] + [choose_2 [[(builtin constrData) (con integer 1)] (con (list data) [])]] + [choose_2 + [(lam field_3 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_3] (con (list data) [])]]) + [fromInt_4 (con integer 2)]]] + [choose_2 + [[(lam field_5 + (lam field_6 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_5] + [[(force (builtin mkCons)) field_6] (con (list data) [])]]])) + [fromInt_4 (con integer 3)]] + [fromInt_4 (con integer 4)]]])]) + (builtin iData)]) + (lam subject_7 + [(lam match_10 + [(lam leaf_16 + [(lam projection_24 + (case + projection_24 + (lam tag_20 + (lam fields_21 + (case + tag_20 + (force + [[(force (builtin trace)) [fromString_8 message_27]] + (delay [fromInt_9 (con integer 1)])]) + (force leaf_16) + (force leaf_16) + (force leaf_16)))))) + [(builtin unConstrData) match_10]]) + (delay + (force + [[(force (builtin trace)) [fromString_8 message_26]] + (delay [fromInt_9 (con integer 9)])]))]) + (force [[(force (builtin trace)) [fromString_8 message_25]] (delay subject_7)])])]) + (lam value_23 value_23)]) + (lam value_22 value_22)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 9) (con integer 9) (con integer 9)) +--- logs +["subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 4974023, memory: 26104 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_multiple_bindings_return_function.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_multiple_bindings_return_function.snap new file mode 100644 index 00000000..af6bb8ad --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_multiple_bindings_return_function.snap @@ -0,0 +1,109 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : (Choice, int, int) -> (int -> int)\nchoose subject =\n case trace \"subject\" subject of\n (Stop, _, _) -> \\n -> n\n (_, z, a) -> trace \"shared\" (\\n -> subtractInteger (addInteger z n) a)\nmain = (choose (Stop, 90, 80) 1, choose (Zero, 21, 3) 1, choose (One 2, 31, 4) 1, choose (Two 3 4, 41, 5) 1)\n" +--- +--- core +let message#35 : string = "subject" in +let message#36 : string = "shared" in +let fromString#9 : string -> string = \value#33 : string -> value#33 in +let choose#2 : (Main.Choice, int, int) -> int -> int = \subject#8 : (Main.Choice, int, int) -> let match#14 : (Main.Choice, int, int) = trace (fromString#9 message#35) in subject#8 in +let leaf#23 : 'erased = \a#12 : int z#11 : int -> trace (fromString#9 message#36) in \n#13 : int -> subtractInteger (addInteger z#11 n#13) a#12 in +case@Tag match#14 of + 0 field#24 field#25 field#26 -> let projection#34 : pair int (list Data) = unConstrData field#24 in + case@Pair projection#34 of + Pair tag#30 fields#31 -> case@Tag tag#30 of + 0 -> \n#10 : int -> n#10 + 1 -> let z#11 : int = field#25 in + let a#12 : int = field#26 in + leaf#23 a#12 z#11 + 2 -> let z#11 : int = field#25 in + let a#12 : int = field#26 in + leaf#23 a#12 z#11 + 3 -> let z#11 : int = field#25 in + let a#12 : int = field#26 in + leaf#23 a#12 z#11 in +let fromInt#3 : int -> int = \value#32 : int -> value#32 in +let fromInt#5 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0 (constrData 0 (con (list data) [])) (fromInt#3 90) (fromInt#3 80)) (fromInt#3 1)) (choose#2 (constr 0 (constrData 1 (con (list data) [])) (fromInt#3 21) (fromInt#3 3)) (fromInt#3 1)) (choose#2 (constr 0 ((\field#4 : Int -> constrData 2 (mkCons field#4 (con (list data) []))) (fromInt#5 2)) (fromInt#3 31) (fromInt#3 4)) (fromInt#3 1)) (choose#2 (constr 0 ((\field#6 : Int field#7 : Int -> constrData 3 (mkCons field#6 (mkCons field#7 (con (list data) [])))) (fromInt#5 3) (fromInt#5 4)) (fromInt#3 41) (fromInt#3 5)) (fromInt#3 1)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_35 + [(lam message_36 + [(lam fromString_9 + [(lam choose_2 + [(lam fromInt_3 + [(lam fromInt_5 + [(lam main_1 main_1) + (constr 0 + [[choose_2 + (constr 0 + [[(builtin constrData) (con integer 0)] (con (list data) [])] + [fromInt_3 (con integer 90)] + [fromInt_3 (con integer 80)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 + [[(builtin constrData) (con integer 1)] (con (list data) [])] + [fromInt_3 (con integer 21)] + [fromInt_3 (con integer 3)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 + [(lam field_4 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_4] (con (list data) [])]]) + [fromInt_5 (con integer 2)]] + [fromInt_3 (con integer 31)] + [fromInt_3 (con integer 4)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 + [[(lam field_6 + (lam field_7 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_6] + [[(force (builtin mkCons)) field_7] (con (list data) [])]]])) + [fromInt_5 (con integer 3)]] + [fromInt_5 (con integer 4)]] + [fromInt_3 (con integer 41)] + [fromInt_3 (con integer 5)])] + [fromInt_3 (con integer 1)]])]) + (builtin iData)]) + (lam value_32 value_32)]) + (lam subject_8 + [(lam match_14 + [(lam leaf_23 + (case + match_14 + (lam field_24 + (lam field_25 + (lam field_26 + [(lam projection_34 + (case + projection_34 + (lam tag_30 + (lam fields_31 + (case + tag_30 + (lam n_10 n_10) + [(lam z_11 [(lam a_12 [[leaf_23 a_12] z_11]) field_26]) field_25] + [(lam z_11 [(lam a_12 [[leaf_23 a_12] z_11]) field_26]) field_25] + [(lam z_11 [(lam a_12 [[leaf_23 a_12] z_11]) field_26]) field_25]))))) + [(builtin unConstrData) field_24]]))))) + (lam a_12 + (lam z_11 + (force + [[(force (builtin trace)) [fromString_9 message_36]] + (delay + (lam n_13 [[(builtin subtractInteger) [[(builtin addInteger) z_11] n_13]] a_12]))])))]) + (force [[(force (builtin trace)) [fromString_9 message_35]] (delay subject_8)])])]) + (lam value_33 value_33)]) + (con string "shared")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 19) (con integer 28) (con integer 37)) +--- logs +["subject", "subject", "shared", "subject", "shared", "subject", "shared"] +--- budget +cpu: 7265773, memory: 36984 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_only_does_not_inspect_unknown_tag.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_only_does_not_inspect_unknown_tag.snap new file mode 100644 index 00000000..8a7d15bf --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_only_does_not_inspect_unknown_tag.snap @@ -0,0 +1,40 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n _ -> trace \"fallback\" 9\nmain = choose (coerce (constrData 59 []))\n" +--- +--- core +let message#10 : string = "subject" in +let message#11 : string = "fallback" in +let fromInt#4 : int -> int = \value#8 : int -> value#8 in +let fromString#6 : string -> string = \value#9 : string -> value#9 in +let choose#2 : Main.Choice -> int = \subject#5 : Main.Choice -> let match#7 : Main.Choice = trace (fromString#6 message#10) in subject#5 in +trace (fromString#6 message#11) in fromInt#4 9 in +let main#1 : int = choose#2 ((\coerce#3 : 'erased -> coerce#3) (constrData (fromInt#4 59) (con (list data) []))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_10 + [(lam message_11 + [(lam fromInt_4 + [(lam fromString_6 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 + [(lam coerce_3 coerce_3) + [[(builtin constrData) [fromInt_4 (con integer 59)]] (con (list data) [])]]]]) + (lam subject_5 + [(lam match_7 + (force + [[(force (builtin trace)) [fromString_6 message_11]] + (delay [fromInt_4 (con integer 9)])])) + (force [[(force (builtin trace)) [fromString_6 message_10]] (delay subject_5)])])]) + (lam value_9 value_9)]) + (lam value_8 value_8)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(con integer 9) +--- logs +["subject", "fallback"] +--- budget +cpu: 1069247, memory: 5996 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_returns_captured_function.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_returns_captured_function.snap new file mode 100644 index 00000000..1185a63b --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_returns_captured_function.snap @@ -0,0 +1,88 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : int -> Choice -> (int -> int)\nchoose outer subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" (\\n -> n)\n _ -> trace \"fallback\" (\\n -> addInteger outer n)\nmain = (choose 10 Stop 5, choose 10 Zero 5, choose 10 (One 2) 5, choose 10 (Two 3 4) 5)\n" +--- +--- core +let message#28 : string = "subject" in +let message#29 : string = "fallback" in +let message#30 : string = "explicit" in +let fromString#10 : string -> string = \value#26 : string -> value#26 in +let choose#2 : int -> Main.Choice -> int -> int = \outer#8 : int subject#9 : Main.Choice -> let match#13 : Main.Choice = trace (fromString#10 message#28) in subject#9 in +let leaf#19 : 'erased = delay (trace (fromString#10 message#29) in \n#12 : int -> addInteger outer#8 n#12) in +let projection#27 : pair int (list Data) = unConstrData match#13 in +case@Pair projection#27 of + Pair tag#23 fields#24 -> case@Tag tag#23 of + 0 -> trace (fromString#10 message#30) in \n#11 : int -> n#11 + 1 -> force leaf#19 + 2 -> force leaf#19 + 3 -> force leaf#19 in +let fromInt#3 : int -> int = \value#25 : int -> value#25 in +let fromInt#5 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (fromInt#3 10) (constrData 0 (con (list data) [])) (fromInt#3 5)) (choose#2 (fromInt#3 10) (constrData 1 (con (list data) [])) (fromInt#3 5)) (choose#2 (fromInt#3 10) ((\field#4 : Int -> constrData 2 (mkCons field#4 (con (list data) []))) (fromInt#5 2)) (fromInt#3 5)) (choose#2 (fromInt#3 10) ((\field#6 : Int field#7 : Int -> constrData 3 (mkCons field#6 (mkCons field#7 (con (list data) [])))) (fromInt#5 3) (fromInt#5 4)) (fromInt#3 5)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_28 + [(lam message_29 + [(lam message_30 + [(lam fromString_10 + [(lam choose_2 + [(lam fromInt_3 + [(lam fromInt_5 + [(lam main_1 main_1) + (constr 0 + [[[choose_2 [fromInt_3 (con integer 10)]] + [[(builtin constrData) (con integer 0)] (con (list data) [])]] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] + [[(builtin constrData) (con integer 1)] (con (list data) [])]] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] + [(lam field_4 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_4] (con (list data) [])]]) + [fromInt_5 (con integer 2)]]] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] + [[(lam field_6 + (lam field_7 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_6] + [[(force (builtin mkCons)) field_7] (con (list data) [])]]])) + [fromInt_5 (con integer 3)]] + [fromInt_5 (con integer 4)]]] + [fromInt_3 (con integer 5)]])]) + (builtin iData)]) + (lam value_25 value_25)]) + (lam outer_8 + (lam subject_9 + [(lam match_13 + [(lam leaf_19 + [(lam projection_27 + (case + projection_27 + (lam tag_23 + (lam fields_24 + (case + tag_23 + (force + [[(force (builtin trace)) [fromString_10 message_30]] (delay (lam n_11 n_11))]) + (force leaf_19) + (force leaf_19) + (force leaf_19)))))) + [(builtin unConstrData) match_13]]) + (delay + (force + [[(force (builtin trace)) [fromString_10 message_29]] + (delay (lam n_12 [[(builtin addInteger) outer_8] n_12]))]))]) + (force [[(force (builtin trace)) [fromString_10 message_28]] (delay subject_9)])]))]) + (lam value_26 value_26)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 5) (con integer 15) (con integer 15) (con integer 15)) +--- logs +["subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 6045647, memory: 30910 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_one.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_one.snap new file mode 100644 index 00000000..37715d93 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_one.snap @@ -0,0 +1,64 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose (One 2)\n" +--- +--- core +let message#23 : string = "subject" in +let message#24 : string = "fallback" in +let fromString#6 : string -> string = \value#20 : string -> value#20 in +let fromInt#7 : int -> int = \value#21 : int -> value#21 in +let choose#2 : Main.Choice -> int = \subject#5 : Main.Choice -> let match#8 : Main.Choice = trace (fromString#6 message#23) in subject#5 in +let leaf#14 : 'erased = delay (trace (fromString#6 message#24) in error) in +let projection#22 : pair int (list Data) = unConstrData match#8 in +case@Pair projection#22 of + Pair tag#18 fields#19 -> case@Tag tag#18 of + 0 -> fromInt#7 1 + 1 -> force leaf#14 + 2 -> force leaf#14 + 3 -> force leaf#14 in +let fromInt#4 : int -> Int = iData in +let main#1 : int = choose#2 ((\field#3 : Int -> constrData 2 (mkCons field#3 (con (list data) []))) (fromInt#4 2)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_23 + [(lam message_24 + [(lam fromString_6 + [(lam fromInt_7 + [(lam choose_2 + [(lam fromInt_4 + [(lam main_1 main_1) + [choose_2 + [(lam field_3 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_3] (con (list data) [])]]) + [fromInt_4 (con integer 2)]]]]) + (builtin iData)]) + (lam subject_5 + [(lam match_8 + [(lam leaf_14 + [(lam projection_22 + (case + projection_22 + (lam tag_18 + (lam fields_19 + (case + tag_18 + [fromInt_7 (con integer 1)] + (force leaf_14) + (force leaf_14) + (force leaf_14)))))) + [(builtin unConstrData) match_8]]) + (delay + (force [[(force (builtin trace)) [fromString_6 message_24]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_6 message_23]] (delay subject_5)])])]) + (lam value_21 value_21)]) + (lam value_20 value_20)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 253496, memory: 292 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_two.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_two.snap new file mode 100644 index 00000000..ac7d4863 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_two.snap @@ -0,0 +1,67 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose (Two 3 4)\n" +--- +--- core +let message#24 : string = "subject" in +let message#25 : string = "fallback" in +let fromString#7 : string -> string = \value#21 : string -> value#21 in +let fromInt#8 : int -> int = \value#22 : int -> value#22 in +let choose#2 : Main.Choice -> int = \subject#6 : Main.Choice -> let match#9 : Main.Choice = trace (fromString#7 message#24) in subject#6 in +let leaf#15 : 'erased = delay (trace (fromString#7 message#25) in error) in +let projection#23 : pair int (list Data) = unConstrData match#9 in +case@Pair projection#23 of + Pair tag#19 fields#20 -> case@Tag tag#19 of + 0 -> fromInt#8 1 + 1 -> force leaf#15 + 2 -> force leaf#15 + 3 -> force leaf#15 in +let fromInt#5 : int -> Int = iData in +let main#1 : int = choose#2 ((\field#3 : Int field#4 : Int -> constrData 3 (mkCons field#3 (mkCons field#4 (con (list data) [])))) (fromInt#5 3) (fromInt#5 4)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_24 + [(lam message_25 + [(lam fromString_7 + [(lam fromInt_8 + [(lam choose_2 + [(lam fromInt_5 + [(lam main_1 main_1) + [choose_2 + [[(lam field_3 + (lam field_4 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_3] + [[(force (builtin mkCons)) field_4] (con (list data) [])]]])) + [fromInt_5 (con integer 3)]] + [fromInt_5 (con integer 4)]]]]) + (builtin iData)]) + (lam subject_6 + [(lam match_9 + [(lam leaf_15 + [(lam projection_23 + (case + projection_23 + (lam tag_19 + (lam fields_20 + (case + tag_19 + [fromInt_8 (con integer 1)] + (force leaf_15) + (force leaf_15) + (force leaf_15)))))) + [(builtin unConstrData) match_9]]) + (delay + (force [[(force (builtin trace)) [fromString_7 message_25]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_7 message_24]] (delay subject_6)])])]) + (lam value_22 value_22)]) + (lam value_21 value_21)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 341157, memory: 356 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_unselected.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_unselected.snap new file mode 100644 index 00000000..dce50c96 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_unselected.snap @@ -0,0 +1,62 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" fail\nmain = choose Stop\n" +--- +--- core +let message#21 : string = "subject" in +let message#22 : string = "fallback" in +let message#23 : string = "explicit" in +let fromString#4 : string -> string = \value#18 : string -> value#18 in +let fromInt#5 : int -> int = \value#19 : int -> value#19 in +let choose#2 : Main.Choice -> int = \subject#3 : Main.Choice -> let match#6 : Main.Choice = trace (fromString#4 message#21) in subject#3 in +let leaf#12 : 'erased = delay (trace (fromString#4 message#22) in error) in +let projection#20 : pair int (list Data) = unConstrData match#6 in +case@Pair projection#20 of + Pair tag#16 fields#17 -> case@Tag tag#16 of + 0 -> trace (fromString#4 message#23) in fromInt#5 1 + 1 -> force leaf#12 + 2 -> force leaf#12 + 3 -> force leaf#12 in +let main#1 : int = choose#2 (constrData 0 (con (list data) [])) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_21 + [(lam message_22 + [(lam message_23 + [(lam fromString_4 + [(lam fromInt_5 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 [[(builtin constrData) (con integer 0)] (con (list data) [])]]]) + (lam subject_3 + [(lam match_6 + [(lam leaf_12 + [(lam projection_20 + (case + projection_20 + (lam tag_16 + (lam fields_17 + (case + tag_16 + (force + [[(force (builtin trace)) [fromString_4 message_23]] + (delay [fromInt_5 (con integer 1)])]) + (force leaf_12) + (force leaf_12) + (force leaf_12)))))) + [(builtin unConstrData) match_6]]) + (delay + (force [[(force (builtin trace)) [fromString_4 message_22]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_4 message_21]] (delay subject_3)])])]) + (lam value_19 value_19)]) + (lam value_18 value_18)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(con integer 1) +--- logs +["subject", "explicit"] +--- budget +cpu: 1269835, memory: 7128 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_zero.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_zero.snap new file mode 100644 index 00000000..d4c9e8f9 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_failure_zero.snap @@ -0,0 +1,57 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose Zero\n" +--- +--- core +let message#21 : string = "subject" in +let message#22 : string = "fallback" in +let fromString#4 : string -> string = \value#18 : string -> value#18 in +let fromInt#5 : int -> int = \value#19 : int -> value#19 in +let choose#2 : Main.Choice -> int = \subject#3 : Main.Choice -> let match#6 : Main.Choice = trace (fromString#4 message#21) in subject#3 in +let leaf#12 : 'erased = delay (trace (fromString#4 message#22) in error) in +let projection#20 : pair int (list Data) = unConstrData match#6 in +case@Pair projection#20 of + Pair tag#16 fields#17 -> case@Tag tag#16 of + 0 -> fromInt#5 1 + 1 -> force leaf#12 + 2 -> force leaf#12 + 3 -> force leaf#12 in +let main#1 : int = choose#2 (constrData 1 (con (list data) [])) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_21 + [(lam message_22 + [(lam fromString_4 + [(lam fromInt_5 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 [[(builtin constrData) (con integer 1)] (con (list data) [])]]]) + (lam subject_3 + [(lam match_6 + [(lam leaf_12 + [(lam projection_20 + (case + projection_20 + (lam tag_16 + (lam fields_17 + (case + tag_16 + [fromInt_5 (con integer 1)] + (force leaf_12) + (force leaf_12) + (force leaf_12)))))) + [(builtin unConstrData) match_6]]) + (delay + (force [[(force (builtin trace)) [fromString_4 message_22]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_4 message_21]] (delay subject_3)])])]) + (lam value_19 value_19)]) + (lam value_18 value_18)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 165835, memory: 228 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_helper_receives_bound_values.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_helper_receives_bound_values.snap new file mode 100644 index 00000000..b965610f --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_shared_helper_receives_bound_values.snap @@ -0,0 +1,93 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : (Choice, int) -> int\nchoose subject =\n case trace \"subject\" subject of\n (Stop, _) -> 0\n (_, value) -> trace \"shared\" value\nmain = (choose (Stop, 1), choose (Zero, 11), choose (One 2, 22), choose (Two 3 4, 33))\n" +--- +--- core +let message#30 : string = "subject" in +let message#31 : string = "shared" in +let fromInt#3 : int -> int = \value#27 : int -> value#27 in +let fromString#9 : string -> string = \value#28 : string -> value#28 in +let choose#2 : (Main.Choice, int) -> int = \subject#8 : (Main.Choice, int) -> let match#11 : (Main.Choice, int) = trace (fromString#9 message#30) in subject#8 in +let leaf#19 : 'erased = \value#10 : int -> trace (fromString#9 message#31) in value#10 in +case@Tag match#11 of + 0 field#20 field#21 -> let projection#29 : pair int (list Data) = unConstrData field#20 in + case@Pair projection#29 of + Pair tag#25 fields#26 -> case@Tag tag#25 of + 0 -> fromInt#3 0 + 1 -> let value#10 : int = field#21 in + leaf#19 value#10 + 2 -> let value#10 : int = field#21 in + leaf#19 value#10 + 3 -> let value#10 : int = field#21 in + leaf#19 value#10 in +let fromInt#5 : int -> Int = iData in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0 (constrData 0 (con (list data) [])) (fromInt#3 1))) (choose#2 (constr 0 (constrData 1 (con (list data) [])) (fromInt#3 11))) (choose#2 (constr 0 ((\field#4 : Int -> constrData 2 (mkCons field#4 (con (list data) []))) (fromInt#5 2)) (fromInt#3 22))) (choose#2 (constr 0 ((\field#6 : Int field#7 : Int -> constrData 3 (mkCons field#6 (mkCons field#7 (con (list data) [])))) (fromInt#5 3) (fromInt#5 4)) (fromInt#3 33))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_30 + [(lam message_31 + [(lam fromInt_3 + [(lam fromString_9 + [(lam choose_2 + [(lam fromInt_5 + [(lam main_1 main_1) + (constr 0 + [choose_2 + (constr 0 + [[(builtin constrData) (con integer 0)] (con (list data) [])] + [fromInt_3 (con integer 1)])] + [choose_2 + (constr 0 + [[(builtin constrData) (con integer 1)] (con (list data) [])] + [fromInt_3 (con integer 11)])] + [choose_2 + (constr 0 + [(lam field_4 + [[(builtin constrData) (con integer 2)] + [[(force (builtin mkCons)) field_4] (con (list data) [])]]) + [fromInt_5 (con integer 2)]] + [fromInt_3 (con integer 22)])] + [choose_2 + (constr 0 + [[(lam field_6 + (lam field_7 + [[(builtin constrData) (con integer 3)] + [[(force (builtin mkCons)) field_6] + [[(force (builtin mkCons)) field_7] (con (list data) [])]]])) + [fromInt_5 (con integer 3)]] + [fromInt_5 (con integer 4)]] + [fromInt_3 (con integer 33)])])]) + (builtin iData)]) + (lam subject_8 + [(lam match_11 + [(lam leaf_19 + (case + match_11 + (lam field_20 + (lam field_21 + [(lam projection_29 + (case + projection_29 + (lam tag_25 + (lam fields_26 + (case + tag_25 + [fromInt_3 (con integer 0)] + [(lam value_10 [leaf_19 value_10]) field_21] + [(lam value_10 [leaf_19 value_10]) field_21] + [(lam value_10 [leaf_19 value_10]) field_21]))))) + [(builtin unConstrData) field_20]])))) + (lam value_10 + (force [[(force (builtin trace)) [fromString_9 message_31]] (delay value_10)]))]) + (force [[(force (builtin trace)) [fromString_9 message_30]] (delay subject_8)])])]) + (lam value_28 value_28)]) + (lam value_27 value_27)]) + (con string "shared")]) + (con string "subject")]) +--- result +(constr 0 (con integer 0) (con integer 11) (con integer 22) (con integer 33)) +--- logs +["subject", "subject", "shared", "subject", "shared", "subject", "shared"] +--- budget +cpu: 5330525, memory: 28672 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_unknown_tag_fails_dispatch.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_unknown_tag_fails_dispatch.snap new file mode 100644 index 00000000..c81bf614 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__big_wildcard_unknown_tag_fails_dispatch.snap @@ -0,0 +1,66 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype Choice = Stop | Zero | One Int | Two Int Int\nchoose : Choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" 9\nmain = choose (coerce (constrData 59 []))\n" +--- +--- core +let message#22 : string = "subject" in +let message#23 : string = "fallback" in +let message#24 : string = "explicit" in +let fromInt#4 : int -> int = \value#19 : int -> value#19 in +let fromString#6 : string -> string = \value#20 : string -> value#20 in +let choose#2 : Main.Choice -> int = \subject#5 : Main.Choice -> let match#7 : Main.Choice = trace (fromString#6 message#22) in subject#5 in +let leaf#13 : 'erased = delay (trace (fromString#6 message#23) in fromInt#4 9) in +let projection#21 : pair int (list Data) = unConstrData match#7 in +case@Pair projection#21 of + Pair tag#17 fields#18 -> case@Tag tag#17 of + 0 -> trace (fromString#6 message#24) in fromInt#4 1 + 1 -> force leaf#13 + 2 -> force leaf#13 + 3 -> force leaf#13 in +let main#1 : int = choose#2 ((\coerce#3 : 'erased -> coerce#3) (constrData (fromInt#4 59) (con (list data) []))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_22 + [(lam message_23 + [(lam message_24 + [(lam fromInt_4 + [(lam fromString_6 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 + [(lam coerce_3 coerce_3) + [[(builtin constrData) [fromInt_4 (con integer 59)]] (con (list data) [])]]]]) + (lam subject_5 + [(lam match_7 + [(lam leaf_13 + [(lam projection_21 + (case + projection_21 + (lam tag_17 + (lam fields_18 + (case + tag_17 + (force + [[(force (builtin trace)) [fromString_6 message_24]] + (delay [fromInt_4 (con integer 1)])]) + (force leaf_13) + (force leaf_13) + (force leaf_13)))))) + [(builtin unConstrData) match_7]]) + (delay + (force + [[(force (builtin trace)) [fromString_6 message_23]] + (delay [fromInt_4 (con integer 9)])]))]) + (force [[(force (builtin trace)) [fromString_6 message_22]] (delay subject_5)])])]) + (lam value_20 value_20)]) + (lam value_19 value_19)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: NonConstrScrutinized(Con(Integer(59))) +--- logs +["subject"] +--- budget +cpu: 106337, memory: 196 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__captured_generic_evidence_is_local_to_each_outer_specialization.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__captured_generic_evidence_is_local_to_each_outer_specialization.snap index 396baf73..03831358 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__captured_generic_evidence_is_local_to_each_outer_specialization.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__captured_generic_evidence_is_local_to_each_outer_specialization.snap @@ -32,8 +32,7 @@ main#1 (lam value_15 value_15)]) (lam x_11 [(lam same_12 [same_12 x_11]) (lam y_13 [[eq_14 x_11] y_13])])]) (lam arg_16 - (lam arg_17 - [(lam match_20 [(lam match_19 [fromBool_18 (con bool True)]) arg_17]) arg_16]))]) + (lam arg_17 (case arg_16 (case arg_17 [fromBool_18 (con bool True)]))))]) (lam value_21 value_21)]) (lam value_10 value_10)]) (lam x_6 [(lam same_7 [same_7 x_6]) (lam y_8 [[eq_9 x_6] y_8])])]) @@ -43,4 +42,4 @@ main#1 --- logs [] --- budget -cpu: 1172433, memory: 7101 +cpu: 1140433, memory: 6901 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__constrained_functions_are_first_class_specializations.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__constrained_functions_are_first_class_specializations.snap index f7c4c40a..13eba9b2 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__constrained_functions_are_first_class_specializations.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__constrained_functions_are_first_class_specializations.snap @@ -20,9 +20,7 @@ main#1 [(lam main_1 main_1) [[[pass_2 eq_3] [fromUnit_4 (con unit ())]] [fromUnit_4 (con unit ())]]]) (lam value_12 value_12)]) - (lam arg_7 - (lam arg_8 - [(lam match_11 [(lam match_10 [fromBool_9 (con bool True)]) arg_8]) arg_7]))]) + (lam arg_7 (lam arg_8 (case arg_7 (case arg_8 [fromBool_9 (con bool True)]))))]) (lam value_13 value_13)]) (lam f_5 (lam x_6 [f_5 x_6]))]) --- result @@ -30,4 +28,4 @@ main#1 --- logs [] --- budget -cpu: 688100, memory: 4400 +cpu: 656100, memory: 4200 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__generic_impl_context_default_and_superclass_evidence_are_closed.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__generic_impl_context_default_and_superclass_evidence_are_closed.snap index e203ffbb..301e90f7 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__generic_impl_context_default_and_superclass_evidence_are_closed.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__generic_impl_context_default_and_superclass_evidence_are_closed.snap @@ -1,30 +1,31 @@ --- source: crates/nash-codegen/src/build/tests.rs -description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\ntrait Eq 'a => Same 'a where\n same : 'a -> 'a -> bool\n same x y = eq x y\nimpl Same int where\nimpl Eq 'a => Same (list 'a) where\nuse : Same 'a => 'a -> 'a -> bool\nuse x y = if same x y then neq x y else True\nmain = use [1, 2] [1, 3]\n" +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\ntrait Eq 'a => Same 'a where\n same : 'a -> 'a -> bool\n same x y = eq x y\nimpl Same int where\nimpl Eq (list 'a) => Same (list 'a) where\nuse : Same 'a => 'a -> 'a -> bool\nuse x y = if same x y then neq x y else True\nmain = use [1, 2] [1, 3]\n" --- --- core let fromBool#6 : bool -> bool = \value#10 : bool -> value#10 in -let eq#25 : int -> int -> bool = equalsInteger in -let eq#13 : list 'erased -> list 'erased -> bool = (\self#32 : 'erased -> self#32 self#32) (\self#32 : 'erased xs#16 : list 'erased ys#17 : list 'erased -> let match#29 : list 'erased = xs#16 in -case@List match#29 of - Nil -> let match#18 : list 'erased = ys#17 in - case@List match#18 of +let eq#26 : int -> int -> bool = equalsInteger in +let eq#13 : list 'erased -> list 'erased -> bool = (\self#35 : 'erased -> self#35 self#35) (\self#35 : 'erased xs#17 : list 'erased ys#18 : list 'erased -> let match#30 : list 'erased = xs#17 in +case@List match#30 of + Nil -> let match#19 : list 'erased = ys#18 in + case@List match#19 of Nil -> fromBool#6 true - Cons field#19 field#20 -> fromBool#6 false - Cons field#30 field#31 -> let x#21 : 'erased = field#30 in - let restX#22 : list 'erased = field#31 in - let match#26 : list 'erased = ys#17 in - case@List match#26 of + Cons field#20 field#21 -> fromBool#6 false + Cons field#31 field#32 -> let x#22 : 'erased = field#31 in + let restX#23 : list 'erased = field#32 in + let match#27 : list 'erased = ys#18 in + case@List match#27 of Nil -> fromBool#6 false - Cons field#27 field#28 -> let y#23 : 'erased = field#27 in - let restY#24 : list 'erased = field#28 in - case@Bool eq#25 x#21 y#23 of - True -> self#32 self#32 restX#22 restY#24 - False -> fromBool#6 false) in + Cons field#28 field#29 -> let y#24 : 'erased = field#28 in + let restY#25 : list 'erased = field#29 in + case@Bool eq#26 x#22 y#24 of + True -> self#35 self#35 restX#23 restY#25 + False -> false) in let same#7 : 'erased -> 'erased -> bool = \x#11 : 'erased y#12 : 'erased -> eq#13 x#11 y#12 in -let neq#8 : 'erased -> 'erased -> bool = \a#14 : 'erased b#15 : 'erased -> case@Bool eq#13 a#14 b#15 of - True -> fromBool#6 false - False -> fromBool#6 true in +let not#16 : 'erased -> bool = \value#33 : 'erased -> case@Bool (\identity#34 : 'erased -> identity#34) value#33 of + True -> false + False -> true in +let neq#8 : 'erased -> 'erased -> bool = \a#14 : 'erased b#15 : 'erased -> not#16 (eq#13 a#14 b#15) in let use#2 : 'erased -> 'erased -> bool = \x#4 : 'erased y#5 : 'erased -> case@Bool same#7 x#4 y#5 of True -> neq#8 x#4 y#5 False -> fromBool#6 true in @@ -34,64 +35,62 @@ main#1 --- uplc (program 1.1.0 [(lam fromBool_6 - [(lam eq_25 + [(lam eq_26 [(lam eq_13 [(lam same_7 - [(lam neq_8 - [(lam use_2 - [(lam fromInt_3 - [(lam main_1 main_1) - [[use_2 - [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] - [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list integer) [])]]] - [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] - [[(force (builtin mkCons)) [fromInt_3 (con integer 3)]] (con (list integer) [])]]]]) - (lam value_9 value_9)]) - (lam x_4 - (lam y_5 - (case [[same_7 x_4] y_5] [fromBool_6 (con bool True)] [[neq_8 x_4] y_5])))]) - (lam a_14 - (lam b_15 - (case - [[eq_13 a_14] b_15] - [fromBool_6 (con bool True)] - [fromBool_6 (con bool False)])))]) + [(lam not_16 + [(lam neq_8 + [(lam use_2 + [(lam fromInt_3 + [(lam main_1 main_1) + [[use_2 + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list integer) [])]]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 3)]] (con (list integer) [])]]]]) + (lam value_9 value_9)]) + (lam x_4 + (lam y_5 + (case [[same_7 x_4] y_5] [fromBool_6 (con bool True)] [[neq_8 x_4] y_5])))]) + (lam a_14 (lam b_15 [not_16 [[eq_13 a_14] b_15]]))]) + (lam value_33 + (case [(lam identity_34 identity_34) value_33] (con bool True) (con bool False)))]) (lam x_11 (lam y_12 [[eq_13 x_11] y_12]))]) - [(lam self_32 [self_32 self_32]) - (lam self_32 - (lam xs_16 - (lam ys_17 - [(lam match_29 + [(lam self_35 [self_35 self_35]) + (lam self_35 + (lam xs_17 + (lam ys_18 + [(lam match_30 (case - match_29 - (lam field_30 - (lam field_31 - [(lam x_21 - [(lam restX_22 - [(lam match_26 + match_30 + (lam field_31 + (lam field_32 + [(lam x_22 + [(lam restX_23 + [(lam match_27 (case - match_26 - (lam field_27 - (lam field_28 - [(lam y_23 - [(lam restY_24 + match_27 + (lam field_28 + (lam field_29 + [(lam y_24 + [(lam restY_25 (case - [[eq_25 x_21] y_23] - [fromBool_6 (con bool False)] - [[[self_32 self_32] restX_22] restY_24])) - field_28]) - field_27])) + [[eq_26 x_22] y_24] + (con bool False) + [[[self_35 self_35] restX_23] restY_25])) + field_29]) + field_28])) [fromBool_6 (con bool False)])) - ys_17]) - field_31]) - field_30])) - [(lam match_18 + ys_18]) + field_32]) + field_31])) + [(lam match_19 (case - match_18 - (lam field_19 (lam field_20 [fromBool_6 (con bool False)])) + match_19 + (lam field_20 (lam field_21 [fromBool_6 (con bool False)])) [fromBool_6 (con bool True)])) - ys_17])) - xs_16])))]]) + ys_18])) + xs_17])))]]) (builtin equalsInteger)]) (lam value_10 value_10)]) --- result diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_big_structural_cases.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_big_structural_cases.snap new file mode 100644 index 00000000..820db4aa --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_big_structural_cases.snap @@ -0,0 +1,53 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nsame : list Int -> list Int -> bool\nsame = eq\nmain =\n ( same [] []\n , same [1, 2] [1, 2]\n , same [1, 2] [1, 3]\n , same [1] [1, 2]\n , same [1, 2] [2, 1]\n )\n" +--- +--- core +let eq#4 : list 'erased -> list 'erased -> bool = \xs#5 : list 'erased ys#6 : list 'erased -> equalsData (listData xs#5) (listData ys#6) in +let same#2 : list Int -> list Int -> bool = eq#4 in +let fromInt#3 : int -> Int = iData in +let main#1 : (bool, bool, bool, bool, bool) = constr 0 (same#2 (con (list data) []) (con (list data) [])) (same#2 (mkCons (fromInt#3 1) (mkCons (fromInt#3 2) (con (list data) []))) (mkCons (fromInt#3 1) (mkCons (fromInt#3 2) (con (list data) [])))) (same#2 (mkCons (fromInt#3 1) (mkCons (fromInt#3 2) (con (list data) []))) (mkCons (fromInt#3 1) (mkCons (fromInt#3 3) (con (list data) [])))) (same#2 (mkCons (fromInt#3 1) (con (list data) [])) (mkCons (fromInt#3 1) (mkCons (fromInt#3 2) (con (list data) [])))) (same#2 (mkCons (fromInt#3 1) (mkCons (fromInt#3 2) (con (list data) []))) (mkCons (fromInt#3 2) (mkCons (fromInt#3 1) (con (list data) [])))) in +main#1 +--- uplc +(program 1.1.0 + [(lam eq_4 + [(lam same_2 + [(lam fromInt_3 + [(lam main_1 main_1) + (constr 0 + [[same_2 (con (list data) [])] (con (list data) [])] + [[same_2 + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list data) [])]]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list data) [])]]] + [[same_2 + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list data) [])]]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 3)]] (con (list data) [])]]] + [[same_2 + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] (con (list data) [])]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list data) [])]]] + [[same_2 + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] (con (list data) [])]]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 2)]] + [[(force (builtin mkCons)) [fromInt_3 (con integer 1)]] (con (list data) [])]]])]) + (builtin iData)]) + eq_4]) + (lam xs_5 + (lam ys_6 + [[(builtin equalsData) [(builtin listData) xs_5]] [(builtin listData) ys_6]]))]) +--- result +(constr 0 + (con bool True) + (con bool True) + (con bool False) + (con bool False) + (con bool False)) +--- logs +[] +--- budget +cpu: 10732620, memory: 20685 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_generic_big_and_little.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_generic_big_and_little.snap new file mode 100644 index 00000000..241d2f2c --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_generic_big_and_little.snap @@ -0,0 +1,106 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nsame : Eq (list 'a) => list 'a -> list 'a -> bool\nsame xs ys = eq xs ys\nbig : list Int\nbig = [1, 2]\nsmall : list int\nsmall = [1, 2]\nmain = if same big big then same small small else False\n" +--- +--- core +let fromBool#2 : bool -> bool = \value#7 : bool -> value#7 in +let eq#10 : list 'erased -> list 'erased -> bool = \xs#16 : list 'erased ys#17 : list 'erased -> equalsData (listData xs#16) (listData ys#17) in +let same#3 : list 'erased -> list 'erased -> bool = \xs#8 : list 'erased ys#9 : list 'erased -> eq#10 xs#8 ys#9 in +let fromInt#11 : int -> Int = iData in +let big#4 : list Int = mkCons (fromInt#11 1) (mkCons (fromInt#11 2) (con (list data) [])) in +let eq#27 : int -> int -> bool = equalsInteger in +let eq#14 : list 'erased -> list 'erased -> bool = (\self#35 : 'erased -> self#35 self#35) (\self#35 : 'erased xs#18 : list 'erased ys#19 : list 'erased -> let match#31 : list 'erased = xs#18 in +case@List match#31 of + Nil -> let match#20 : list 'erased = ys#19 in + case@List match#20 of + Nil -> fromBool#2 true + Cons field#21 field#22 -> fromBool#2 false + Cons field#32 field#33 -> let x#23 : 'erased = field#32 in + let restX#24 : list 'erased = field#33 in + let match#28 : list 'erased = ys#19 in + case@List match#28 of + Nil -> fromBool#2 false + Cons field#29 field#30 -> let y#25 : 'erased = field#29 in + let restY#26 : list 'erased = field#30 in + case@Bool eq#27 x#23 y#25 of + True -> self#35 self#35 restX#24 restY#26 + False -> false) in +let same#5 : list 'erased -> list 'erased -> bool = \xs#12 : list 'erased ys#13 : list 'erased -> eq#14 xs#12 ys#13 in +let fromInt#15 : int -> int = \value#34 : int -> value#34 in +let small#6 : list int = mkCons (fromInt#15 1) (mkCons (fromInt#15 2) (con (list integer) [])) in +let main#1 : bool = case@Bool same#3 big#4 big#4 of + True -> same#5 small#6 small#6 + False -> fromBool#2 false in +main#1 +--- uplc +(program 1.1.0 + [(lam fromBool_2 + [(lam eq_10 + [(lam same_3 + [(lam fromInt_11 + [(lam big_4 + [(lam eq_27 + [(lam eq_14 + [(lam same_5 + [(lam fromInt_15 + [(lam small_6 + [(lam main_1 main_1) + (case + [[same_3 big_4] big_4] + [fromBool_2 (con bool False)] + [[same_5 small_6] small_6])]) + [[(force (builtin mkCons)) [fromInt_15 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_15 (con integer 2)]] + (con (list integer) [])]]]) + (lam value_34 value_34)]) + (lam xs_12 (lam ys_13 [[eq_14 xs_12] ys_13]))]) + [(lam self_35 [self_35 self_35]) + (lam self_35 + (lam xs_18 + (lam ys_19 + [(lam match_31 + (case + match_31 + (lam field_32 + (lam field_33 + [(lam x_23 + [(lam restX_24 + [(lam match_28 + (case + match_28 + (lam field_29 + (lam field_30 + [(lam y_25 + [(lam restY_26 + (case + [[eq_27 x_23] y_25] + (con bool False) + [[[self_35 self_35] restX_24] restY_26])) + field_30]) + field_29])) + [fromBool_2 (con bool False)])) + ys_19]) + field_33]) + field_32])) + [(lam match_20 + (case + match_20 + (lam field_21 (lam field_22 [fromBool_2 (con bool False)])) + [fromBool_2 (con bool True)])) + ys_19])) + xs_18])))]]) + (builtin equalsInteger)]) + [[(force (builtin mkCons)) [fromInt_11 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_11 (con integer 2)]] (con (list data) [])]]]) + (builtin iData)]) + (lam xs_8 (lam ys_9 [[eq_10 xs_8] ys_9]))]) + (lam xs_16 + (lam ys_17 + [[(builtin equalsData) [(builtin listData) xs_16]] [(builtin listData) ys_17]]))]) + (lam value_7 value_7)]) +--- result +(con bool True) +--- logs +[] +--- budget +cpu: 4956570, memory: 20259 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_little_preserves_custom_eq_and_short_circuit.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_little_preserves_custom_eq_and_short_circuit.snap new file mode 100644 index 00000000..7f7376b4 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__list_eq_little_preserves_custom_eq_and_short_circuit.snap @@ -0,0 +1,97 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nvalues : list int\nvalues = [1, 2]\nmain = eq values values\n" +--- +--- core +let message#30 : string = "custom" in +let fromBool#6 : bool -> bool = \value#22 : bool -> value#22 in +let fromString#25 : string -> string = \value#29 : string -> value#29 in +let eq#14 : int -> int -> bool = \arg#23 : int arg#24 : int -> let match#27 : int = arg#23 in +let match#26 : int = arg#24 in +trace (fromString#25 message#30) in fromBool#6 false in +let eq#2 : list 'erased -> list 'erased -> bool = (\self#31 : 'erased -> self#31 self#31) (\self#31 : 'erased xs#4 : list 'erased ys#5 : list 'erased -> let match#18 : list 'erased = xs#4 in +case@List match#18 of + Nil -> let match#7 : list 'erased = ys#5 in + case@List match#7 of + Nil -> fromBool#6 true + Cons field#8 field#9 -> fromBool#6 false + Cons field#19 field#20 -> let x#10 : 'erased = field#19 in + let restX#11 : list 'erased = field#20 in + let match#15 : list 'erased = ys#5 in + case@List match#15 of + Nil -> fromBool#6 false + Cons field#16 field#17 -> let y#12 : 'erased = field#16 in + let restY#13 : list 'erased = field#17 in + case@Bool eq#14 x#10 y#12 of + True -> self#31 self#31 restX#11 restY#13 + False -> false) in +let fromInt#21 : int -> int = \value#28 : int -> value#28 in +let values#3 : list int = mkCons (fromInt#21 1) (mkCons (fromInt#21 2) (con (list integer) [])) in +let main#1 : bool = eq#2 values#3 values#3 in +main#1 +--- uplc +(program 1.1.0 + [(lam message_30 + [(lam fromBool_6 + [(lam fromString_25 + [(lam eq_14 + [(lam eq_2 + [(lam fromInt_21 + [(lam values_3 [(lam main_1 main_1) [[eq_2 values_3] values_3]]) + [[(force (builtin mkCons)) [fromInt_21 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_21 (con integer 2)]] + (con (list integer) [])]]]) + (lam value_28 value_28)]) + [(lam self_31 [self_31 self_31]) + (lam self_31 + (lam xs_4 + (lam ys_5 + [(lam match_18 + (case + match_18 + (lam field_19 + (lam field_20 + [(lam x_10 + [(lam restX_11 + [(lam match_15 + (case + match_15 + (lam field_16 + (lam field_17 + [(lam y_12 + [(lam restY_13 + (case + [[eq_14 x_10] y_12] + (con bool False) + [[[self_31 self_31] restX_11] restY_13])) + field_17]) + field_16])) + [fromBool_6 (con bool False)])) + ys_5]) + field_20]) + field_19])) + [(lam match_7 + (case + match_7 + (lam field_8 (lam field_9 [fromBool_6 (con bool False)])) + [fromBool_6 (con bool True)])) + ys_5])) + xs_4])))]]) + (lam arg_23 + (lam arg_24 + [(lam match_27 + [(lam match_26 + (force + [[(force (builtin trace)) [fromString_25 message_30]] + (delay [fromBool_6 (con bool False)])])) + arg_24]) + arg_23]))]) + (lam value_29 value_29)]) + (lam value_22 value_22)]) + (con string "custom")]) +--- result +(con bool False) +--- logs +["custom"] +--- budget +cpu: 1900322, memory: 10796 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_binds_whole_and_captures_outer.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_binds_whole_and_captures_outer.snap new file mode 100644 index 00000000..128d377f --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_binds_whole_and_captures_outer.snap @@ -0,0 +1,84 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nread : choice -> int\nread value =\n case value of\n Stop -> 0\n Zero -> 0\n One a -> a\n Two a b -> addInteger (a) (b)\nchoose : int -> choice -> int\nchoose outer subject =\n case trace \"subject\" subject of\n Stop -> 1\n whole -> trace \"fallback\" (addInteger outer (read whole))\nmain = (choose 10 Stop, choose 10 Zero, choose 10 (One 20), choose 10 (Two 30 40))\n" +--- +--- core +let message#30 : string = "subject" in +let message#31 : string = "fallback" in +let fromInt#3 : int -> int = \value#20 : int -> value#20 in +let fromString#9 : string -> string = \value#21 : string -> value#21 in +let read#11 : Main.choice -> int = \value#22 : Main.choice -> let match#26 : Main.choice = value#22 in +case@Tag match#26 of + 0 -> fromInt#3 0 + 1 -> fromInt#3 0 + 2 field#27 -> let a#23 : int = field#27 in + a#23 + 3 field#28 field#29 -> let a#24 : int = field#28 in + let b#25 : int = field#29 in + addInteger a#24 b#25 in +let choose#2 : int -> Main.choice -> int = \outer#7 : int subject#8 : Main.choice -> let match#12 : Main.choice = trace (fromString#9 message#30) in subject#8 in +let leaf#16 : 'erased = \whole#10 : Main.choice -> trace (fromString#9 message#31) in addInteger outer#7 (read#11 whole#10) in +case@Tag match#12 of + 0 -> fromInt#3 1 + 1 -> let whole#10 : Main.choice = match#12 in + leaf#16 whole#10 + 2 field#17 -> let whole#10 : Main.choice = match#12 in + leaf#16 whole#10 + 3 field#18 field#19 -> let whole#10 : Main.choice = match#12 in + leaf#16 whole#10 in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (fromInt#3 10) (constr 0)) (choose#2 (fromInt#3 10) (constr 1)) (choose#2 (fromInt#3 10) ((\field#4 : int -> constr 2 field#4) (fromInt#3 20))) (choose#2 (fromInt#3 10) ((\field#5 : int field#6 : int -> constr 3 field#5 field#6) (fromInt#3 30) (fromInt#3 40))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_30 + [(lam message_31 + [(lam fromInt_3 + [(lam fromString_9 + [(lam read_11 + [(lam choose_2 + [(lam main_1 main_1) + (constr 0 + [[choose_2 [fromInt_3 (con integer 10)]] (constr 0)] + [[choose_2 [fromInt_3 (con integer 10)]] (constr 1)] + [[choose_2 [fromInt_3 (con integer 10)]] + [(lam field_4 (constr 2 field_4)) [fromInt_3 (con integer 20)]]] + [[choose_2 [fromInt_3 (con integer 10)]] + [[(lam field_5 (lam field_6 (constr 3 field_5 field_6))) + [fromInt_3 (con integer 30)]] + [fromInt_3 (con integer 40)]]])]) + (lam outer_7 + (lam subject_8 + [(lam match_12 + [(lam leaf_16 + (case + match_12 + [fromInt_3 (con integer 1)] + [(lam whole_10 [leaf_16 whole_10]) match_12] + (lam field_17 [(lam whole_10 [leaf_16 whole_10]) match_12]) + (lam field_18 (lam field_19 [(lam whole_10 [leaf_16 whole_10]) match_12])))) + (lam whole_10 + (force + [[(force (builtin trace)) [fromString_9 message_31]] + (delay [[(builtin addInteger) outer_7] [read_11 whole_10]])]))]) + (force [[(force (builtin trace)) [fromString_9 message_30]] (delay subject_8)])]))]) + (lam value_22 + [(lam match_26 + (case + match_26 + [fromInt_3 (con integer 0)] + [fromInt_3 (con integer 0)] + (lam field_27 [(lam a_23 a_23) field_27]) + (lam field_28 + (lam field_29 + [(lam a_24 [(lam b_25 [[(builtin addInteger) a_24] b_25]) field_29]) field_28])))) + value_22])]) + (lam value_21 value_21)]) + (lam value_20 value_20)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 10) (con integer 30) (con integer 80)) +--- logs +["subject", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 5045418, memory: 26732 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_calls_user_continuation_only_when_selected.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_calls_user_continuation_only_when_selected.snap new file mode 100644 index 00000000..e8a346a0 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_calls_user_continuation_only_when_selected.snap @@ -0,0 +1,78 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> (int -> int) -> int\nchoose subject continue =\n case trace \"subject\" subject of\n Stop -> 0\n _ -> trace \"fallback\" (continue 9)\nfinish : int -> int\nfinish n = trace \"continue\" (addInteger n 100)\nmain = (choose Stop (\\_ -> trace \"wrong\" fail), choose Zero finish, choose (One 2) finish, choose (Two 3 4) finish)\n" +--- +--- core +let message#24 : string = "subject" in +let message#25 : string = "fallback" in +let message#26 : string = "continue" in +let message#27 : string = "wrong" in +let fromString#4 : string -> string = \value#21 : string -> value#21 in +let fromInt#8 : int -> int = \value#23 : int -> value#23 in +let choose#2 : Main.choice -> (int -> int) -> int = \subject#11 : Main.choice (continue#12 : int -> int) -> let match#13 : Main.choice = trace (fromString#4 message#24) in subject#11 in +let leaf#17 : 'erased = delay (trace (fromString#4 message#25) in continue#12 (fromInt#8 9)) in +case@Tag match#13 of + 0 -> fromInt#8 0 + 1 -> force leaf#17 + 2 field#18 -> force leaf#17 + 3 field#19 field#20 -> force leaf#17 in +let finish#6 : int -> int = \n#22 : int -> trace (fromString#4 message#26) in addInteger n#22 (fromInt#8 100) in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0) (\arg#3 : int -> let match#5 : int = arg#3 in +trace (fromString#4 message#27) in error)) (choose#2 (constr 1) finish#6) (choose#2 ((\field#7 : int -> constr 2 field#7) (fromInt#8 2)) finish#6) (choose#2 ((\field#9 : int field#10 : int -> constr 3 field#9 field#10) (fromInt#8 3) (fromInt#8 4)) finish#6) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_24 + [(lam message_25 + [(lam message_26 + [(lam message_27 + [(lam fromString_4 + [(lam fromInt_8 + [(lam choose_2 + [(lam finish_6 + [(lam main_1 main_1) + (constr 0 + [[choose_2 (constr 0)] + (lam arg_3 + [(lam match_5 + (force [[(force (builtin trace)) [fromString_4 message_27]] (delay (error))])) + arg_3])] + [[choose_2 (constr 1)] finish_6] + [[choose_2 [(lam field_7 (constr 2 field_7)) [fromInt_8 (con integer 2)]]] + finish_6] + [[choose_2 + [[(lam field_9 (lam field_10 (constr 3 field_9 field_10))) + [fromInt_8 (con integer 3)]] + [fromInt_8 (con integer 4)]]] + finish_6])]) + (lam n_22 + (force + [[(force (builtin trace)) [fromString_4 message_26]] + (delay [[(builtin addInteger) n_22] [fromInt_8 (con integer 100)]])]))]) + (lam subject_11 + (lam continue_12 + [(lam match_13 + [(lam leaf_17 + (case + match_13 + [fromInt_8 (con integer 0)] + (force leaf_17) + (lam field_18 (force leaf_17)) + (lam field_19 (lam field_20 (force leaf_17))))) + (delay + (force + [[(force (builtin trace)) [fromString_4 message_25]] + (delay [continue_12 [fromInt_8 (con integer 9)]])]))]) + (force [[(force (builtin trace)) [fromString_4 message_24]] (delay subject_11)])]))]) + (lam value_23 value_23)]) + (lam value_21 value_21)]) + (con string "wrong")]) + (con string "continue")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 0) (con integer 109) (con integer 109) (con integer 109)) +--- logs +["subject", "subject", "fallback", "continue", "subject", "fallback", "continue", "subject", "fallback", "continue"] +--- budget +cpu: 5058704, memory: 26426 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_inline_function_result_consumes_fields.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_inline_function_result_consumes_fields.snap new file mode 100644 index 00000000..19f49110 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_inline_function_result_consumes_fields.snap @@ -0,0 +1,51 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Two int int\nchoose : choice -> (int -> int)\nchoose subject =\n case trace \"subject\" subject of\n Stop -> \\n -> n\n _ -> trace \"fallback\" (\\n -> addInteger n 1)\nmain = (choose Stop 10, choose (Two 3 4) 20)\n" +--- +--- core +let message#15 : string = "subject" in +let message#16 : string = "fallback" in +let fromInt#3 : int -> int = \value#13 : int -> value#13 in +let fromString#7 : string -> string = \value#14 : string -> value#14 in +let choose#2 : Main.choice -> int -> int = \subject#6 : Main.choice -> let match#10 : Main.choice = trace (fromString#7 message#15) in subject#6 in +case@Tag match#10 of + 0 -> \n#8 : int -> n#8 + 1 field#11 field#12 -> trace (fromString#7 message#16) in \n#9 : int -> addInteger n#9 (fromInt#3 1) in +let main#1 : (int, int) = constr 0 (choose#2 (constr 0) (fromInt#3 10)) (choose#2 ((\field#4 : int field#5 : int -> constr 1 field#4 field#5) (fromInt#3 3) (fromInt#3 4)) (fromInt#3 20)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_15 + [(lam message_16 + [(lam fromInt_3 + [(lam fromString_7 + [(lam choose_2 + [(lam main_1 main_1) + (constr 0 + [[choose_2 (constr 0)] [fromInt_3 (con integer 10)]] + [[choose_2 + [[(lam field_4 (lam field_5 (constr 1 field_4 field_5))) + [fromInt_3 (con integer 3)]] + [fromInt_3 (con integer 4)]]] + [fromInt_3 (con integer 20)]])]) + (lam subject_6 + [(lam match_10 + (case + match_10 + (lam n_8 n_8) + (lam field_11 + (lam field_12 + (force + [[(force (builtin trace)) [fromString_7 message_16]] + (delay (lam n_9 [[(builtin addInteger) n_9] [fromInt_3 (con integer 1)]]))]))))) + (force [[(force (builtin trace)) [fromString_7 message_15]] (delay subject_6)])])]) + (lam value_14 value_14)]) + (lam value_13 value_13)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 10) (con integer 21)) +--- logs +["subject", "subject", "fallback"] +--- budget +cpu: 1911802, memory: 10398 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_mixed_arities_trace_order.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_mixed_arities_trace_order.snap new file mode 100644 index 00000000..798e2f6f --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_mixed_arities_trace_order.snap @@ -0,0 +1,63 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" 9\nmain = (choose Stop, choose Zero, choose (One 2), choose (Two 3 4))\n" +--- +--- core +let message#19 : string = "subject" in +let message#20 : string = "fallback" in +let message#21 : string = "explicit" in +let fromInt#4 : int -> int = \value#17 : int -> value#17 in +let fromString#8 : string -> string = \value#18 : string -> value#18 in +let choose#2 : Main.choice -> int = \subject#7 : Main.choice -> let match#9 : Main.choice = trace (fromString#8 message#19) in subject#7 in +let leaf#13 : 'erased = delay (trace (fromString#8 message#20) in fromInt#4 9) in +case@Tag match#9 of + 0 -> trace (fromString#8 message#21) in fromInt#4 1 + 1 -> force leaf#13 + 2 field#14 -> force leaf#13 + 3 field#15 field#16 -> force leaf#13 in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0)) (choose#2 (constr 1)) (choose#2 ((\field#3 : int -> constr 2 field#3) (fromInt#4 2))) (choose#2 ((\field#5 : int field#6 : int -> constr 3 field#5 field#6) (fromInt#4 3) (fromInt#4 4))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_19 + [(lam message_20 + [(lam message_21 + [(lam fromInt_4 + [(lam fromString_8 + [(lam choose_2 + [(lam main_1 main_1) + (constr 0 + [choose_2 (constr 0)] + [choose_2 (constr 1)] + [choose_2 [(lam field_3 (constr 2 field_3)) [fromInt_4 (con integer 2)]]] + [choose_2 + [[(lam field_5 (lam field_6 (constr 3 field_5 field_6))) + [fromInt_4 (con integer 3)]] + [fromInt_4 (con integer 4)]]])]) + (lam subject_7 + [(lam match_9 + [(lam leaf_13 + (case + match_9 + (force + [[(force (builtin trace)) [fromString_8 message_21]] + (delay [fromInt_4 (con integer 1)])]) + (force leaf_13) + (lam field_14 (force leaf_13)) + (lam field_15 (lam field_16 (force leaf_13))))) + (delay + (force + [[(force (builtin trace)) [fromString_8 message_20]] + (delay [fromInt_4 (con integer 9)])]))]) + (force [[(force (builtin trace)) [fromString_8 message_19]] (delay subject_7)])])]) + (lam value_18 value_18)]) + (lam value_17 value_17)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 9) (con integer 9) (con integer 9)) +--- logs +["subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 3548084, memory: 19556 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_multiple_bindings_return_function.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_multiple_bindings_return_function.snap new file mode 100644 index 00000000..88f4817b --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_multiple_bindings_return_function.snap @@ -0,0 +1,86 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : (choice, int, int) -> (int -> int)\nchoose subject =\n case trace \"subject\" subject of\n (Stop, _, _) -> \\n -> n\n (_, z, a) -> trace \"shared\" (\\n -> subtractInteger (addInteger z n) a)\nmain = (choose (Stop, 90, 80) 1, choose (Zero, 21, 3) 1, choose (One 2, 31, 4) 1, choose (Two 3 4, 41, 5) 1)\n" +--- +--- core +let message#29 : string = "subject" in +let message#30 : string = "shared" in +let fromString#8 : string -> string = \value#28 : string -> value#28 in +let choose#2 : (Main.choice, int, int) -> int -> int = \subject#7 : (Main.choice, int, int) -> let match#13 : (Main.choice, int, int) = trace (fromString#8 message#29) in subject#7 in +let leaf#20 : 'erased = \a#11 : int z#10 : int -> trace (fromString#8 message#30) in \n#12 : int -> subtractInteger (addInteger z#10 n#12) a#11 in +case@Tag match#13 of + 0 field#21 field#22 field#23 -> case@Tag field#21 of + 0 -> \n#9 : int -> n#9 + 1 -> let z#10 : int = field#22 in + let a#11 : int = field#23 in + leaf#20 a#11 z#10 + 2 field#24 -> let z#10 : int = field#22 in + let a#11 : int = field#23 in + leaf#20 a#11 z#10 + 3 field#25 field#26 -> let z#10 : int = field#22 in + let a#11 : int = field#23 in + leaf#20 a#11 z#10 in +let fromInt#3 : int -> int = \value#27 : int -> value#27 in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0 (constr 0) (fromInt#3 90) (fromInt#3 80)) (fromInt#3 1)) (choose#2 (constr 0 (constr 1) (fromInt#3 21) (fromInt#3 3)) (fromInt#3 1)) (choose#2 (constr 0 ((\field#4 : int -> constr 2 field#4) (fromInt#3 2)) (fromInt#3 31) (fromInt#3 4)) (fromInt#3 1)) (choose#2 (constr 0 ((\field#5 : int field#6 : int -> constr 3 field#5 field#6) (fromInt#3 3) (fromInt#3 4)) (fromInt#3 41) (fromInt#3 5)) (fromInt#3 1)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_29 + [(lam message_30 + [(lam fromString_8 + [(lam choose_2 + [(lam fromInt_3 + [(lam main_1 main_1) + (constr 0 + [[choose_2 + (constr 0 (constr 0) [fromInt_3 (con integer 90)] [fromInt_3 (con integer 80)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 (constr 1) [fromInt_3 (con integer 21)] [fromInt_3 (con integer 3)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 + [(lam field_4 (constr 2 field_4)) [fromInt_3 (con integer 2)]] + [fromInt_3 (con integer 31)] + [fromInt_3 (con integer 4)])] + [fromInt_3 (con integer 1)]] + [[choose_2 + (constr 0 + [[(lam field_5 (lam field_6 (constr 3 field_5 field_6))) + [fromInt_3 (con integer 3)]] + [fromInt_3 (con integer 4)]] + [fromInt_3 (con integer 41)] + [fromInt_3 (con integer 5)])] + [fromInt_3 (con integer 1)]])]) + (lam value_27 value_27)]) + (lam subject_7 + [(lam match_13 + [(lam leaf_20 + (case + match_13 + (lam field_21 + (lam field_22 + (lam field_23 + (case + field_21 + (lam n_9 n_9) + [(lam z_10 [(lam a_11 [[leaf_20 a_11] z_10]) field_23]) field_22] + (lam field_24 [(lam z_10 [(lam a_11 [[leaf_20 a_11] z_10]) field_23]) field_22]) + (lam field_25 + (lam field_26 [(lam z_10 [(lam a_11 [[leaf_20 a_11] z_10]) field_23]) field_22])))))))) + (lam a_11 + (lam z_10 + (force + [[(force (builtin trace)) [fromString_8 message_30]] + (delay + (lam n_12 [[(builtin subtractInteger) [[(builtin addInteger) z_10] n_12]] a_11]))])))]) + (force [[(force (builtin trace)) [fromString_8 message_29]] (delay subject_7)])])]) + (lam value_28 value_28)]) + (con string "shared")]) + (con string "subject")]) +--- result +(constr 0 (con integer 1) (con integer 19) (con integer 28) (con integer 37)) +--- logs +["subject", "subject", "shared", "subject", "shared", "subject", "shared"] +--- budget +cpu: 5839834, memory: 30436 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_only_does_not_inspect_unknown_tag.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_only_does_not_inspect_unknown_tag.snap new file mode 100644 index 00000000..8d51ff80 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_only_does_not_inspect_unknown_tag.snap @@ -0,0 +1,37 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\ntype rogue = R0 | R1 | R2 | R3 | R4\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n _ -> trace \"fallback\" 9\nmain = choose (coerce R4)\n" +--- +--- core +let message#10 : string = "subject" in +let message#11 : string = "fallback" in +let fromString#5 : string -> string = \value#8 : string -> value#8 in +let fromInt#6 : int -> int = \value#9 : int -> value#9 in +let choose#2 : Main.choice -> int = \subject#4 : Main.choice -> let match#7 : Main.choice = trace (fromString#5 message#10) in subject#4 in +trace (fromString#5 message#11) in fromInt#6 9 in +let main#1 : int = choose#2 ((\coerce#3 : 'erased -> coerce#3) (constr 4)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_10 + [(lam message_11 + [(lam fromString_5 + [(lam fromInt_6 + [(lam choose_2 + [(lam main_1 main_1) [choose_2 [(lam coerce_3 coerce_3) (constr 4)]]]) + (lam subject_4 + [(lam match_7 + (force + [[(force (builtin trace)) [fromString_5 message_11]] + (delay [fromInt_6 (con integer 9)])])) + (force [[(force (builtin trace)) [fromString_5 message_10]] (delay subject_4)])])]) + (lam value_9 value_9)]) + (lam value_8 value_8)]) + (con string "fallback")]) + (con string "subject")]) +--- result +(con integer 9) +--- logs +["subject", "fallback"] +--- budget +cpu: 935096, memory: 5264 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_returns_captured_function.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_returns_captured_function.snap new file mode 100644 index 00000000..217fd698 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_returns_captured_function.snap @@ -0,0 +1,68 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : int -> choice -> (int -> int)\nchoose outer subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" (\\n -> n)\n _ -> trace \"fallback\" (\\n -> addInteger outer n)\nmain = (choose 10 Stop 5, choose 10 Zero 5, choose 10 (One 2) 5, choose 10 (Two 3 4) 5)\n" +--- +--- core +let message#22 : string = "subject" in +let message#23 : string = "fallback" in +let message#24 : string = "explicit" in +let fromString#9 : string -> string = \value#21 : string -> value#21 in +let choose#2 : int -> Main.choice -> int -> int = \outer#7 : int subject#8 : Main.choice -> let match#12 : Main.choice = trace (fromString#9 message#22) in subject#8 in +let leaf#16 : 'erased = delay (trace (fromString#9 message#23) in \n#11 : int -> addInteger outer#7 n#11) in +case@Tag match#12 of + 0 -> trace (fromString#9 message#24) in \n#10 : int -> n#10 + 1 -> force leaf#16 + 2 field#17 -> force leaf#16 + 3 field#18 field#19 -> force leaf#16 in +let fromInt#3 : int -> int = \value#20 : int -> value#20 in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (fromInt#3 10) (constr 0) (fromInt#3 5)) (choose#2 (fromInt#3 10) (constr 1) (fromInt#3 5)) (choose#2 (fromInt#3 10) ((\field#4 : int -> constr 2 field#4) (fromInt#3 2)) (fromInt#3 5)) (choose#2 (fromInt#3 10) ((\field#5 : int field#6 : int -> constr 3 field#5 field#6) (fromInt#3 3) (fromInt#3 4)) (fromInt#3 5)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_22 + [(lam message_23 + [(lam message_24 + [(lam fromString_9 + [(lam choose_2 + [(lam fromInt_3 + [(lam main_1 main_1) + (constr 0 + [[[choose_2 [fromInt_3 (con integer 10)]] (constr 0)] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] (constr 1)] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] + [(lam field_4 (constr 2 field_4)) [fromInt_3 (con integer 2)]]] + [fromInt_3 (con integer 5)]] + [[[choose_2 [fromInt_3 (con integer 10)]] + [[(lam field_5 (lam field_6 (constr 3 field_5 field_6))) + [fromInt_3 (con integer 3)]] + [fromInt_3 (con integer 4)]]] + [fromInt_3 (con integer 5)]])]) + (lam value_20 value_20)]) + (lam outer_7 + (lam subject_8 + [(lam match_12 + [(lam leaf_16 + (case + match_12 + (force + [[(force (builtin trace)) [fromString_9 message_24]] (delay (lam n_10 n_10))]) + (force leaf_16) + (lam field_17 (force leaf_16)) + (lam field_18 (lam field_19 (force leaf_16))))) + (delay + (force + [[(force (builtin trace)) [fromString_9 message_23]] + (delay (lam n_11 [[(builtin addInteger) outer_7] n_11]))]))]) + (force [[(force (builtin trace)) [fromString_9 message_22]] (delay subject_8)])]))]) + (lam value_21 value_21)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(constr 0 (con integer 5) (con integer 15) (con integer 15) (con integer 15)) +--- logs +["subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", "fallback"] +--- budget +cpu: 4619708, memory: 24362 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_one.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_one.snap new file mode 100644 index 00000000..ed1a2c07 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_one.snap @@ -0,0 +1,49 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose (One 2)\n" +--- +--- core +let message#17 : string = "subject" in +let message#18 : string = "fallback" in +let fromInt#4 : int -> int = \value#15 : int -> value#15 in +let fromString#6 : string -> string = \value#16 : string -> value#16 in +let choose#2 : Main.choice -> int = \subject#5 : Main.choice -> let match#7 : Main.choice = trace (fromString#6 message#17) in subject#5 in +let leaf#11 : 'erased = delay (trace (fromString#6 message#18) in error) in +case@Tag match#7 of + 0 -> fromInt#4 1 + 1 -> force leaf#11 + 2 field#12 -> force leaf#11 + 3 field#13 field#14 -> force leaf#11 in +let main#1 : int = choose#2 ((\field#3 : int -> constr 2 field#3) (fromInt#4 2)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_17 + [(lam message_18 + [(lam fromInt_4 + [(lam fromString_6 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 [(lam field_3 (constr 2 field_3)) [fromInt_4 (con integer 2)]]]]) + (lam subject_5 + [(lam match_7 + [(lam leaf_11 + (case + match_7 + [fromInt_4 (con integer 1)] + (force leaf_11) + (lam field_12 (force leaf_11)) + (lam field_13 (lam field_14 (force leaf_11))))) + (delay + (force [[(force (builtin trace)) [fromString_6 message_18]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_6 message_17]] (delay subject_5)])])]) + (lam value_16 value_16)]) + (lam value_15 value_15)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 119096, memory: 164 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_two.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_two.snap new file mode 100644 index 00000000..9a9b9d50 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_two.snap @@ -0,0 +1,52 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose (Two 3 4)\n" +--- +--- core +let message#18 : string = "subject" in +let message#19 : string = "fallback" in +let fromInt#5 : int -> int = \value#16 : int -> value#16 in +let fromString#7 : string -> string = \value#17 : string -> value#17 in +let choose#2 : Main.choice -> int = \subject#6 : Main.choice -> let match#8 : Main.choice = trace (fromString#7 message#18) in subject#6 in +let leaf#12 : 'erased = delay (trace (fromString#7 message#19) in error) in +case@Tag match#8 of + 0 -> fromInt#5 1 + 1 -> force leaf#12 + 2 field#13 -> force leaf#12 + 3 field#14 field#15 -> force leaf#12 in +let main#1 : int = choose#2 ((\field#3 : int field#4 : int -> constr 3 field#3 field#4) (fromInt#5 3) (fromInt#5 4)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_18 + [(lam message_19 + [(lam fromInt_5 + [(lam fromString_7 + [(lam choose_2 + [(lam main_1 main_1) + [choose_2 + [[(lam field_3 (lam field_4 (constr 3 field_3 field_4))) + [fromInt_5 (con integer 3)]] + [fromInt_5 (con integer 4)]]]]) + (lam subject_6 + [(lam match_8 + [(lam leaf_12 + (case + match_8 + [fromInt_5 (con integer 1)] + (force leaf_12) + (lam field_13 (force leaf_12)) + (lam field_14 (lam field_15 (force leaf_12))))) + (delay + (force [[(force (builtin trace)) [fromString_7 message_19]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_7 message_18]] (delay subject_6)])])]) + (lam value_17 value_17)]) + (lam value_16 value_16)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 119096, memory: 164 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_unselected.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_unselected.snap new file mode 100644 index 00000000..5d9fe9e6 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_unselected.snap @@ -0,0 +1,52 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" fail\nmain = choose Stop\n" +--- +--- core +let message#16 : string = "subject" in +let message#17 : string = "fallback" in +let message#18 : string = "explicit" in +let fromString#4 : string -> string = \value#14 : string -> value#14 in +let fromInt#5 : int -> int = \value#15 : int -> value#15 in +let choose#2 : Main.choice -> int = \subject#3 : Main.choice -> let match#6 : Main.choice = trace (fromString#4 message#16) in subject#3 in +let leaf#10 : 'erased = delay (trace (fromString#4 message#17) in error) in +case@Tag match#6 of + 0 -> trace (fromString#4 message#18) in fromInt#5 1 + 1 -> force leaf#10 + 2 field#11 -> force leaf#10 + 3 field#12 field#13 -> force leaf#10 in +let main#1 : int = choose#2 (constr 0) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_16 + [(lam message_17 + [(lam message_18 + [(lam fromString_4 + [(lam fromInt_5 + [(lam choose_2 [(lam main_1 main_1) [choose_2 (constr 0)]]) + (lam subject_3 + [(lam match_6 + [(lam leaf_10 + (case + match_6 + (force + [[(force (builtin trace)) [fromString_4 message_18]] + (delay [fromInt_5 (con integer 1)])]) + (force leaf_10) + (lam field_11 (force leaf_10)) + (lam field_12 (lam field_13 (force leaf_10))))) + (delay + (force [[(force (builtin trace)) [fromString_4 message_17]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_4 message_16]] (delay subject_3)])])]) + (lam value_15 value_15)]) + (lam value_14 value_14)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +(con integer 1) +--- logs +["subject", "explicit"] +--- budget +cpu: 1015096, memory: 5764 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_zero.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_zero.snap new file mode 100644 index 00000000..a920e73e --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_failure_zero.snap @@ -0,0 +1,47 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> 1\n _ -> trace \"fallback\" fail\nmain = choose Zero\n" +--- +--- core +let message#16 : string = "subject" in +let message#17 : string = "fallback" in +let fromString#4 : string -> string = \value#14 : string -> value#14 in +let fromInt#5 : int -> int = \value#15 : int -> value#15 in +let choose#2 : Main.choice -> int = \subject#3 : Main.choice -> let match#6 : Main.choice = trace (fromString#4 message#16) in subject#3 in +let leaf#10 : 'erased = delay (trace (fromString#4 message#17) in error) in +case@Tag match#6 of + 0 -> fromInt#5 1 + 1 -> force leaf#10 + 2 field#11 -> force leaf#10 + 3 field#12 field#13 -> force leaf#10 in +let main#1 : int = choose#2 (constr 1) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_16 + [(lam message_17 + [(lam fromString_4 + [(lam fromInt_5 + [(lam choose_2 [(lam main_1 main_1) [choose_2 (constr 1)]]) + (lam subject_3 + [(lam match_6 + [(lam leaf_10 + (case + match_6 + [fromInt_5 (con integer 1)] + (force leaf_10) + (lam field_11 (force leaf_10)) + (lam field_12 (lam field_13 (force leaf_10))))) + (delay + (force [[(force (builtin trace)) [fromString_4 message_17]] (delay (error))]))]) + (force [[(force (builtin trace)) [fromString_4 message_16]] (delay subject_3)])])]) + (lam value_15 value_15)]) + (lam value_14 value_14)]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: ExplicitErrorTerm +--- logs +["subject", "fallback"] +--- budget +cpu: 119096, memory: 164 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_helper_receives_bound_values.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_helper_receives_bound_values.snap new file mode 100644 index 00000000..fd24e873 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_shared_helper_receives_bound_values.snap @@ -0,0 +1,69 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\nchoose : (choice, int) -> int\nchoose subject =\n case trace \"subject\" subject of\n (Stop, _) -> 0\n (_, value) -> trace \"shared\" value\nmain = (choose (Stop, 1), choose (Zero, 11), choose (One 2, 22), choose (Two 3 4, 33))\n" +--- +--- core +let message#24 : string = "subject" in +let message#25 : string = "shared" in +let fromInt#3 : int -> int = \value#22 : int -> value#22 in +let fromString#8 : string -> string = \value#23 : string -> value#23 in +let choose#2 : (Main.choice, int) -> int = \subject#7 : (Main.choice, int) -> let match#10 : (Main.choice, int) = trace (fromString#8 message#24) in subject#7 in +let leaf#16 : 'erased = \value#9 : int -> trace (fromString#8 message#25) in value#9 in +case@Tag match#10 of + 0 field#17 field#18 -> case@Tag field#17 of + 0 -> fromInt#3 0 + 1 -> let value#9 : int = field#18 in + leaf#16 value#9 + 2 field#19 -> let value#9 : int = field#18 in + leaf#16 value#9 + 3 field#20 field#21 -> let value#9 : int = field#18 in + leaf#16 value#9 in +let main#1 : (int, int, int, int) = constr 0 (choose#2 (constr 0 (constr 0) (fromInt#3 1))) (choose#2 (constr 0 (constr 1) (fromInt#3 11))) (choose#2 (constr 0 ((\field#4 : int -> constr 2 field#4) (fromInt#3 2)) (fromInt#3 22))) (choose#2 (constr 0 ((\field#5 : int field#6 : int -> constr 3 field#5 field#6) (fromInt#3 3) (fromInt#3 4)) (fromInt#3 33))) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_24 + [(lam message_25 + [(lam fromInt_3 + [(lam fromString_8 + [(lam choose_2 + [(lam main_1 main_1) + (constr 0 + [choose_2 (constr 0 (constr 0) [fromInt_3 (con integer 1)])] + [choose_2 (constr 0 (constr 1) [fromInt_3 (con integer 11)])] + [choose_2 + (constr 0 + [(lam field_4 (constr 2 field_4)) [fromInt_3 (con integer 2)]] + [fromInt_3 (con integer 22)])] + [choose_2 + (constr 0 + [[(lam field_5 (lam field_6 (constr 3 field_5 field_6))) + [fromInt_3 (con integer 3)]] + [fromInt_3 (con integer 4)]] + [fromInt_3 (con integer 33)])])]) + (lam subject_7 + [(lam match_10 + [(lam leaf_16 + (case + match_10 + (lam field_17 + (lam field_18 + (case + field_17 + [fromInt_3 (con integer 0)] + [(lam value_9 [leaf_16 value_9]) field_18] + (lam field_19 [(lam value_9 [leaf_16 value_9]) field_18]) + (lam field_20 (lam field_21 [(lam value_9 [leaf_16 value_9]) field_18]))))))) + (lam value_9 + (force [[(force (builtin trace)) [fromString_8 message_25]] (delay value_9)]))]) + (force [[(force (builtin trace)) [fromString_8 message_24]] (delay subject_7)])])]) + (lam value_23 value_23)]) + (lam value_22 value_22)]) + (con string "shared")]) + (con string "subject")]) +--- result +(constr 0 (con integer 0) (con integer 11) (con integer 22) (con integer 33)) +--- logs +["subject", "subject", "shared", "subject", "shared", "subject", "shared"] +--- budget +cpu: 3904586, memory: 22124 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_unknown_tag_fails_dispatch.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_unknown_tag_fails_dispatch.snap new file mode 100644 index 00000000..d359ca3a --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__little_wildcard_unknown_tag_fails_dispatch.snap @@ -0,0 +1,55 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype choice = Stop | Zero | One int | Two int int\ntype rogue = R0 | R1 | R2 | R3 | R4\nchoose : choice -> int\nchoose subject =\n case trace \"subject\" subject of\n Stop -> trace \"explicit\" 1\n _ -> trace \"fallback\" 9\nmain = choose (coerce R4)\n" +--- +--- core +let message#17 : string = "subject" in +let message#18 : string = "fallback" in +let message#19 : string = "explicit" in +let fromString#5 : string -> string = \value#15 : string -> value#15 in +let fromInt#6 : int -> int = \value#16 : int -> value#16 in +let choose#2 : Main.choice -> int = \subject#4 : Main.choice -> let match#7 : Main.choice = trace (fromString#5 message#17) in subject#4 in +let leaf#11 : 'erased = delay (trace (fromString#5 message#18) in fromInt#6 9) in +case@Tag match#7 of + 0 -> trace (fromString#5 message#19) in fromInt#6 1 + 1 -> force leaf#11 + 2 field#12 -> force leaf#11 + 3 field#13 field#14 -> force leaf#11 in +let main#1 : int = choose#2 ((\coerce#3 : 'erased -> coerce#3) (constr 4)) in +main#1 +--- uplc +(program 1.1.0 + [(lam message_17 + [(lam message_18 + [(lam message_19 + [(lam fromString_5 + [(lam fromInt_6 + [(lam choose_2 + [(lam main_1 main_1) [choose_2 [(lam coerce_3 coerce_3) (constr 4)]]]) + (lam subject_4 + [(lam match_7 + [(lam leaf_11 + (case + match_7 + (force + [[(force (builtin trace)) [fromString_5 message_19]] + (delay [fromInt_6 (con integer 1)])]) + (force leaf_11) + (lam field_12 (force leaf_11)) + (lam field_13 (lam field_14 (force leaf_11))))) + (delay + (force + [[(force (builtin trace)) [fromString_5 message_18]] + (delay [fromInt_6 (con integer 9)])]))]) + (force [[(force (builtin trace)) [fromString_5 message_17]] (delay subject_4)])])]) + (lam value_16 value_16)]) + (lam value_15 value_15)]) + (con string "explicit")]) + (con string "fallback")]) + (con string "subject")]) +--- result +error: MissingCaseBranch([Force(Apply { function: Apply { function: Force(Builtin(Trace)), argument: Apply { function: Var(DeBruijn(5)), argument: Var(DeBruijn(6)) } }, argument: Delay(Apply { function: Var(DeBruijn(4)), argument: Constant(Integer(1)) }) }), Force(Var(DeBruijn(1))), Lambda { parameter: DeBruijn(0), body: Force(Var(DeBruijn(2))) }, Lambda { parameter: DeBruijn(0), body: Lambda { parameter: DeBruijn(0), body: Force(Var(DeBruijn(3))) } }], Constr(4, [])) +--- logs +["subject"] +--- budget +cpu: 59598, memory: 132 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_big_and_native_preserve_entry_order.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_big_and_native_preserve_entry_order.snap new file mode 100644 index 00000000..25f862be --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_big_and_native_preserve_entry_order.snap @@ -0,0 +1,155 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nentries : list (pair Int Int)\nentries = [Builtin.mkPairData 1 2, Builtin.mkPairData 1 3]\nreversed : list (pair Int Int)\nreversed = [Builtin.mkPairData 1 3, Builtin.mkPairData 1 2]\nmain =\n ( eq (Builtin.mapData entries) (Builtin.mapData entries)\n , eq (Builtin.mapData entries) (Builtin.mapData reversed)\n , eq entries entries\n , eq entries reversed\n )\n" +--- +--- core +let fromInt#5 : int -> Int = iData in +let entries#2 : list (pair Int Int) = mkCons (mkPairData (fromInt#5 1) (fromInt#5 2)) (mkCons (mkPairData (fromInt#5 1) (fromInt#5 3)) (con (list (pair data data)) [])) in +let reversed#3 : list (pair Int Int) = mkCons (mkPairData (fromInt#5 1) (fromInt#5 3)) (mkCons (mkPairData (fromInt#5 1) (fromInt#5 2)) (con (list (pair data data)) [])) in +let fromBool#8 : bool -> bool = \value#23 : bool -> value#23 in +let eq#16 : pair 'erased 'erased -> pair 'erased 'erased -> bool = \a#24 : pair 'erased 'erased b#25 : pair 'erased 'erased -> let destruct#26 : pair 'erased 'erased = b#25 in +let destruct#27 : pair 'erased 'erased = a#24 in +let match#30 : pair 'erased 'erased = destruct#27 in +case@Pair match#30 of + Pair field#31 field#32 -> let firstA#28 : 'erased = field#31 in + let secondA#29 : 'erased = field#32 in + let match#35 : pair 'erased 'erased = destruct#26 in + case@Pair match#35 of + Pair field#36 field#37 -> let firstB#33 : 'erased = field#36 in + let secondB#34 : 'erased = field#37 in + case@Bool equalsData firstA#28 firstB#33 of + True -> let match#40 : pair 'erased 'erased = destruct#27 in + let firstA#38 : 'erased = field#31 in + let secondA#39 : 'erased = field#32 in + let match#45 : pair 'erased 'erased = destruct#26 in + let firstB#43 : 'erased = field#36 in + let secondB#44 : 'erased = field#37 in + equalsData secondA#39 secondB#44 + False -> false in +let eq#4 : list 'erased -> list 'erased -> bool = (\self#41 : 'erased -> self#41 self#41) (\self#41 : 'erased xs#6 : list 'erased ys#7 : list 'erased -> let match#20 : list 'erased = xs#6 in +case@List match#20 of + Nil -> let match#9 : list 'erased = ys#7 in + case@List match#9 of + Nil -> fromBool#8 true + Cons field#10 field#11 -> fromBool#8 false + Cons field#21 field#22 -> let x#12 : 'erased = field#21 in + let restX#13 : list 'erased = field#22 in + let match#17 : list 'erased = ys#7 in + case@List match#17 of + Nil -> fromBool#8 false + Cons field#18 field#19 -> let y#14 : 'erased = field#18 in + let restY#15 : list 'erased = field#19 in + case@Bool eq#16 x#12 y#14 of + True -> self#41 self#41 restX#13 restY#15 + False -> false) in +let main#1 : (bool, bool, bool, bool) = constr 0 (equalsData (mapData entries#2) (mapData entries#2)) (equalsData (mapData entries#2) (mapData reversed#3)) (eq#4 entries#2 entries#2) (eq#4 entries#2 reversed#3) in +main#1 +--- uplc +(program 1.1.0 + [(lam fromInt_5 + [(lam entries_2 + [(lam reversed_3 + [(lam fromBool_8 + [(lam eq_16 + [(lam eq_4 + [(lam main_1 main_1) + (constr 0 + [[(builtin equalsData) [(builtin mapData) entries_2]] + [(builtin mapData) entries_2]] + [[(builtin equalsData) [(builtin mapData) entries_2]] + [(builtin mapData) reversed_3]] + [[eq_4 entries_2] entries_2] + [[eq_4 entries_2] reversed_3])]) + [(lam self_41 [self_41 self_41]) + (lam self_41 + (lam xs_6 + (lam ys_7 + [(lam match_20 + (case + match_20 + (lam field_21 + (lam field_22 + [(lam x_12 + [(lam restX_13 + [(lam match_17 + (case + match_17 + (lam field_18 + (lam field_19 + [(lam y_14 + [(lam restY_15 + (case + [[eq_16 x_12] y_14] + (con bool False) + [[[self_41 self_41] restX_13] restY_15])) + field_19]) + field_18])) + [fromBool_8 (con bool False)])) + ys_7]) + field_22]) + field_21])) + [(lam match_9 + (case + match_9 + (lam field_10 (lam field_11 [fromBool_8 (con bool False)])) + [fromBool_8 (con bool True)])) + ys_7])) + xs_6])))]]) + (lam a_24 + (lam b_25 + [(lam destruct_26 + [(lam destruct_27 + [(lam match_30 + (case + match_30 + (lam field_31 + (lam field_32 + [(lam firstA_28 + [(lam secondA_29 + [(lam match_35 + (case + match_35 + (lam field_36 + (lam field_37 + [(lam firstB_33 + [(lam secondB_34 + (case + [[(builtin equalsData) firstA_28] firstB_33] + (con bool False) + [(lam match_40 + [(lam firstA_38 + [(lam secondA_39 + [(lam match_45 + [(lam firstB_43 + [(lam secondB_44 [[(builtin equalsData) secondA_39] secondB_44]) field_37]) + field_36]) + destruct_26]) + field_32]) + field_31]) + destruct_27])) + field_37]) + field_36])))) + destruct_26]) + field_32]) + field_31])))) + destruct_27]) + a_24]) + b_25]))]) + (lam value_23 value_23)]) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_5 (con integer 1)]] [fromInt_5 (con integer 3)]]] + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_5 (con integer 1)]] [fromInt_5 (con integer 2)]]] + (con (list (pair data data)) [])]]]) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_5 (con integer 1)]] [fromInt_5 (con integer 2)]]] + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_5 (con integer 1)]] [fromInt_5 (con integer 3)]]] + (con (list (pair data data)) [])]]]) + (builtin iData)]) +--- result +(constr 0 (con bool True) (con bool False) (con bool True) (con bool False)) +--- logs +[] +--- budget +cpu: 16844054, memory: 43248 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_little_preserves_custom_eq_and_short_circuit.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_little_preserves_custom_eq_and_short_circuit.snap new file mode 100644 index 00000000..460c2bac --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__map_eq_little_preserves_custom_eq_and_short_circuit.snap @@ -0,0 +1,179 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Literal exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\nvalues : map int (list Data)\nvalues = [Builtin.unConstrData (Builtin.constrData 1 []), Builtin.unConstrData (Builtin.constrData 2 [])]\nmain = eq values values\n" +--- +--- core +let message#64 : string = "custom" in +let fromBool#10 : bool -> bool = \value#25 : bool -> value#25 in +let fromString#54 : string -> string = \value#59 : string -> value#59 in +let eq#30 : int -> int -> bool = \arg#52 : int arg#53 : int -> let match#56 : int = arg#52 in +let match#55 : int = arg#53 in +trace (fromString#54 message#64) in fromBool#10 false in +let eq#41 : list 'erased -> list 'erased -> bool = \xs#57 : list 'erased ys#58 : list 'erased -> equalsData (listData xs#57) (listData ys#58) in +let eq#18 : pair 'erased 'erased -> pair 'erased 'erased -> bool = \a#26 : pair 'erased 'erased b#27 : pair 'erased 'erased -> let destruct#28 : pair 'erased 'erased = b#27 in +let destruct#29 : pair 'erased 'erased = a#26 in +let match#33 : pair 'erased 'erased = destruct#29 in +case@Pair match#33 of + Pair field#34 field#35 -> let firstA#31 : 'erased = field#34 in + let secondA#32 : 'erased = field#35 in + let match#38 : pair 'erased 'erased = destruct#28 in + case@Pair match#38 of + Pair field#39 field#40 -> let firstB#36 : 'erased = field#39 in + let secondB#37 : 'erased = field#40 in + case@Bool eq#30 firstA#31 firstB#36 of + True -> let match#44 : pair 'erased 'erased = destruct#29 in + let firstA#42 : 'erased = field#34 in + let secondA#43 : 'erased = field#35 in + let match#49 : pair 'erased 'erased = destruct#28 in + let firstB#47 : 'erased = field#39 in + let secondB#48 : 'erased = field#40 in + eq#41 secondA#43 secondB#48 + False -> false in +let eq#6 : list 'erased -> list 'erased -> bool = (\self#45 : 'erased -> self#45 self#45) (\self#45 : 'erased xs#8 : list 'erased ys#9 : list 'erased -> let match#22 : list 'erased = xs#8 in +case@List match#22 of + Nil -> let match#11 : list 'erased = ys#9 in + case@List match#11 of + Nil -> fromBool#10 true + Cons field#12 field#13 -> fromBool#10 false + Cons field#23 field#24 -> let x#14 : 'erased = field#23 in + let restX#15 : list 'erased = field#24 in + let match#19 : list 'erased = ys#9 in + case@List match#19 of + Nil -> fromBool#10 false + Cons field#20 field#21 -> let y#16 : 'erased = field#20 in + let restY#17 : list 'erased = field#21 in + case@Bool eq#18 x#14 y#16 of + True -> self#45 self#45 restX#15 restY#17 + False -> false) in +let eqMapEntries#4 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#6 in +let eq#2 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eqMapEntries#4 in +let fromInt#5 : int -> int = \value#7 : int -> value#7 in +let evaluated#60 : 'erased = constrData (fromInt#5 1) (con (list data) []) in +let projection#61 : pair int (list Data) = unConstrData evaluated#60 in +let evaluated#62 : 'erased = constrData (fromInt#5 2) (con (list data) []) in +let projection#63 : pair int (list Data) = unConstrData evaluated#62 in +let values#3 : list (pair int (list Data)) = mkCons projection#61 (mkCons projection#63 (con (list (pair integer (list data))) [])) in +let main#1 : bool = eq#2 values#3 values#3 in +main#1 +--- uplc +(program 1.1.0 + [(lam message_64 + [(lam fromBool_10 + [(lam fromString_54 + [(lam eq_30 + [(lam eq_41 + [(lam eq_18 + [(lam eq_6 + [(lam eqMapEntries_4 + [(lam eq_2 + [(lam fromInt_5 + [(lam evaluated_60 + [(lam projection_61 + [(lam evaluated_62 + [(lam projection_63 + [(lam values_3 [(lam main_1 main_1) [[eq_2 values_3] values_3]]) + [[(force (builtin mkCons)) projection_61] + [[(force (builtin mkCons)) projection_63] + (con (list (pair integer (list data))) [])]]]) + [(builtin unConstrData) evaluated_62]]) + [[(builtin constrData) [fromInt_5 (con integer 2)]] (con (list data) [])]]) + [(builtin unConstrData) evaluated_60]]) + [[(builtin constrData) [fromInt_5 (con integer 1)]] (con (list data) [])]]) + (lam value_7 value_7)]) + eqMapEntries_4]) + eq_6]) + [(lam self_45 [self_45 self_45]) + (lam self_45 + (lam xs_8 + (lam ys_9 + [(lam match_22 + (case + match_22 + (lam field_23 + (lam field_24 + [(lam x_14 + [(lam restX_15 + [(lam match_19 + (case + match_19 + (lam field_20 + (lam field_21 + [(lam y_16 + [(lam restY_17 + (case + [[eq_18 x_14] y_16] + (con bool False) + [[[self_45 self_45] restX_15] restY_17])) + field_21]) + field_20])) + [fromBool_10 (con bool False)])) + ys_9]) + field_24]) + field_23])) + [(lam match_11 + (case + match_11 + (lam field_12 (lam field_13 [fromBool_10 (con bool False)])) + [fromBool_10 (con bool True)])) + ys_9])) + xs_8])))]]) + (lam a_26 + (lam b_27 + [(lam destruct_28 + [(lam destruct_29 + [(lam match_33 + (case + match_33 + (lam field_34 + (lam field_35 + [(lam firstA_31 + [(lam secondA_32 + [(lam match_38 + (case + match_38 + (lam field_39 + (lam field_40 + [(lam firstB_36 + [(lam secondB_37 + (case + [[eq_30 firstA_31] firstB_36] + (con bool False) + [(lam match_44 + [(lam firstA_42 + [(lam secondA_43 + [(lam match_49 + [(lam firstB_47 [(lam secondB_48 [[eq_41 secondA_43] secondB_48]) field_40]) + field_39]) + destruct_28]) + field_35]) + field_34]) + destruct_29])) + field_40]) + field_39])))) + destruct_28]) + field_35]) + field_34])))) + destruct_29]) + a_26]) + b_27]))]) + (lam xs_57 + (lam ys_58 + [[(builtin equalsData) [(builtin listData) xs_57]] [(builtin listData) ys_58]]))]) + (lam arg_52 + (lam arg_53 + [(lam match_56 + [(lam match_55 + (force + [[(force (builtin trace)) [fromString_54 message_64]] + (delay [fromBool_10 (con bool False)])])) + arg_53]) + arg_52]))]) + (lam value_59 value_59)]) + (lam value_25 value_25)]) + (con string "custom")]) +--- result +(con bool False) +--- logs +["custom"] +--- budget +cpu: 3209800, memory: 18524 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_literal_implementations_and_default_methods_execute.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_literal_implementations_and_default_methods_execute.snap index 31bf3bee..883d5ae8 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_literal_implementations_and_default_methods_execute.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_literal_implementations_and_default_methods_execute.snap @@ -4,12 +4,13 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport --- --- core let fromBool#2 : bool -> bool = \value#6 : bool -> value#6 in -let eq#9 : int -> int -> bool = equalsInteger in -let neq#3 : 'erased -> 'erased -> bool = \a#7 : 'erased b#8 : 'erased -> case@Bool eq#9 a#7 b#8 of - True -> fromBool#2 false - False -> fromBool#2 true in -let fromInt#4 : int -> int = \value#10 : int -> value#10 in -let same#5 : int -> int -> bool = eq#9 in +let not#9 : 'erased -> bool = \value#12 : 'erased -> case@Bool (\identity#13 : 'erased -> identity#13) value#12 of + True -> false + False -> true in +let eq#10 : int -> int -> bool = equalsInteger in +let neq#3 : 'erased -> 'erased -> bool = \a#7 : 'erased b#8 : 'erased -> not#9 (eq#10 a#7 b#8) in +let fromInt#4 : int -> int = \value#11 : int -> value#11 in +let same#5 : int -> int -> bool = eq#10 in let main#1 : bool = case@Bool neq#3 (addInteger (fromInt#4 20) (fromInt#4 21)) (fromInt#4 42) of True -> same#5 (fromInt#4 42) (fromInt#4 42) False -> fromBool#2 false in @@ -17,31 +18,29 @@ main#1 --- uplc (program 1.1.0 [(lam fromBool_2 - [(lam eq_9 - [(lam neq_3 - [(lam fromInt_4 - [(lam same_5 - [(lam main_1 main_1) - (case - [[neq_3 - [[(builtin addInteger) [fromInt_4 (con integer 20)]] - [fromInt_4 (con integer 21)]]] - [fromInt_4 (con integer 42)]] - [fromBool_2 (con bool False)] - [[same_5 [fromInt_4 (con integer 42)]] [fromInt_4 (con integer 42)]])]) - eq_9]) - (lam value_10 value_10)]) - (lam a_7 - (lam b_8 - (case - [[eq_9 a_7] b_8] - [fromBool_2 (con bool True)] - [fromBool_2 (con bool False)])))]) - (builtin equalsInteger)]) + [(lam not_9 + [(lam eq_10 + [(lam neq_3 + [(lam fromInt_4 + [(lam same_5 + [(lam main_1 main_1) + (case + [[neq_3 + [[(builtin addInteger) [fromInt_4 (con integer 20)]] + [fromInt_4 (con integer 21)]]] + [fromInt_4 (con integer 42)]] + [fromBool_2 (con bool False)] + [[same_5 [fromInt_4 (con integer 42)]] [fromInt_4 (con integer 42)]])]) + eq_10]) + (lam value_11 value_11)]) + (lam a_7 (lam b_8 [not_9 [[eq_10 a_7] b_8]]))]) + (builtin equalsInteger)]) + (lam value_12 + (case [(lam identity_13 identity_13) value_12] (con bool True) (con bool False)))]) (lam value_6 value_6)]) --- result (con bool True) --- logs [] --- budget -cpu: 1149974, memory: 6004 +cpu: 1245974, memory: 6604 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_map_alias_has_distinct_eq.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_map_alias_has_distinct_eq.snap new file mode 100644 index 00000000..c59e3451 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__native_map_alias_has_distinct_eq.snap @@ -0,0 +1,42 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\ntype alias map 'k 'v = list (pair ('k : Big) ('v : Big))\nimpl Eq (map 'k 'v) where\n eq xs ys = eq (Builtin.mapData xs) (Builtin.mapData ys)\nentries : map Int Int\nentries = [Builtin.mkPairData 1 2, Builtin.mkPairData 1 3]\nreversed : map Int Int\nreversed = [Builtin.mkPairData 1 3, Builtin.mkPairData 1 2]\nsame : Eq 'a => 'a -> 'a -> bool\nsame = eq\nmain = (same entries entries, same entries reversed)\n" +--- +--- core +let eq#5 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = \xs#7 : list (pair 'erased 'erased) ys#8 : list (pair 'erased 'erased) -> equalsData (mapData xs#7) (mapData ys#8) in +let same#2 : 'erased -> 'erased -> bool = eq#5 in +let fromInt#6 : int -> Int = iData in +let entries#3 : list (pair Int Int) = mkCons (mkPairData (fromInt#6 1) (fromInt#6 2)) (mkCons (mkPairData (fromInt#6 1) (fromInt#6 3)) (con (list (pair data data)) [])) in +let reversed#4 : list (pair Int Int) = mkCons (mkPairData (fromInt#6 1) (fromInt#6 3)) (mkCons (mkPairData (fromInt#6 1) (fromInt#6 2)) (con (list (pair data data)) [])) in +let main#1 : (bool, bool) = constr 0 (same#2 entries#3 entries#3) (same#2 entries#3 reversed#4) in +main#1 +--- uplc +(program 1.1.0 + [(lam eq_5 + [(lam same_2 + [(lam fromInt_6 + [(lam entries_3 + [(lam reversed_4 + [(lam main_1 main_1) + (constr 0 [[same_2 entries_3] entries_3] [[same_2 entries_3] reversed_4])]) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_6 (con integer 1)]] [fromInt_6 (con integer 3)]]] + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_6 (con integer 1)]] [fromInt_6 (con integer 2)]]] + (con (list (pair data data)) [])]]]) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_6 (con integer 1)]] [fromInt_6 (con integer 2)]]] + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_6 (con integer 1)]] [fromInt_6 (con integer 3)]]] + (con (list (pair data data)) [])]]]) + (builtin iData)]) + eq_5]) + (lam xs_7 + (lam ys_8 + [[(builtin equalsData) [(builtin mapData) xs_7]] [(builtin mapData) ys_8]]))]) +--- result +(constr 0 (con bool True) (con bool False)) +--- logs +[] +--- budget +cpu: 5452796, memory: 10842 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_eq_all_representation_classes.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_eq_all_representation_classes.snap new file mode 100644 index 00000000..5e7ff688 --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_eq_all_representation_classes.snap @@ -0,0 +1,440 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nbigBig : map Int Int\nbigBig = [Builtin.mkPairData 1 2]\nbigLittle : map Int int\nbigLittle = []\nlittleBig : map int Int\nlittleBig = []\nlittleLittle : map int (list Data)\nlittleLittle = [Builtin.unConstrData (Builtin.constrData 1 [])]\ndifferent : map int (list Data)\ndifferent = [Builtin.unConstrData (Builtin.constrData 2 [])]\nsame : Eq (map 'k 'v) => map 'k 'v -> map 'k 'v -> bool\nsame = eq\nmain =\n ( same bigBig bigBig\n , same bigLittle bigLittle\n , same littleBig littleBig\n , same littleLittle different\n )\n" +--- +--- core +let eq#11 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = \xs#17 : list (pair 'erased 'erased) ys#18 : list (pair 'erased 'erased) -> equalsData (mapData xs#17) (mapData ys#18) in +let same#2 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#11 in +let fromInt#12 : int -> Int = iData in +let bigBig#3 : list (pair Int Int) = mkCons (mkPairData (fromInt#12 1) (fromInt#12 2)) (con (list (pair data data)) []) in +let fromBool#28 : bool -> bool = \value#75 : bool -> value#75 in +let eq#90 : int -> int -> bool = equalsInteger in +let eq#36 : pair 'erased 'erased -> pair 'erased 'erased -> bool = \a#76 : pair 'erased 'erased b#77 : pair 'erased 'erased -> let destruct#78 : pair 'erased 'erased = b#77 in +let destruct#79 : pair 'erased 'erased = a#76 in +let match#82 : pair 'erased 'erased = destruct#79 in +case@Pair match#82 of + Pair field#83 field#84 -> let firstA#80 : 'erased = field#83 in + let secondA#81 : 'erased = field#84 in + let match#87 : pair 'erased 'erased = destruct#78 in + case@Pair match#87 of + Pair field#88 field#89 -> let firstB#85 : 'erased = field#88 in + let secondB#86 : 'erased = field#89 in + case@Bool equalsData firstA#80 firstB#85 of + True -> let match#93 : pair 'erased 'erased = destruct#79 in + let firstA#91 : 'erased = field#83 in + let secondA#92 : 'erased = field#84 in + let match#98 : pair 'erased 'erased = destruct#78 in + let firstB#96 : 'erased = field#88 in + let secondB#97 : 'erased = field#89 in + eq#90 secondA#92 secondB#97 + False -> false in +let eq#23 : list 'erased -> list 'erased -> bool = (\self#123 : 'erased -> self#123 self#123) (\self#123 : 'erased xs#26 : list 'erased ys#27 : list 'erased -> let match#40 : list 'erased = xs#26 in +case@List match#40 of + Nil -> let match#29 : list 'erased = ys#27 in + case@List match#29 of + Nil -> fromBool#28 true + Cons field#30 field#31 -> fromBool#28 false + Cons field#41 field#42 -> let x#32 : 'erased = field#41 in + let restX#33 : list 'erased = field#42 in + let match#37 : list 'erased = ys#27 in + case@List match#37 of + Nil -> fromBool#28 false + Cons field#38 field#39 -> let y#34 : 'erased = field#38 in + let restY#35 : list 'erased = field#39 in + case@Bool eq#36 x#32 y#34 of + True -> self#123 self#123 restX#33 restY#35 + False -> false) in +let eqMapEntries#19 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#23 in +let eq#13 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eqMapEntries#19 in +let same#4 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#13 in +let bigLittle#5 : list (pair Int int) = (con (list (pair data integer)) []) in +let eq#52 : pair 'erased 'erased -> pair 'erased 'erased -> bool = \a#101 : pair 'erased 'erased b#102 : pair 'erased 'erased -> let destruct#103 : pair 'erased 'erased = b#102 in +let destruct#104 : pair 'erased 'erased = a#101 in +let match#107 : pair 'erased 'erased = destruct#104 in +case@Pair match#107 of + Pair field#108 field#109 -> let firstA#105 : 'erased = field#108 in + let secondA#106 : 'erased = field#109 in + let match#112 : pair 'erased 'erased = destruct#103 in + case@Pair match#112 of + Pair field#113 field#114 -> let firstB#110 : 'erased = field#113 in + let secondB#111 : 'erased = field#114 in + case@Bool eq#90 firstA#105 firstB#110 of + True -> let match#117 : pair 'erased 'erased = destruct#104 in + let firstA#115 : 'erased = field#108 in + let secondA#116 : 'erased = field#109 in + let match#122 : pair 'erased 'erased = destruct#103 in + let firstB#120 : 'erased = field#113 in + let secondB#121 : 'erased = field#114 in + equalsData secondA#116 secondB#121 + False -> false in +let eq#24 : list 'erased -> list 'erased -> bool = (\self#100 : 'erased -> self#100 self#100) (\self#100 : 'erased xs#43 : list 'erased ys#44 : list 'erased -> let match#56 : list 'erased = xs#43 in +case@List match#56 of + Nil -> let match#45 : list 'erased = ys#44 in + case@List match#45 of + Nil -> fromBool#28 true + Cons field#46 field#47 -> fromBool#28 false + Cons field#57 field#58 -> let x#48 : 'erased = field#57 in + let restX#49 : list 'erased = field#58 in + let match#53 : list 'erased = ys#44 in + case@List match#53 of + Nil -> fromBool#28 false + Cons field#54 field#55 -> let y#50 : 'erased = field#54 in + let restY#51 : list 'erased = field#55 in + case@Bool eq#52 x#48 y#50 of + True -> self#100 self#100 restX#49 restY#51 + False -> false) in +let eqMapEntries#20 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#24 in +let eq#14 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eqMapEntries#20 in +let same#6 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#14 in +let littleBig#7 : list (pair int Int) = (con (list (pair integer data)) []) in +let eq#139 : list 'erased -> list 'erased -> bool = \xs#150 : list 'erased ys#151 : list 'erased -> equalsData (listData xs#150) (listData ys#151) in +let eq#68 : pair 'erased 'erased -> pair 'erased 'erased -> bool = \a#125 : pair 'erased 'erased b#126 : pair 'erased 'erased -> let destruct#127 : pair 'erased 'erased = b#126 in +let destruct#128 : pair 'erased 'erased = a#125 in +let match#131 : pair 'erased 'erased = destruct#128 in +case@Pair match#131 of + Pair field#132 field#133 -> let firstA#129 : 'erased = field#132 in + let secondA#130 : 'erased = field#133 in + let match#136 : pair 'erased 'erased = destruct#127 in + case@Pair match#136 of + Pair field#137 field#138 -> let firstB#134 : 'erased = field#137 in + let secondB#135 : 'erased = field#138 in + case@Bool eq#90 firstA#129 firstB#134 of + True -> let match#142 : pair 'erased 'erased = destruct#128 in + let firstA#140 : 'erased = field#132 in + let secondA#141 : 'erased = field#133 in + let match#147 : pair 'erased 'erased = destruct#127 in + let firstB#145 : 'erased = field#137 in + let secondB#146 : 'erased = field#138 in + eq#139 secondA#141 secondB#146 + False -> false in +let eq#25 : list 'erased -> list 'erased -> bool = (\self#94 : 'erased -> self#94 self#94) (\self#94 : 'erased xs#59 : list 'erased ys#60 : list 'erased -> let match#72 : list 'erased = xs#59 in +case@List match#72 of + Nil -> let match#61 : list 'erased = ys#60 in + case@List match#61 of + Nil -> fromBool#28 true + Cons field#62 field#63 -> fromBool#28 false + Cons field#73 field#74 -> let x#64 : 'erased = field#73 in + let restX#65 : list 'erased = field#74 in + let match#69 : list 'erased = ys#60 in + case@List match#69 of + Nil -> fromBool#28 false + Cons field#70 field#71 -> let y#66 : 'erased = field#70 in + let restY#67 : list 'erased = field#71 in + case@Bool eq#68 x#64 y#66 of + True -> self#94 self#94 restX#65 restY#67 + False -> false) in +let eqMapEntries#21 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#25 in +let eq#15 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eqMapEntries#21 in +let same#8 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = eq#15 in +let fromInt#16 : int -> int = \value#22 : int -> value#22 in +let evaluated#152 : 'erased = constrData (fromInt#16 1) (con (list data) []) in +let projection#153 : pair int (list Data) = unConstrData evaluated#152 in +let littleLittle#9 : list (pair int (list Data)) = mkCons projection#153 (con (list (pair integer (list data))) []) in +let evaluated#154 : 'erased = constrData (fromInt#16 2) (con (list data) []) in +let projection#155 : pair int (list Data) = unConstrData evaluated#154 in +let different#10 : list (pair int (list Data)) = mkCons projection#155 (con (list (pair integer (list data))) []) in +let main#1 : (bool, bool, bool, bool) = constr 0 (same#2 bigBig#3 bigBig#3) (same#4 bigLittle#5 bigLittle#5) (same#6 littleBig#7 littleBig#7) (same#8 littleLittle#9 different#10) in +main#1 +--- uplc +(program 1.1.0 + [(lam eq_11 + [(lam same_2 + [(lam fromInt_12 + [(lam bigBig_3 + [(lam fromBool_28 + [(lam eq_90 + [(lam eq_36 + [(lam eq_23 + [(lam eqMapEntries_19 + [(lam eq_13 + [(lam same_4 + [(lam bigLittle_5 + [(lam eq_52 + [(lam eq_24 + [(lam eqMapEntries_20 + [(lam eq_14 + [(lam same_6 + [(lam littleBig_7 + [(lam eq_139 + [(lam eq_68 + [(lam eq_25 + [(lam eqMapEntries_21 + [(lam eq_15 + [(lam same_8 + [(lam fromInt_16 + [(lam evaluated_152 + [(lam projection_153 + [(lam littleLittle_9 + [(lam evaluated_154 + [(lam projection_155 + [(lam different_10 + [(lam main_1 main_1) + (constr 0 + [[same_2 bigBig_3] bigBig_3] + [[same_4 bigLittle_5] bigLittle_5] + [[same_6 littleBig_7] littleBig_7] + [[same_8 littleLittle_9] different_10])]) + [[(force (builtin mkCons)) projection_155] + (con (list (pair integer (list data))) [])]]) + [(builtin unConstrData) evaluated_154]]) + [[(builtin constrData) [fromInt_16 (con integer 2)]] (con (list data) [])]]) + [[(force (builtin mkCons)) projection_153] + (con (list (pair integer (list data))) [])]]) + [(builtin unConstrData) evaluated_152]]) + [[(builtin constrData) [fromInt_16 (con integer 1)]] (con (list data) [])]]) + (lam value_22 value_22)]) + eq_15]) + eqMapEntries_21]) + eq_25]) + [(lam self_94 [self_94 self_94]) + (lam self_94 + (lam xs_59 + (lam ys_60 + [(lam match_72 + (case + match_72 + (lam field_73 + (lam field_74 + [(lam x_64 + [(lam restX_65 + [(lam match_69 + (case + match_69 + (lam field_70 + (lam field_71 + [(lam y_66 + [(lam restY_67 + (case + [[eq_68 x_64] y_66] + (con bool False) + [[[self_94 self_94] restX_65] restY_67])) + field_71]) + field_70])) + [fromBool_28 (con bool False)])) + ys_60]) + field_74]) + field_73])) + [(lam match_61 + (case + match_61 + (lam field_62 (lam field_63 [fromBool_28 (con bool False)])) + [fromBool_28 (con bool True)])) + ys_60])) + xs_59])))]]) + (lam a_125 + (lam b_126 + [(lam destruct_127 + [(lam destruct_128 + [(lam match_131 + (case + match_131 + (lam field_132 + (lam field_133 + [(lam firstA_129 + [(lam secondA_130 + [(lam match_136 + (case + match_136 + (lam field_137 + (lam field_138 + [(lam firstB_134 + [(lam secondB_135 + (case + [[eq_90 firstA_129] firstB_134] + (con bool False) + [(lam match_142 + [(lam firstA_140 + [(lam secondA_141 + [(lam match_147 + [(lam firstB_145 + [(lam secondB_146 [[eq_139 secondA_141] secondB_146]) field_138]) + field_137]) + destruct_127]) + field_133]) + field_132]) + destruct_128])) + field_138]) + field_137])))) + destruct_127]) + field_133]) + field_132])))) + destruct_128]) + a_125]) + b_126]))]) + (lam xs_150 + (lam ys_151 + [[(builtin equalsData) [(builtin listData) xs_150]] [(builtin listData) ys_151]]))]) + (con (list (pair integer data)) [])]) + eq_14]) + eqMapEntries_20]) + eq_24]) + [(lam self_100 [self_100 self_100]) + (lam self_100 + (lam xs_43 + (lam ys_44 + [(lam match_56 + (case + match_56 + (lam field_57 + (lam field_58 + [(lam x_48 + [(lam restX_49 + [(lam match_53 + (case + match_53 + (lam field_54 + (lam field_55 + [(lam y_50 + [(lam restY_51 + (case + [[eq_52 x_48] y_50] + (con bool False) + [[[self_100 self_100] restX_49] restY_51])) + field_55]) + field_54])) + [fromBool_28 (con bool False)])) + ys_44]) + field_58]) + field_57])) + [(lam match_45 + (case + match_45 + (lam field_46 (lam field_47 [fromBool_28 (con bool False)])) + [fromBool_28 (con bool True)])) + ys_44])) + xs_43])))]]) + (lam a_101 + (lam b_102 + [(lam destruct_103 + [(lam destruct_104 + [(lam match_107 + (case + match_107 + (lam field_108 + (lam field_109 + [(lam firstA_105 + [(lam secondA_106 + [(lam match_112 + (case + match_112 + (lam field_113 + (lam field_114 + [(lam firstB_110 + [(lam secondB_111 + (case + [[eq_90 firstA_105] firstB_110] + (con bool False) + [(lam match_117 + [(lam firstA_115 + [(lam secondA_116 + [(lam match_122 + [(lam firstB_120 + [(lam secondB_121 [[(builtin equalsData) secondA_116] secondB_121]) field_114]) + field_113]) + destruct_103]) + field_109]) + field_108]) + destruct_104])) + field_114]) + field_113])))) + destruct_103]) + field_109]) + field_108])))) + destruct_104]) + a_101]) + b_102]))]) + (con (list (pair data integer)) [])]) + eq_13]) + eqMapEntries_19]) + eq_23]) + [(lam self_123 [self_123 self_123]) + (lam self_123 + (lam xs_26 + (lam ys_27 + [(lam match_40 + (case + match_40 + (lam field_41 + (lam field_42 + [(lam x_32 + [(lam restX_33 + [(lam match_37 + (case + match_37 + (lam field_38 + (lam field_39 + [(lam y_34 + [(lam restY_35 + (case + [[eq_36 x_32] y_34] + (con bool False) + [[[self_123 self_123] restX_33] restY_35])) + field_39]) + field_38])) + [fromBool_28 (con bool False)])) + ys_27]) + field_42]) + field_41])) + [(lam match_29 + (case + match_29 + (lam field_30 (lam field_31 [fromBool_28 (con bool False)])) + [fromBool_28 (con bool True)])) + ys_27])) + xs_26])))]]) + (lam a_76 + (lam b_77 + [(lam destruct_78 + [(lam destruct_79 + [(lam match_82 + (case + match_82 + (lam field_83 + (lam field_84 + [(lam firstA_80 + [(lam secondA_81 + [(lam match_87 + (case + match_87 + (lam field_88 + (lam field_89 + [(lam firstB_85 + [(lam secondB_86 + (case + [[(builtin equalsData) firstA_80] firstB_85] + (con bool False) + [(lam match_93 + [(lam firstA_91 + [(lam secondA_92 + [(lam match_98 + [(lam firstB_96 [(lam secondB_97 [[eq_90 secondA_92] secondB_97]) field_89]) + field_88]) + destruct_78]) + field_84]) + field_83]) + destruct_79])) + field_89]) + field_88])))) + destruct_78]) + field_84]) + field_83])))) + destruct_79]) + a_76]) + b_77]))]) + (builtin equalsInteger)]) + (lam value_75 value_75)]) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_12 (con integer 1)]] + [fromInt_12 (con integer 2)]]] + (con (list (pair data data)) [])]]) + (builtin iData)]) + eq_11]) + (lam xs_17 + (lam ys_18 + [[(builtin equalsData) [(builtin mapData) xs_17]] [(builtin mapData) ys_18]]))]) +--- result +(constr 0 (con bool True) (con bool True) (con bool True) (con bool False)) +--- logs +[] +--- budget +cpu: 6461687, memory: 29486 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_unwrap_retains_structural_eq.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_unwrap_retains_structural_eq.snap new file mode 100644 index 00000000..a1aa571e --- /dev/null +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__primitive_map_unwrap_retains_structural_eq.snap @@ -0,0 +1,32 @@ +--- +source: crates/nash-codegen/src/build/tests.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nencoded : Map Int Int\nencoded = Builtin.mapData [Builtin.mkPairData 1 2]\nnative = Builtin.unMapData encoded\nmain = eq native native\n" +--- +--- core +let eq#2 : list (pair 'erased 'erased) -> list (pair 'erased 'erased) -> bool = \xs#4 : list (pair 'erased 'erased) ys#5 : list (pair 'erased 'erased) -> equalsData (mapData xs#4) (mapData ys#5) in +let fromInt#7 : int -> Int = iData in +let encoded#6 : Map Int Int = mapData (mkCons (mkPairData (fromInt#7 1) (fromInt#7 2)) (con (list (pair data data)) [])) in +let native#3 : list (pair Int Int) = unMapData encoded#6 in +let main#1 : bool = eq#2 native#3 native#3 in +main#1 +--- uplc +(program 1.1.0 + [(lam eq_2 + [(lam fromInt_7 + [(lam encoded_6 + [(lam native_3 [(lam main_1 main_1) [[eq_2 native_3] native_3]]) + [(builtin unMapData) encoded_6]]) + [(builtin mapData) + [[(force (builtin mkCons)) + [[(builtin mkPairData) [fromInt_7 (con integer 1)]] [fromInt_7 (con integer 2)]]] + (con (list (pair data data)) [])]]]) + (builtin iData)]) + (lam xs_4 + (lam ys_5 + [[(builtin equalsData) [(builtin mapData) xs_4]] [(builtin mapData) ys_5]]))]) +--- result +(con bool True) +--- logs +[] +--- budget +cpu: 2376021, memory: 5057 diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__source_trait_default_specialization.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__source_trait_default_specialization.snap index 8a85186d..063e4d0d 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__source_trait_default_specialization.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__source_trait_default_specialization.snap @@ -3,13 +3,14 @@ source: crates/nash-codegen/src/build/tests.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\nmain = neq () ()\n" --- --- core -let fromBool#6 : bool -> bool = \value#9 : bool -> value#9 in -let eq#7 : unit -> unit -> bool = \arg#10 : unit arg#11 : unit -> let match#13 : unit = arg#10 in -let match#12 : unit = arg#11 in -fromBool#6 true in -let neq#2 : 'erased -> 'erased -> bool = \a#4 : 'erased b#5 : 'erased -> case@Bool eq#7 a#4 b#5 of - True -> fromBool#6 false - False -> fromBool#6 true in +let not#6 : 'erased -> bool = \value#9 : 'erased -> case@Bool (\identity#10 : 'erased -> identity#10) value#9 of + True -> false + False -> true in +let fromBool#13 : bool -> bool = \value#16 : bool -> value#16 in +let eq#7 : unit -> unit -> bool = \arg#11 : unit arg#12 : unit -> let match#15 : unit = arg#11 in +let match#14 : unit = arg#12 in +fromBool#13 true in +let neq#2 : 'erased -> 'erased -> bool = \a#4 : 'erased b#5 : 'erased -> not#6 (eq#7 a#4 b#5) in let fromUnit#3 : unit -> unit = \value#8 : unit -> value#8 in let main#1 : bool = neq#2 (fromUnit#3 ()) (fromUnit#3 ()) in main#1 @@ -18,8 +19,10 @@ main#1 [(lam i0 [(lam i1 [(lam i2 - [(lam i3 [(lam i4 i4) [[i2 [i3 (con unit ())]] [i3 (con unit ())]]]) - (lam i3 i3)]) - (lam i2 (lam i3 (case [[i1 i2] i3] [i0 (con bool True)] [i0 (con bool False)])))]) - (lam i1 (lam i2 [(lam i3 [(lam i4 [i0 (con bool True)]) i2]) i1]))]) - (lam i0 i0)]) + [(lam i3 + [(lam i4 [(lam i5 i5) [[i3 [i4 (con unit ())]] [i4 (con unit ())]]]) + (lam i4 i4)]) + (lam i3 (lam i4 [i0 [[i2 i3] i4]]))]) + (lam i2 (lam i3 (case i2 (case i3 [i1 (con bool True)]))))]) + (lam i1 i1)]) + (lam i0 (case [(lam i1 i1) i0] (con bool True) (con bool False)))]) diff --git a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__transparent_alias_method_variables_are_matched_after_expansion.snap b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__transparent_alias_method_variables_are_matched_after_expansion.snap index 06f08294..57982a4d 100644 --- a/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__transparent_alias_method_variables_are_matched_after_expansion.snap +++ b/crates/nash-codegen/src/build/snapshots/nash_codegen__build__tests__transparent_alias_method_variables_are_matched_after_expansion.snap @@ -16,10 +16,10 @@ main#1 [(lam raw_4 [(lam main_1 main_1) [[keep_2 [fromUnit_3 (con unit ())]] raw_4]]) [fromUnit_3 (con unit ())]]) (lam value_8 value_8)]) - (lam arg_5 (lam x_6 [(lam match_7 x_6) arg_5]))]) + (lam arg_5 (lam x_6 (case arg_5 x_6)))]) --- result (con unit ()) --- logs [] --- budget -cpu: 448100, memory: 2900 +cpu: 432100, memory: 2800 diff --git a/crates/nash-codegen/src/build/tests.rs b/crates/nash-codegen/src/build/tests.rs index 811c4a76..9f722fb0 100644 --- a/crates/nash-codegen/src/build/tests.rs +++ b/crates/nash-codegen/src/build/tests.rs @@ -3,6 +3,7 @@ use nash_ast::primitives; use std::collections::BTreeMap; mod source; +mod wildcard_cases; fn fixture<'a>(arena: &'a Arena, source: &str) -> (nash_can::CanResult<'a>, SolvedTypes<'a>) { fixture_in(arena, source, None) @@ -144,10 +145,26 @@ fn with_base_modules( source: &str, extra_modules: &[&str], check: impl FnOnce(&Arena, &Build<'_, '_>, QualifiedName<'_>), +) { + with_base_eq( + source, + include_str!("../../../nash-driver/base/src/Eq.nash"), + extra_modules, + check, + ); +} + +fn with_base_eq( + source: &str, + eq_source: &str, + extra_modules: &[&str], + check: impl FnOnce(&Arena, &Build<'_, '_>, QualifiedName<'_>), ) { let modules: Vec<_> = [ include_str!("../../../nash-driver/base/src/Literal.nash"), - include_str!("../../../nash-driver/base/src/Eq.nash"), + include_str!("../../../nash-driver/base/src/Lift.nash"), + include_str!("../../../nash-driver/base/src/Logic.nash"), + eq_source, ] .into_iter() .chain(extra_modules.iter().copied()) @@ -476,7 +493,7 @@ fn generic_impl_context_default_and_superclass_evidence_are_closed() { same : 'a -> 'a -> bool same x y = eq x y impl Same int where - impl Eq 'a => Same (list 'a) where + impl Eq (list 'a) => Same (list 'a) where use : Same 'a => 'a -> 'a -> bool use x y = if same x y then neq x y else True main = use [1, 2] [1, 3] @@ -1791,3 +1808,267 @@ source_codegen_snapshot!( "#, "(constr 0 (con data (I 1)) (con data (I 4)) (con data (I 5)) (con data (I 4)))" ); + +#[test] +fn list_eq_generic_big_and_little() { + let result = core_eval( + "list_eq_generic_big_and_little", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + same : Eq (list 'a) => list 'a -> list 'a -> bool + same xs ys = eq xs ys + big : list Int + big = [1, 2] + small : list int + small = [1, 2] + main = if same big big then same small small else False + "# + ), + ); + assert_eq!(result.result, "(con bool True)"); + assert!(result.logs.is_empty()); +} + +#[test] +fn list_eq_big_structural_cases() { + let result = core_eval( + "list_eq_big_structural_cases", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + same : list Int -> list Int -> bool + same = eq + main = + ( same [] [] + , same [1, 2] [1, 2] + , same [1, 2] [1, 3] + , same [1] [1, 2] + , same [1, 2] [2, 1] + ) + "# + ), + ); + assert_eq!( + result + .result + .split_whitespace() + .collect::>() + .join(" "), + "(constr 0 (con bool True) (con bool True) (con bool False) (con bool False) (con bool False))" + ); + assert!(result.logs.is_empty()); +} + +#[test] +fn list_eq_little_preserves_custom_eq_and_short_circuit() { + // A trait-owner fixture gives a storable little type nonstructural equality. + let eq_source = include_str!("../../../nash-driver/base/src/Eq.nash").replace( + "eq = Builtin.equalsInteger", + "eq _ _ = trace \"custom\" False", + ); + with_base_eq( + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Literal exposing (..) + import Eq exposing (..) + values : list int + values = [1, 2] + main = eq values values + "# + ), + &eq_source, + &[], + |arena, build, root| { + let compiled = build + .compile(arena, root, None, TraceConfig::default()) + .unwrap(); + let core = + crate::recursion::rewrite(&nash_ir::build::Builder::new(arena), compiled.core) + .unwrap(); + let result = crate::harness::eval_core(arena, core); + assert_eq!(result.result, "(con bool False)"); + assert_eq!(result.logs, ["custom"]); + insta::assert_snapshot!(format!( + "--- core\n{}\n{result}", + nash_ir::pretty::pretty(core) + )); + }, + ); +} + +#[test] +fn map_eq_big_and_native_preserve_entry_order() { + let result = core_eval( + "map_eq_big_and_native_preserve_entry_order", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + entries : list (pair Int Int) + entries = [Builtin.mkPairData 1 2, Builtin.mkPairData 1 3] + reversed : list (pair Int Int) + reversed = [Builtin.mkPairData 1 3, Builtin.mkPairData 1 2] + main = + ( eq (Builtin.mapData entries) (Builtin.mapData entries) + , eq (Builtin.mapData entries) (Builtin.mapData reversed) + , eq entries entries + , eq entries reversed + ) + "# + ), + ); + assert_eq!( + result + .result + .split_whitespace() + .collect::>() + .join(" "), + "(constr 0 (con bool True) (con bool False) (con bool True) (con bool False))" + ); + assert!(result.logs.is_empty()); +} + +#[test] +fn native_map_alias_has_distinct_eq() { + let result = core_eval( + "native_map_alias_has_distinct_eq", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + type alias entriesMap 'k 'v = list (pair ('k : Big) ('v : Big)) + impl Eq (entriesMap 'k 'v) where + eq xs ys = eq (Builtin.mapData xs) (Builtin.mapData ys) + entries : entriesMap Int Int + entries = [Builtin.mkPairData 1 2, Builtin.mkPairData 1 3] + reversed : entriesMap Int Int + reversed = [Builtin.mkPairData 1 3, Builtin.mkPairData 1 2] + same : Eq 'a => 'a -> 'a -> bool + same = eq + main = (same entries entries, same entries reversed) + "# + ), + ); + assert_eq!(result.result, "(constr 0 (con bool True) (con bool False))"); + assert!(result.logs.is_empty()); +} + +#[test] +fn primitive_map_unwrap_retains_structural_eq() { + let result = core_eval( + "primitive_map_unwrap_retains_structural_eq", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + encoded : Map Int Int + encoded = Builtin.mapData [Builtin.mkPairData 1 2] + native = Builtin.unMapData encoded + main = eq native native + "# + ), + ); + assert_eq!(result.result, "(con bool True)"); +} + +#[test] +fn primitive_map_eq_all_representation_classes() { + let result = core_eval( + "primitive_map_eq_all_representation_classes", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + import Literal exposing (..) + import Eq exposing (..) + bigBig : map Int Int + bigBig = [Builtin.mkPairData 1 2] + bigLittle : map Int int + bigLittle = [] + littleBig : map int Int + littleBig = [] + littleLittle : map int (list Data) + littleLittle = [Builtin.unConstrData (Builtin.constrData 1 [])] + different : map int (list Data) + different = [Builtin.unConstrData (Builtin.constrData 2 [])] + same : Eq (map 'k 'v) => map 'k 'v -> map 'k 'v -> bool + same = eq + main = + ( same bigBig bigBig + , same bigLittle bigLittle + , same littleBig littleBig + , same littleLittle different + ) + "# + ), + ); + assert_eq!( + result + .result + .split_whitespace() + .collect::>() + .join(" "), + "(constr 0 (con bool True) (con bool True) (con bool True) (con bool False))" + ); +} + +#[test] +fn map_eq_little_preserves_custom_eq_and_short_circuit() { + // A trait-owner fixture gives a storable little type nonstructural equality. + let eq_source = include_str!("../../../nash-driver/base/src/Eq.nash").replace( + "eq = Builtin.equalsInteger", + "eq _ _ = trace \"custom\" False", + ); + with_base_eq( + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Literal exposing (..) + import Builtin exposing (..) + import Eq exposing (..) + values : map int (list Data) + values = [Builtin.unConstrData (Builtin.constrData 1 []), Builtin.unConstrData (Builtin.constrData 2 [])] + main = eq values values + "# + ), + &eq_source, + &[], + |arena, build, root| { + let compiled = build + .compile(arena, root, None, TraceConfig::default()) + .unwrap(); + let core = + crate::recursion::rewrite(&nash_ir::build::Builder::new(arena), compiled.core) + .unwrap(); + let result = crate::harness::eval_core(arena, core); + assert_eq!(result.result, "(con bool False)"); + assert_eq!(result.logs, ["custom"]); + insta::assert_snapshot!(format!( + "--- core\n{}\n{result}", + nash_ir::pretty::pretty(core) + )); + }, + ); +} diff --git a/crates/nash-codegen/src/build/tests/source.rs b/crates/nash-codegen/src/build/tests/source.rs index 7a8da9ec..d03a35b0 100644 --- a/crates/nash-codegen/src/build/tests/source.rs +++ b/crates/nash-codegen/src/build/tests/source.rs @@ -1,6 +1,5 @@ const BASE_MODULES: &[&str] = &[ include_str!("../../../../nash-driver/base/src/Function.nash"), - include_str!("../../../../nash-driver/base/src/Lift.nash"), include_str!("../../../../nash-driver/base/src/Bool.nash"), include_str!("../../../../nash-driver/base/src/Unit.nash"), include_str!("../../../../nash-driver/base/src/Ordering.nash"), diff --git a/crates/nash-codegen/src/build/tests/source/builtins.rs b/crates/nash-codegen/src/build/tests/source/builtins.rs index 643cf181..94dff219 100644 --- a/crates/nash-codegen/src/build/tests/source/builtins.rs +++ b/crates/nash-codegen/src/build/tests/source/builtins.rs @@ -610,11 +610,11 @@ case!( module Main exposing (..) import Primitive exposing (..) import Lift exposing (Lift) - entries : list (pair Int (List Data)) + entries : map Int (List Data) entries = [Builtin.mkPairData (Builtin.iData 7) (Builtin.listData [I 42])] wrapped : Map Int (List Data) wrapped = lift entries - decoded : list (pair Int (List Data)) + decoded : map Int (List Data) decoded = lower wrapped main : int main = diff --git a/crates/nash-codegen/src/build/tests/source/patterns.rs b/crates/nash-codegen/src/build/tests/source/patterns.rs index dcd55270..c397d58f 100644 --- a/crates/nash-codegen/src/build/tests/source/patterns.rs +++ b/crates/nash-codegen/src/build/tests/source/patterns.rs @@ -1,3 +1,16 @@ +case!( + native_unit_case_sequences_subject_before_body, + r#" + module Main exposing (..) + import Primitive exposing (..) + main : int + main = + case trace "subject" () of + () -> trace "body" 42 +"#, + Ok("(con integer 42)") +); + case!( expect_empty_list_on_filled_list, r#" @@ -387,7 +400,7 @@ case!( } main = let - emptyPairs : list (pair Bytes (Map Bytes Int)) + emptyPairs : map Bytes (Map Bytes Int) emptyPairs = [] prevOutput : Output prevOutput = @@ -425,7 +438,7 @@ case!( } main = let - emptyPairs : list (pair Bytes (Map Bytes Int)) + emptyPairs : map Bytes (Map Bytes Int) emptyPairs = [] prevOutput : Output prevOutput = @@ -463,7 +476,7 @@ case!( } main = let - emptyPairs : list (pair Bytes (Map Bytes Int)) + emptyPairs : map Bytes (Map Bytes Int) emptyPairs = [] prevOutput : Output prevOutput = @@ -798,14 +811,15 @@ case!( module Main exposing (..) import Primitive exposing (type bool(..)) import Bool + import Logic import Lift exposing (Lift) both : (Lift bool 'a, Lift bool 'b) => 'a -> 'b -> bool - both a b = Bool.and a b + both a b = Logic.and a b bad : unit -> Bool.Bool bad _ = fail main : bool main = - if Bool.or Bool.True (bad ()) then + if Logic.or Bool.True (bad ()) then both Bool.True True else False "#, @@ -818,13 +832,14 @@ case!( module Main exposing (..) import Primitive exposing (type bool(..)) import Bool + import Logic bad : unit -> Bool.Bool bad _ = fail main : bool main = let partial : Bool.Bool -> bool - partial = Bool.or Bool.True + partial = Logic.or Bool.True in partial (bad ()) "#, @@ -837,6 +852,7 @@ case!( module Main exposing (..) import Primitive exposing (type bool(..), coerce) import Bool + import Logic import Lift exposing (Lift) type alias flag = bool impl Lift bool flag where @@ -845,9 +861,9 @@ case!( off : flag off = coerce True both : (Lift bool 'a, Lift bool 'b) => 'a -> 'b -> bool - both a b = Bool.and a b + both a b = Logic.and a b main : bool - main = if Bool.and off True then True else both off True + main = if Logic.and off True then True else both off True "#, Ok("(con bool False)") ); @@ -858,6 +874,7 @@ case!( module Main exposing (..) import Primitive exposing (type bool(..), coerce) import Bool + import Logic import Lift exposing (Lift) type alias flag = bool impl Lift bool flag where @@ -866,7 +883,7 @@ case!( value : flag value = coerce False main : bool - main = Bool.or True value + main = Logic.or True value "#, Ok("(con bool True)") ); @@ -876,6 +893,7 @@ case!( r#" module Main exposing (..) import Bool + import Logic import Lift exposing (Lift) make : bool -> Bool.Bool make = lift diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_in_silent_and_verbose.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_in_silent_and_verbose.snap index c82a7944..1a581be7 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_in_silent_and_verbose.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_in_silent_and_verbose.snap @@ -20,7 +20,7 @@ case@List match#19 of let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of True -> self#28 self#28 restX#12 restY#14 - False -> fromBool#7 false) in + False -> false) in let fromAssetList#4 : list int -> list int = \inner#22 : list int -> let match#24 : list int = inner#22 in case@List match#24 of Nil -> error @@ -61,7 +61,7 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] + (con bool False) [[[self_28 self_28] restX_12] restY_14])) field_18]) field_17])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_silent.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_silent.snap index c82a7944..1a581be7 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_silent.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__expect_non_empty_list_with_as_binding_fails_silent.snap @@ -20,7 +20,7 @@ case@List match#19 of let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of True -> self#28 self#28 restX#12 restY#14 - False -> fromBool#7 false) in + False -> false) in let fromAssetList#4 : list int -> list int = \inner#22 : list int -> let match#24 : list int = inner#22 in case@List match#24 of Nil -> error @@ -61,7 +61,7 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] + (con bool False) [[[self_28 self_28] restX_12] restY_14])) field_18]) field_17])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__mk_cons_direct_invoke_1.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__mk_cons_direct_invoke_1.snap index 0f569861..b9a09987 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__mk_cons_direct_invoke_1.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__builtins__mk_cons_direct_invoke_1.snap @@ -20,7 +20,7 @@ case@List match#19 of let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of True -> self#24 self#24 restX#12 restY#14 - False -> fromBool#7 false) in + False -> false) in let fromInt#3 : int -> int = \value#22 : int -> value#22 in let expected#4 : list int = mkCons (fromInt#3 1) (con (list integer) []) in let main#1 : bool = eq#2 (mkCons (fromInt#3 1) (con (list integer) [])) expected#4 in @@ -58,7 +58,7 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] + (con bool False) [[[self_24 self_24] restX_12] restY_14])) field_18]) field_17])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_19_map_wrap_void.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_19_map_wrap_void.snap index f8be1c0a..1cb79aee 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_19_map_wrap_void.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_19_map_wrap_void.snap @@ -71,8 +71,7 @@ main#1 (delay [fromBool_10 (con bool False)])]) (constr 0 a_8 b_9)]))]) (lam arg_34 - (lam arg_35 - [(lam match_37 [(lam match_36 [fromBool_10 (con bool True)]) arg_35]) arg_34]))]) + (lam arg_35 (case arg_34 (case arg_35 [fromBool_10 (con bool True)]))))]) (lam value_33 value_33)]) --- result (con bool True) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_22_filter_map.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_22_filter_map.snap index b25ccb40..e7a98d9e 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_22_filter_map.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_22_filter_map.snap @@ -20,7 +20,7 @@ case@List match#23 of let restY#18 : list 'erased = field#22 in case@Bool eq#19 x#15 y#17 of True -> self#45 self#45 restX#16 restY#18 - False -> fromBool#11 false) in + False -> false) in let foldr#28 : list 'erased -> ('erased -> 'erased -> 'erased) -> 'erased -> 'erased = \xs#36 : list 'erased (f#37 : 'erased -> 'erased -> 'erased) zero#38 : 'erased -> (\self#44 : 'erased -> self#44 self#44) (\self#44 : 'erased xs#36 : list 'erased -> let match#41 : list 'erased = xs#36 in case@List match#41 of Nil -> zero#38 @@ -103,7 +103,7 @@ main#1 [(lam restY_18 (case [[eq_19 x_15] y_17] - [fromBool_11 (con bool False)] + (con bool False) [[[self_45 self_45] restX_16] restY_18])) field_22]) field_21])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_25_void_equal.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_25_void_equal.snap index 55a9445b..223f634c 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_25_void_equal.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_25_void_equal.snap @@ -18,13 +18,11 @@ main#1 [(lam main_1 main_1) [[eq_2 [fromUnit_3 (con unit ())]] [fromUnit_3 (con unit ())]]]) (lam value_9 value_9)]) - (lam arg_4 - (lam arg_5 - [(lam match_8 [(lam match_7 [fromBool_6 (con bool True)]) arg_5]) arg_4]))]) + (lam arg_4 (lam arg_5 (case arg_4 (case arg_5 [fromBool_6 (con bool True)]))))]) (lam value_10 value_10)]) --- result (con bool True) --- logs [] --- budget -cpu: 544100, memory: 3500 +cpu: 512100, memory: 3300 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_27_flat_map.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_27_flat_map.snap index b4e8396e..d4b88b68 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_27_flat_map.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_27_flat_map.snap @@ -20,7 +20,7 @@ case@List match#20 of let restY#15 : list 'erased = field#19 in case@Bool eq#16 x#12 y#14 of True -> self#48 self#48 restX#13 restY#15 - False -> fromBool#8 false) in + False -> false) in let foldr#35 : list 'erased -> ('erased -> 'erased -> 'erased) -> 'erased -> 'erased = \xs#38 : list 'erased (f#39 : 'erased -> 'erased -> 'erased) zero#40 : 'erased -> (\self#47 : 'erased -> self#47 self#47) (\self#47 : 'erased xs#38 : list 'erased -> let match#43 : list 'erased = xs#38 in case@List match#43 of Nil -> zero#40 @@ -119,7 +119,7 @@ main#1 [(lam restY_15 (case [[eq_16 x_12] y_14] - [fromBool_8 (con bool False)] + (con bool False) [[[self_48 self_48] restX_13] restY_15])) field_19]) field_18])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_empty_list.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_empty_list.snap index 9d3bee7a..6920179e 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_empty_list.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_empty_list.snap @@ -5,7 +5,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport --- core let fromBool#7 : bool -> bool = \value#31 : bool -> value#31 in let eq#15 : int -> int -> bool = equalsInteger in -let eq#2 : list 'erased -> list 'erased -> bool = (\self#44 : 'erased -> self#44 self#44) (\self#44 : 'erased xs#5 : list 'erased ys#6 : list 'erased -> let match#19 : list 'erased = xs#5 in +let eq#2 : list 'erased -> list 'erased -> bool = (\self#47 : 'erased -> self#47 self#47) (\self#47 : 'erased xs#5 : list 'erased ys#6 : list 'erased -> let match#19 : list 'erased = xs#5 in case@List match#19 of Nil -> let match#8 : list 'erased = ys#6 in case@List match#8 of @@ -19,25 +19,26 @@ case@List match#19 of Cons field#17 field#18 -> let y#13 : 'erased = field#17 in let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of - True -> self#44 self#44 restX#12 restY#14 - False -> fromBool#7 false) in -let filter#25 : list int -> (int -> bool) -> list int = \xs#32 : list int (f#33 : int -> bool) -> (\self#43 : 'erased -> self#43 self#43) (\self#43 : 'erased xs#32 : list int -> let match#36 : list int = xs#32 in + True -> self#47 self#47 restX#12 restY#14 + False -> false) in +let filter#25 : list int -> (int -> bool) -> list int = \xs#32 : list int (f#33 : int -> bool) -> (\self#46 : 'erased -> self#46 self#46) (\self#46 : 'erased xs#32 : list int -> let match#36 : list int = xs#32 in case@List match#36 of Nil -> (con (list integer) []) Cons field#37 field#38 -> let x#34 : int = field#37 in let rest#35 : list int = field#38 in case@Bool f#33 x#34 of - True -> mkCons x#34 (self#43 self#43 rest#35) - False -> self#43 self#43 rest#35) xs#32 in -let neq#27 : 'erased -> 'erased -> bool = \a#39 : 'erased b#40 : 'erased -> case@Bool eq#15 a#39 b#40 of - True -> fromBool#7 false - False -> fromBool#7 true in -let unique#3 : list int -> list int = (\self#41 : 'erased -> self#41 self#41) (\self#41 : 'erased xs#22 : list int -> let match#28 : list int = xs#22 in + True -> mkCons x#34 (self#46 self#46 rest#35) + False -> self#46 self#46 rest#35) xs#32 in +let not#41 : 'erased -> bool = \value#42 : 'erased -> case@Bool (\identity#43 : 'erased -> identity#43) value#42 of + True -> false + False -> true in +let neq#27 : 'erased -> 'erased -> bool = \a#39 : 'erased b#40 : 'erased -> not#41 (eq#15 a#39 b#40) in +let unique#3 : list int -> list int = (\self#44 : 'erased -> self#44 self#44) (\self#44 : 'erased xs#22 : list int -> let match#28 : list int = xs#22 in case@List match#28 of Nil -> (con (list integer) []) Cons field#29 field#30 -> let x#23 : int = field#29 in let rest#24 : list int = field#30 in - mkCons x#23 (self#41 self#41 (filter#25 rest#24 (\y#26 : int -> neq#27 y#26 x#23)))) in + mkCons x#23 (self#44 self#44 (filter#25 rest#24 (\y#26 : int -> neq#27 y#26 x#23)))) in let empty#4 : list int = (con (list integer) []) in let main#1 : bool = eq#2 (unique#3 empty#4) (con (list integer) []) in main#1 @@ -47,37 +48,35 @@ main#1 [(lam eq_15 [(lam eq_2 [(lam filter_25 - [(lam neq_27 - [(lam unique_3 - [(lam empty_4 - [(lam main_1 main_1) [[eq_2 [unique_3 empty_4]] (con (list integer) [])]]) - (con (list integer) [])]) - [(lam self_41 [self_41 self_41]) - (lam self_41 - (lam xs_22 - [(lam match_28 - (case - match_28 - (lam field_29 - (lam field_30 - [(lam x_23 - [(lam rest_24 - [[(force (builtin mkCons)) x_23] - [[self_41 self_41] [[filter_25 rest_24] (lam y_26 [[neq_27 y_26] x_23])]]]) - field_30]) - field_29])) - (con (list integer) []))) - xs_22]))]]) - (lam a_39 - (lam b_40 - (case - [[eq_15 a_39] b_40] - [fromBool_7 (con bool True)] - [fromBool_7 (con bool False)])))]) + [(lam not_41 + [(lam neq_27 + [(lam unique_3 + [(lam empty_4 + [(lam main_1 main_1) [[eq_2 [unique_3 empty_4]] (con (list integer) [])]]) + (con (list integer) [])]) + [(lam self_44 [self_44 self_44]) + (lam self_44 + (lam xs_22 + [(lam match_28 + (case + match_28 + (lam field_29 + (lam field_30 + [(lam x_23 + [(lam rest_24 + [[(force (builtin mkCons)) x_23] + [[self_44 self_44] [[filter_25 rest_24] (lam y_26 [[neq_27 y_26] x_23])]]]) + field_30]) + field_29])) + (con (list integer) []))) + xs_22]))]]) + (lam a_39 (lam b_40 [not_41 [[eq_15 a_39] b_40]]))]) + (lam value_42 + (case [(lam identity_43 identity_43) value_42] (con bool True) (con bool False)))]) (lam xs_32 (lam f_33 - [[(lam self_43 [self_43 self_43]) - (lam self_43 + [[(lam self_46 [self_46 self_46]) + (lam self_46 (lam xs_32 [(lam match_36 (case @@ -88,15 +87,15 @@ main#1 [(lam rest_35 (case [f_33 x_34] - [[self_43 self_43] rest_35] - [[(force (builtin mkCons)) x_34] [[self_43 self_43] rest_35]])) + [[self_46 self_46] rest_35] + [[(force (builtin mkCons)) x_34] [[self_46 self_46] rest_35]])) field_38]) field_37])) (con (list integer) []))) xs_32]))] xs_32]))]) - [(lam self_44 [self_44 self_44]) - (lam self_44 + [(lam self_47 [self_47 self_47]) + (lam self_47 (lam xs_5 (lam ys_6 [(lam match_19 @@ -115,8 +114,8 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] - [[[self_44 self_44] restX_12] restY_14])) + (con bool False) + [[[self_47 self_47] restX_12] restY_14])) field_18]) field_17])) [fromBool_7 (con bool False)])) @@ -137,4 +136,4 @@ main#1 --- logs [] --- budget -cpu: 1024100, memory: 6500 +cpu: 1072100, memory: 6800 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_list.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_list.snap index 55b8f8fc..d6eba4ff 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_list.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__collections__acceptance_test_28_unique_list.snap @@ -5,7 +5,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport --- core let fromBool#7 : bool -> bool = \value#32 : bool -> value#32 in let eq#15 : int -> int -> bool = equalsInteger in -let eq#2 : list 'erased -> list 'erased -> bool = (\self#45 : 'erased -> self#45 self#45) (\self#45 : 'erased xs#5 : list 'erased ys#6 : list 'erased -> let match#19 : list 'erased = xs#5 in +let eq#2 : list 'erased -> list 'erased -> bool = (\self#48 : 'erased -> self#48 self#48) (\self#48 : 'erased xs#5 : list 'erased ys#6 : list 'erased -> let match#19 : list 'erased = xs#5 in case@List match#19 of Nil -> let match#8 : list 'erased = ys#6 in case@List match#8 of @@ -19,25 +19,26 @@ case@List match#19 of Cons field#17 field#18 -> let y#13 : 'erased = field#17 in let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of - True -> self#45 self#45 restX#12 restY#14 - False -> fromBool#7 false) in -let filter#25 : list int -> (int -> bool) -> list int = \xs#33 : list int (f#34 : int -> bool) -> (\self#44 : 'erased -> self#44 self#44) (\self#44 : 'erased xs#33 : list int -> let match#37 : list int = xs#33 in + True -> self#48 self#48 restX#12 restY#14 + False -> false) in +let filter#25 : list int -> (int -> bool) -> list int = \xs#33 : list int (f#34 : int -> bool) -> (\self#47 : 'erased -> self#47 self#47) (\self#47 : 'erased xs#33 : list int -> let match#37 : list int = xs#33 in case@List match#37 of Nil -> (con (list integer) []) Cons field#38 field#39 -> let x#35 : int = field#38 in let rest#36 : list int = field#39 in case@Bool f#34 x#35 of - True -> mkCons x#35 (self#44 self#44 rest#36) - False -> self#44 self#44 rest#36) xs#33 in -let neq#27 : 'erased -> 'erased -> bool = \a#40 : 'erased b#41 : 'erased -> case@Bool eq#15 a#40 b#41 of - True -> fromBool#7 false - False -> fromBool#7 true in -let unique#3 : list int -> list int = (\self#42 : 'erased -> self#42 self#42) (\self#42 : 'erased xs#22 : list int -> let match#28 : list int = xs#22 in + True -> mkCons x#35 (self#47 self#47 rest#36) + False -> self#47 self#47 rest#36) xs#33 in +let not#42 : 'erased -> bool = \value#43 : 'erased -> case@Bool (\identity#44 : 'erased -> identity#44) value#43 of + True -> false + False -> true in +let neq#27 : 'erased -> 'erased -> bool = \a#40 : 'erased b#41 : 'erased -> not#42 (eq#15 a#40 b#41) in +let unique#3 : list int -> list int = (\self#45 : 'erased -> self#45 self#45) (\self#45 : 'erased xs#22 : list int -> let match#28 : list int = xs#22 in case@List match#28 of Nil -> (con (list integer) []) Cons field#29 field#30 -> let x#23 : int = field#29 in let rest#24 : list int = field#30 in - mkCons x#23 (self#42 self#42 (filter#25 rest#24 (\y#26 : int -> neq#27 y#26 x#23)))) in + mkCons x#23 (self#45 self#45 (filter#25 rest#24 (\y#26 : int -> neq#27 y#26 x#23)))) in let fromInt#4 : int -> int = \value#31 : int -> value#31 in let main#1 : bool = eq#2 (unique#3 (mkCons (fromInt#4 1) (mkCons (fromInt#4 2) (mkCons (fromInt#4 3) (mkCons (fromInt#4 1) (con (list integer) [])))))) (mkCons (fromInt#4 1) (mkCons (fromInt#4 2) (mkCons (fromInt#4 3) (con (list integer) [])))) in main#1 @@ -47,46 +48,44 @@ main#1 [(lam eq_15 [(lam eq_2 [(lam filter_25 - [(lam neq_27 - [(lam unique_3 - [(lam fromInt_4 - [(lam main_1 main_1) - [[eq_2 - [unique_3 + [(lam not_42 + [(lam neq_27 + [(lam unique_3 + [(lam fromInt_4 + [(lam main_1 main_1) + [[eq_2 + [unique_3 + [[(force (builtin mkCons)) [fromInt_4 (con integer 1)]] + [[(force (builtin mkCons)) [fromInt_4 (con integer 2)]] + [[(force (builtin mkCons)) [fromInt_4 (con integer 3)]] + [[(force (builtin mkCons)) [fromInt_4 (con integer 1)]] (con (list integer) [])]]]]]] [[(force (builtin mkCons)) [fromInt_4 (con integer 1)]] [[(force (builtin mkCons)) [fromInt_4 (con integer 2)]] - [[(force (builtin mkCons)) [fromInt_4 (con integer 3)]] - [[(force (builtin mkCons)) [fromInt_4 (con integer 1)]] (con (list integer) [])]]]]]] - [[(force (builtin mkCons)) [fromInt_4 (con integer 1)]] - [[(force (builtin mkCons)) [fromInt_4 (con integer 2)]] - [[(force (builtin mkCons)) [fromInt_4 (con integer 3)]] (con (list integer) [])]]]]]) - (lam value_31 value_31)]) - [(lam self_42 [self_42 self_42]) - (lam self_42 - (lam xs_22 - [(lam match_28 - (case - match_28 - (lam field_29 - (lam field_30 - [(lam x_23 - [(lam rest_24 - [[(force (builtin mkCons)) x_23] - [[self_42 self_42] [[filter_25 rest_24] (lam y_26 [[neq_27 y_26] x_23])]]]) - field_30]) - field_29])) - (con (list integer) []))) - xs_22]))]]) - (lam a_40 - (lam b_41 - (case - [[eq_15 a_40] b_41] - [fromBool_7 (con bool True)] - [fromBool_7 (con bool False)])))]) + [[(force (builtin mkCons)) [fromInt_4 (con integer 3)]] (con (list integer) [])]]]]]) + (lam value_31 value_31)]) + [(lam self_45 [self_45 self_45]) + (lam self_45 + (lam xs_22 + [(lam match_28 + (case + match_28 + (lam field_29 + (lam field_30 + [(lam x_23 + [(lam rest_24 + [[(force (builtin mkCons)) x_23] + [[self_45 self_45] [[filter_25 rest_24] (lam y_26 [[neq_27 y_26] x_23])]]]) + field_30]) + field_29])) + (con (list integer) []))) + xs_22]))]]) + (lam a_40 (lam b_41 [not_42 [[eq_15 a_40] b_41]]))]) + (lam value_43 + (case [(lam identity_44 identity_44) value_43] (con bool True) (con bool False)))]) (lam xs_33 (lam f_34 - [[(lam self_44 [self_44 self_44]) - (lam self_44 + [[(lam self_47 [self_47 self_47]) + (lam self_47 (lam xs_33 [(lam match_37 (case @@ -97,15 +96,15 @@ main#1 [(lam rest_36 (case [f_34 x_35] - [[self_44 self_44] rest_36] - [[(force (builtin mkCons)) x_35] [[self_44 self_44] rest_36]])) + [[self_47 self_47] rest_36] + [[(force (builtin mkCons)) x_35] [[self_47 self_47] rest_36]])) field_39]) field_38])) (con (list integer) []))) xs_33]))] xs_33]))]) - [(lam self_45 [self_45 self_45]) - (lam self_45 + [(lam self_48 [self_48 self_48]) + (lam self_48 (lam xs_5 (lam ys_6 [(lam match_19 @@ -124,8 +123,8 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] - [[[self_45 self_45] restX_12] restY_14])) + (con bool False) + [[[self_48 self_48] restX_12] restY_14])) field_18]) field_17])) [fromBool_7 (con bool False)])) @@ -146,4 +145,4 @@ main#1 --- logs [] --- budget -cpu: 10043137, memory: 55123 +cpu: 10283137, memory: 56623 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_empty.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_empty.snap index 1e82b29f..9d6f6bec 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_empty.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_empty.snap @@ -20,7 +20,7 @@ case@List match#20 of let restY#15 : list 'erased = field#19 in case@Bool eq#16 x#12 y#14 of True -> self#33 self#33 restX#13 restY#15 - False -> fromBool#8 false) in + False -> false) in let map#3 : list 'erased -> ('erased -> int) -> list int = \xs#23 : list 'erased (f#24 : 'erased -> int) -> (\self#32 : 'erased -> self#32 self#32) (\self#32 : 'erased xs#23 : list 'erased -> let match#27 : list 'erased = xs#23 in case@List match#27 of Nil -> (con (list integer) []) @@ -81,7 +81,7 @@ main#1 [(lam restY_15 (case [[eq_16 x_12] y_14] - [fromBool_8 (con bool False)] + (con bool False) [[[self_33 self_33] restX_13] restY_15])) field_19]) field_18])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_filled.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_filled.snap index b6aa58a5..58f692c8 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_filled.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_11_map_filled.snap @@ -20,7 +20,7 @@ case@List match#20 of let restY#15 : list 'erased = field#19 in case@Bool eq#16 x#12 y#14 of True -> self#33 self#33 restX#13 restY#15 - False -> fromBool#8 false) in + False -> false) in let map#3 : list 'erased -> ('erased -> int) -> list int = \xs#23 : list 'erased (f#24 : 'erased -> int) -> (\self#32 : 'erased -> self#32 self#32) (\self#32 : 'erased xs#23 : list 'erased -> let match#27 : list 'erased = xs#23 in case@List match#27 of Nil -> (con (list integer) []) @@ -86,7 +86,7 @@ main#1 [(lam restY_15 (case [[eq_16 x_12] y_14] - [fromBool_8 (con bool False)] + (con bool False) [[[self_33 self_33] restX_13] restY_15])) field_19]) field_18])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_12_filter_even.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_12_filter_even.snap index f45867ae..1326a87a 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_12_filter_even.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_12_filter_even.snap @@ -20,7 +20,7 @@ case@List match#20 of let restY#15 : list 'erased = field#19 in case@Bool eq#16 x#12 y#14 of True -> self#33 self#33 restX#13 restY#15 - False -> fromBool#8 false) in + False -> false) in let filter#3 : list int -> (int -> bool) -> list int = \xs#23 : list int (f#24 : int -> bool) -> (\self#32 : 'erased -> self#32 self#32) (\self#32 : 'erased xs#23 : list int -> let match#27 : list int = xs#23 in case@List match#27 of Nil -> (con (list integer) []) @@ -97,7 +97,7 @@ main#1 [(lam restY_15 (case [[eq_16 x_12] y_14] - [fromBool_8 (con bool False)] + (con bool False) [[[self_33 self_33] restX_13] restY_15])) field_19]) field_18])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_15_zero_arg.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_15_zero_arg.snap index 33638d26..26ba6c6d 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_15_zero_arg.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_15_zero_arg.snap @@ -27,9 +27,9 @@ main#1 [(lam field_5 (constr 0 field_5)) (con (list (pair data data)) [])]]]) (lam value_18 value_18)]) (lam arg_15 - [(lam match_17 - [(lam field_16 (constr 0 field_16)) (con (list (pair data data)) [])]) - arg_15])]) + (case + arg_15 + [(lam field_16 (constr 0 field_16)) (con (list (pair data data)) [])]))]) (lam arg_6 (lam arg_8 [(lam match_13 @@ -54,4 +54,4 @@ main#1 --- logs [] --- budget -cpu: 2279856, memory: 7265 +cpu: 2263856, memory: 7165 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_2_repeat.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_2_repeat.snap index f7ca493e..0c88caef 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_2_repeat.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_2_repeat.snap @@ -20,7 +20,7 @@ case@List match#20 of let restY#15 : list 'erased = field#19 in case@Bool eq#16 x#12 y#14 of True -> self#29 self#29 restX#13 restY#15 - False -> fromBool#8 false) in + False -> false) in let fromInt#5 : int -> int = \value#26 : int -> value#26 in let repeat#3 : bytes -> int -> list bytes = \x#23 : bytes n#24 : int -> (\self#28 : 'erased -> self#28 self#28) (\self#28 : 'erased n#24 : int -> case@Bool lessThanEqualsInteger n#24 (fromInt#5 0) of True -> (con (list bytestring) []) @@ -77,7 +77,7 @@ main#1 [(lam restY_15 (case [[eq_16 x_12] y_14] - [fromBool_8 (con bool False)] + (con bool False) [[[self_29 self_29] restX_13] restY_15])) field_19]) field_18])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_3_concat.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_3_concat.snap index c8ccf814..6cb58a75 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_3_concat.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_3_concat.snap @@ -20,7 +20,7 @@ case@List match#19 of let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of True -> self#38 self#38 restX#12 restY#14 - False -> fromBool#7 false) in + False -> false) in let foldr#24 : list 'erased -> ('erased -> 'erased -> 'erased) -> 'erased -> 'erased = \xs#29 : list 'erased (f#30 : 'erased -> 'erased -> 'erased) zero#31 : 'erased -> (\self#37 : 'erased -> self#37 self#37) (\self#37 : 'erased xs#29 : list 'erased -> let match#34 : list 'erased = xs#29 in case@List match#34 of Nil -> zero#31 @@ -96,7 +96,7 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] + (con bool False) [[[self_38 self_38] restX_12] restY_14])) field_18]) field_17])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_4_concat_no_anon_func.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_4_concat_no_anon_func.snap index 849149e0..2a0c2f04 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_4_concat_no_anon_func.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_4_concat_no_anon_func.snap @@ -20,7 +20,7 @@ case@List match#19 of let restY#14 : list 'erased = field#18 in case@Bool eq#15 x#11 y#13 of True -> self#39 self#39 restX#12 restY#14 - False -> fromBool#7 false) in + False -> false) in let foldr#24 : list 'erased -> ('erased -> 'erased -> 'erased) -> 'erased -> 'erased = \xs#28 : list 'erased (f#29 : 'erased -> 'erased -> 'erased) zero#30 : 'erased -> (\self#38 : 'erased -> self#38 self#38) (\self#38 : 'erased xs#28 : list 'erased -> let match#33 : list 'erased = xs#28 in case@List match#33 of Nil -> zero#30 @@ -95,7 +95,7 @@ main#1 [(lam restY_14 (case [[eq_15 x_11] y_13] - [fromBool_7 (con bool False)] + (con bool False) [[[self_39 self_39] restX_12] restY_14])) field_18]) field_17])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_5_direct_2_heads.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_5_direct_2_heads.snap index c2e9bc56..3a63b140 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_5_direct_2_heads.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_5_direct_2_heads.snap @@ -20,7 +20,7 @@ case@List match#51 of let restY#46 : list 'erased = field#50 in case@Bool eq#47 x#43 y#45 of True -> self#25 self#25 restX#44 restY#46 - False -> fromBool#20 false) in + False -> false) in let eq#2 : Main.option 'erased -> Main.option 'erased -> bool = \a#18 : Main.option 'erased b#19 : Main.option 'erased -> let match#24 : (Main.option 'erased, Main.option 'erased) = constr 0 a#18 b#19 in let leaf#30 : 'erased = delay (fromBool#20 false) in case@Tag match#24 of @@ -124,7 +124,7 @@ main#1 [(lam restY_46 (case [[eq_47 x_43] y_45] - [fromBool_20 (con bool False)] + (con bool False) [[[self_25 self_25] restX_44] restY_46])) field_50]) field_49])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_6_equals_tuple.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_6_equals_tuple.snap index d9e11572..486047ec 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_6_equals_tuple.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_6_equals_tuple.snap @@ -20,7 +20,7 @@ case@List match#33 of let restY#29 : list 'erased = field#32 in case@Bool eq#11 x#26 y#28 of True -> self#36 self#36 restX#27 restY#29 - False -> fromBool#10 false) in + False -> false) in let same#2 : (int, list int) -> (int, list int) -> bool = \arg#4 : (int, list int) arg#7 : (int, list int) -> let match#16 : (int, list int) = arg#4 in case@Tag match#16 of 0 field#17 field#18 -> let a#5 : int = field#17 in @@ -89,7 +89,7 @@ main#1 [(lam restY_29 (case [[eq_11 x_26] y_28] - [fromBool_10 (con bool False)] + (con bool False) [[[self_36 self_36] restX_27] restY_29])) field_32]) field_31])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_7_unzip_tuple.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_7_unzip_tuple.snap index 2d7fe043..bace4e9d 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_7_unzip_tuple.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_7_unzip_tuple.snap @@ -20,7 +20,7 @@ case@List match#62 of let restY#57 : list 'erased = field#61 in case@Bool eq#58 x#54 y#56 of True -> self#87 self#87 restX#55 restY#57 - False -> fromBool#17 false) in + False -> false) in let eq#74 : bytes -> bytes -> bool = equalsByteString in let eq#19 : list 'erased -> list 'erased -> bool = (\self#84 : 'erased -> self#84 self#84) (\self#84 : 'erased xs#65 : list 'erased ys#66 : list 'erased -> let match#78 : list 'erased = xs#65 in case@List match#78 of @@ -37,7 +37,7 @@ case@List match#78 of let restY#73 : list 'erased = field#77 in case@Bool eq#74 x#70 y#72 of True -> self#84 self#84 restX#71 restY#73 - False -> fromBool#17 false) in + False -> false) in let same#2 : ('erased, 'erased) -> ('erased, 'erased) -> bool = \arg#11 : ('erased, 'erased) arg#14 : ('erased, 'erased) -> let match#23 : ('erased, 'erased) = arg#11 in case@Tag match#23 of 0 field#24 field#25 -> let a#12 : 'erased = field#24 in @@ -181,7 +181,7 @@ main#1 [(lam restY_73 (case [[eq_74 x_70] y_72] - [fromBool_17 (con bool False)] + (con bool False) [[[self_84 self_84] restX_71] restY_73])) field_77]) field_76])) @@ -217,7 +217,7 @@ main#1 [(lam restY_57 (case [[eq_58 x_54] y_56] - [fromBool_17 (con bool False)] + (con bool False) [[[self_87 self_87] restX_55] restY_57])) field_61]) field_60])) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_empty.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_empty.snap index c4dc2d69..80314af6 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_empty.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_empty.snap @@ -3,42 +3,49 @@ source: crates/nash-codegen/src/build/tests/source/lists.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\nisEmpty bytes = equalsInteger (Builtin.lengthOfByteString bytes) 0\nmain = eq (isEmpty #\"\") True\n" --- --- core -let fromBool#5 : bool -> bool = \value#11 : bool -> value#11 in -let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> case@Bool a#6 of - True -> b#7 - False -> case@Bool b#7 of - True -> fromBool#5 false - False -> fromBool#5 true in -let fromInt#9 : int -> int = \value#12 : int -> value#12 in -let isEmpty#3 : bytes -> bool = \bytes#8 : bytes -> equalsInteger (lengthOfByteString bytes#8) (fromInt#9 0) in -let fromBytes#4 : bytes -> bytes = \value#10 : bytes -> value#10 in +let not#8 : 'erased -> bool = \value#14 : 'erased -> case@Bool (\identity#15 : 'erased -> identity#15) value#14 of + True -> false + False -> true in +let xor#9 : 'erased -> 'erased -> bool = \a#16 : 'erased b#17 : 'erased -> case@Bool (\identity#19 : 'erased -> identity#19) a#16 of + True -> not#8 b#17 + False -> (\identity#18 : 'erased -> identity#18) b#17 in +let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> not#8 (xor#9 a#6 b#7) in +let fromInt#11 : int -> int = \value#20 : int -> value#20 in +let isEmpty#3 : bytes -> bool = \bytes#10 : bytes -> equalsInteger (lengthOfByteString bytes#10) (fromInt#11 0) in +let fromBytes#4 : bytes -> bytes = \value#12 : bytes -> value#12 in +let fromBool#5 : bool -> bool = \value#13 : bool -> value#13 in let main#1 : bool = eq#2 (isEmpty#3 (fromBytes#4 (con bytestring #))) (fromBool#5 true) in main#1 --- uplc (program 1.1.0 - [(lam fromBool_5 - [(lam eq_2 - [(lam fromInt_9 - [(lam isEmpty_3 - [(lam fromBytes_4 - [(lam main_1 main_1) - [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #)]]] - [fromBool_5 (con bool True)]]]) - (lam value_10 value_10)]) - (lam bytes_8 - [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_8]] - [fromInt_9 (con integer 0)]])]) - (lam value_12 value_12)]) - (lam a_6 - (lam b_7 + [(lam not_8 + [(lam xor_9 + [(lam eq_2 + [(lam fromInt_11 + [(lam isEmpty_3 + [(lam fromBytes_4 + [(lam fromBool_5 + [(lam main_1 main_1) + [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #)]]] + [fromBool_5 (con bool True)]]]) + (lam value_13 value_13)]) + (lam value_12 value_12)]) + (lam bytes_10 + [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_10]] + [fromInt_11 (con integer 0)]])]) + (lam value_20 value_20)]) + (lam a_6 (lam b_7 [not_8 [[xor_9 a_6] b_7]]))]) + (lam a_16 + (lam b_17 (case - a_6 - (case b_7 [fromBool_5 (con bool True)] [fromBool_5 (con bool False)]) - b_7)))]) - (lam value_11 value_11)]) + [(lam identity_19 identity_19) a_16] + [(lam identity_18 identity_18) b_17] + [not_8 b_17])))]) + (lam value_14 + (case [(lam identity_15 identity_15) value_14] (con bool True) (con bool False)))]) --- result (con bool True) --- logs [] --- budget -cpu: 794533, memory: 4611 +cpu: 1290533, memory: 7711 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_not_empty.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_not_empty.snap index ffdae18f..808c1014 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_not_empty.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_8_is_not_empty.snap @@ -3,42 +3,49 @@ source: crates/nash-codegen/src/build/tests/source/lists.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\nisEmpty bytes = equalsInteger (Builtin.lengthOfByteString bytes) 0\nmain = eq (isEmpty #\"01\") False\n" --- --- core -let fromBool#5 : bool -> bool = \value#11 : bool -> value#11 in -let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> case@Bool a#6 of - True -> b#7 - False -> case@Bool b#7 of - True -> fromBool#5 false - False -> fromBool#5 true in -let fromInt#9 : int -> int = \value#12 : int -> value#12 in -let isEmpty#3 : bytes -> bool = \bytes#8 : bytes -> equalsInteger (lengthOfByteString bytes#8) (fromInt#9 0) in -let fromBytes#4 : bytes -> bytes = \value#10 : bytes -> value#10 in +let not#8 : 'erased -> bool = \value#14 : 'erased -> case@Bool (\identity#15 : 'erased -> identity#15) value#14 of + True -> false + False -> true in +let xor#9 : 'erased -> 'erased -> bool = \a#16 : 'erased b#17 : 'erased -> case@Bool (\identity#19 : 'erased -> identity#19) a#16 of + True -> not#8 b#17 + False -> (\identity#18 : 'erased -> identity#18) b#17 in +let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> not#8 (xor#9 a#6 b#7) in +let fromInt#11 : int -> int = \value#20 : int -> value#20 in +let isEmpty#3 : bytes -> bool = \bytes#10 : bytes -> equalsInteger (lengthOfByteString bytes#10) (fromInt#11 0) in +let fromBytes#4 : bytes -> bytes = \value#12 : bytes -> value#12 in +let fromBool#5 : bool -> bool = \value#13 : bool -> value#13 in let main#1 : bool = eq#2 (isEmpty#3 (fromBytes#4 (con bytestring #01))) (fromBool#5 false) in main#1 --- uplc (program 1.1.0 - [(lam fromBool_5 - [(lam eq_2 - [(lam fromInt_9 - [(lam isEmpty_3 - [(lam fromBytes_4 - [(lam main_1 main_1) - [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #01)]]] - [fromBool_5 (con bool False)]]]) - (lam value_10 value_10)]) - (lam bytes_8 - [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_8]] - [fromInt_9 (con integer 0)]])]) - (lam value_12 value_12)]) - (lam a_6 - (lam b_7 + [(lam not_8 + [(lam xor_9 + [(lam eq_2 + [(lam fromInt_11 + [(lam isEmpty_3 + [(lam fromBytes_4 + [(lam fromBool_5 + [(lam main_1 main_1) + [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #01)]]] + [fromBool_5 (con bool False)]]]) + (lam value_13 value_13)]) + (lam value_12 value_12)]) + (lam bytes_10 + [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_10]] + [fromInt_11 (con integer 0)]])]) + (lam value_20 value_20)]) + (lam a_6 (lam b_7 [not_8 [[xor_9 a_6] b_7]]))]) + (lam a_16 + (lam b_17 (case - a_6 - (case b_7 [fromBool_5 (con bool True)] [fromBool_5 (con bool False)]) - b_7)))]) - (lam value_11 value_11)]) + [(lam identity_19 identity_19) a_16] + [(lam identity_18 identity_18) b_17] + [not_8 b_17])))]) + (lam value_14 + (case [(lam identity_15 identity_15) value_14] (con bool True) (con bool False)))]) --- result (con bool True) --- logs [] --- budget -cpu: 874533, memory: 5111 +cpu: 1210533, memory: 7211 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_9_is_empty.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_9_is_empty.snap index e3461f9a..6dacdca9 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_9_is_empty.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__lists__acceptance_test_9_is_empty.snap @@ -3,42 +3,49 @@ source: crates/nash-codegen/src/build/tests/source/lists.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\nisEmpty bytes = equalsInteger (lengthOfByteString bytes) 0\nmain = eq (isEmpty #\"\") True\n" --- --- core -let fromBool#5 : bool -> bool = \value#11 : bool -> value#11 in -let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> case@Bool a#6 of - True -> b#7 - False -> case@Bool b#7 of - True -> fromBool#5 false - False -> fromBool#5 true in -let fromInt#9 : int -> int = \value#12 : int -> value#12 in -let isEmpty#3 : bytes -> bool = \bytes#8 : bytes -> equalsInteger (lengthOfByteString bytes#8) (fromInt#9 0) in -let fromBytes#4 : bytes -> bytes = \value#10 : bytes -> value#10 in +let not#8 : 'erased -> bool = \value#14 : 'erased -> case@Bool (\identity#15 : 'erased -> identity#15) value#14 of + True -> false + False -> true in +let xor#9 : 'erased -> 'erased -> bool = \a#16 : 'erased b#17 : 'erased -> case@Bool (\identity#19 : 'erased -> identity#19) a#16 of + True -> not#8 b#17 + False -> (\identity#18 : 'erased -> identity#18) b#17 in +let eq#2 : bool -> bool -> bool = \a#6 : bool b#7 : bool -> not#8 (xor#9 a#6 b#7) in +let fromInt#11 : int -> int = \value#20 : int -> value#20 in +let isEmpty#3 : bytes -> bool = \bytes#10 : bytes -> equalsInteger (lengthOfByteString bytes#10) (fromInt#11 0) in +let fromBytes#4 : bytes -> bytes = \value#12 : bytes -> value#12 in +let fromBool#5 : bool -> bool = \value#13 : bool -> value#13 in let main#1 : bool = eq#2 (isEmpty#3 (fromBytes#4 (con bytestring #))) (fromBool#5 true) in main#1 --- uplc (program 1.1.0 - [(lam fromBool_5 - [(lam eq_2 - [(lam fromInt_9 - [(lam isEmpty_3 - [(lam fromBytes_4 - [(lam main_1 main_1) - [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #)]]] - [fromBool_5 (con bool True)]]]) - (lam value_10 value_10)]) - (lam bytes_8 - [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_8]] - [fromInt_9 (con integer 0)]])]) - (lam value_12 value_12)]) - (lam a_6 - (lam b_7 + [(lam not_8 + [(lam xor_9 + [(lam eq_2 + [(lam fromInt_11 + [(lam isEmpty_3 + [(lam fromBytes_4 + [(lam fromBool_5 + [(lam main_1 main_1) + [[eq_2 [isEmpty_3 [fromBytes_4 (con bytestring #)]]] + [fromBool_5 (con bool True)]]]) + (lam value_13 value_13)]) + (lam value_12 value_12)]) + (lam bytes_10 + [[(builtin equalsInteger) [(builtin lengthOfByteString) bytes_10]] + [fromInt_11 (con integer 0)]])]) + (lam value_20 value_20)]) + (lam a_6 (lam b_7 [not_8 [[xor_9 a_6] b_7]]))]) + (lam a_16 + (lam b_17 (case - a_6 - (case b_7 [fromBool_5 (con bool True)] [fromBool_5 (con bool False)]) - b_7)))]) - (lam value_11 value_11)]) + [(lam identity_19 identity_19) a_16] + [(lam identity_18 identity_18) b_17] + [not_8 b_17])))]) + (lam value_14 + (case [(lam identity_15 identity_15) value_14] (con bool True) (con bool False)))]) --- result (con bool True) --- logs [] --- budget -cpu: 794533, memory: 4611 +cpu: 1290533, memory: 7711 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_clause_with_assign.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_clause_with_assign.snap index e9d9cb3d..9baaa4dd 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_clause_with_assign.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_clause_with_assign.snap @@ -3,164 +3,114 @@ source: crates/nash-codegen/src/build/tests/source/patterns.rs description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Eq exposing (..)\ntype Option = Some Int | None\ndoInit self =\n case self of\n [] -> trace \"unreachable\" fail\n [_] as a -> a\n [(Some _) as n, x] -> [n]\n [a, x] -> [x]\n a :: b :: c -> c\nmain = eq (doInit [Some 1, None]) [Some 1]\n" --- --- core -let message#60 : string = "unreachable" in -let fromBool#9 : bool -> bool = \value#57 : bool -> value#57 in -let eq#2 : list 'erased -> list 'erased -> bool = (\self#34 : 'erased -> self#34 self#34) (\self#34 : 'erased xs#7 : list 'erased ys#8 : list 'erased -> let match#20 : list 'erased = xs#7 in -case@List match#20 of - Nil -> let match#10 : list 'erased = ys#8 in - case@List match#10 of - Nil -> fromBool#9 true - Cons field#11 field#12 -> fromBool#9 false - Cons field#21 field#22 -> let x#13 : 'erased = field#21 in - let restX#14 : list 'erased = field#22 in - let match#17 : list 'erased = ys#8 in - case@List match#17 of - Nil -> fromBool#9 false - Cons field#18 field#19 -> let y#15 : 'erased = field#18 in - let restY#16 : list 'erased = field#19 in - case@Bool equalsData x#13 y#15 of - True -> self#34 self#34 restX#14 restY#16 - False -> fromBool#9 false) in -let fromString#24 : string -> string = \value#58 : string -> value#58 in -let doInit#3 : list Main.Option -> list Main.Option = \self#23 : list Main.Option -> let match#33 : list Main.Option = self#23 in -let leaf#45 : 'erased = \a#30 : Main.Option b#31 : Main.Option c#32 : list Main.Option -> c#32 in -case@List match#33 of - Nil -> trace (fromString#24 message#60) in error - Cons field#46 field#47 -> case@List field#47 of - Nil -> let a#25 : list Main.Option = match#33 in - a#25 - Cons field#48 field#49 -> let projection#59 : pair int (list Data) = unConstrData field#46 in - case@Pair projection#59 of - Pair tag#55 fields#56 -> case@Tag tag#55 of - 0 -> case@List field#49 of - Nil -> let n#26 : Main.Option = field#46 in - let x#27 : Main.Option = field#48 in - mkCons n#26 (con (list data) []) - Cons field#51 field#52 -> let a#30 : Main.Option = field#46 in - let b#31 : Main.Option = field#48 in - let c#32 : list Main.Option = field#49 in - leaf#45 a#30 b#31 c#32 - 1 -> case@List field#49 of - Nil -> let a#28 : Main.Option = field#46 in - let x#29 : Main.Option = field#48 in - mkCons x#29 (con (list data) []) - Cons field#53 field#54 -> let a#30 : Main.Option = field#46 in - let b#31 : Main.Option = field#48 in - let c#32 : list Main.Option = field#49 in - leaf#45 a#30 b#31 c#32 in +let message#45 : string = "unreachable" in +let eq#2 : list 'erased -> list 'erased -> bool = \xs#7 : list 'erased ys#8 : list 'erased -> equalsData (listData xs#7) (listData ys#8) in +let fromString#10 : string -> string = \value#43 : string -> value#43 in +let doInit#3 : list Main.Option -> list Main.Option = \self#9 : list Main.Option -> let match#19 : list Main.Option = self#9 in +let leaf#31 : 'erased = \a#16 : Main.Option b#17 : Main.Option c#18 : list Main.Option -> c#18 in +case@List match#19 of + Nil -> trace (fromString#10 message#45) in error + Cons field#32 field#33 -> case@List field#33 of + Nil -> let a#11 : list Main.Option = match#19 in + a#11 + Cons field#34 field#35 -> let projection#44 : pair int (list Data) = unConstrData field#32 in + case@Pair projection#44 of + Pair tag#41 fields#42 -> case@Tag tag#41 of + 0 -> case@List field#35 of + Nil -> let n#12 : Main.Option = field#32 in + let x#13 : Main.Option = field#34 in + mkCons n#12 (con (list data) []) + Cons field#37 field#38 -> let a#16 : Main.Option = field#32 in + let b#17 : Main.Option = field#34 in + let c#18 : list Main.Option = field#35 in + leaf#31 a#16 b#17 c#18 + 1 -> case@List field#35 of + Nil -> let a#14 : Main.Option = field#32 in + let x#15 : Main.Option = field#34 in + mkCons x#15 (con (list data) []) + Cons field#39 field#40 -> let a#16 : Main.Option = field#32 in + let b#17 : Main.Option = field#34 in + let c#18 : list Main.Option = field#35 in + leaf#31 a#16 b#17 c#18 in let fromInt#5 : int -> Int = iData in let main#1 : bool = eq#2 (doInit#3 (mkCons ((\field#4 : Int -> constrData 0 (mkCons field#4 (con (list data) []))) (fromInt#5 1)) (mkCons (constrData 1 (con (list data) [])) (con (list data) [])))) (mkCons ((\field#6 : Int -> constrData 0 (mkCons field#6 (con (list data) []))) (fromInt#5 1)) (con (list data) [])) in main#1 --- uplc (program 1.1.0 - [(lam message_60 - [(lam fromBool_9 - [(lam eq_2 - [(lam fromString_24 - [(lam doInit_3 - [(lam fromInt_5 - [(lam main_1 main_1) - [[eq_2 - [doInit_3 - [[(force (builtin mkCons)) - [(lam field_4 - [[(builtin constrData) (con integer 0)] - [[(force (builtin mkCons)) field_4] (con (list data) [])]]) - [fromInt_5 (con integer 1)]]] - [[(force (builtin mkCons)) - [[(builtin constrData) (con integer 1)] (con (list data) [])]] - (con (list data) [])]]]] + [(lam message_45 + [(lam eq_2 + [(lam fromString_10 + [(lam doInit_3 + [(lam fromInt_5 + [(lam main_1 main_1) + [[eq_2 + [doInit_3 [[(force (builtin mkCons)) - [(lam field_6 + [(lam field_4 [[(builtin constrData) (con integer 0)] - [[(force (builtin mkCons)) field_6] (con (list data) [])]]) + [[(force (builtin mkCons)) field_4] (con (list data) [])]]) [fromInt_5 (con integer 1)]]] - (con (list data) [])]]]) - (builtin iData)]) - (lam self_23 - [(lam match_33 - [(lam leaf_45 - (case - match_33 - (lam field_46 - (lam field_47 - (case - field_47 - (lam field_48 - (lam field_49 - [(lam projection_59 - (case - projection_59 - (lam tag_55 - (lam fields_56 - (case - tag_55 - (case - field_49 - (lam field_51 - (lam field_52 - [(lam a_30 - [(lam b_31 [(lam c_32 [[[leaf_45 a_30] b_31] c_32]) field_49]) field_48]) - field_46])) - [(lam n_26 - [(lam x_27 [[(force (builtin mkCons)) n_26] (con (list data) [])]) field_48]) - field_46]) - (case - field_49 - (lam field_53 - (lam field_54 - [(lam a_30 - [(lam b_31 [(lam c_32 [[[leaf_45 a_30] b_31] c_32]) field_49]) field_48]) - field_46])) - [(lam a_28 - [(lam x_29 [[(force (builtin mkCons)) x_29] (con (list data) [])]) field_48]) - field_46])))))) - [(builtin unConstrData) field_46]])) - [(lam a_25 a_25) match_33]))) - (force [[(force (builtin trace)) [fromString_24 message_60]] (delay (error))]))) - (lam a_30 (lam b_31 (lam c_32 c_32)))]) - self_23])]) - (lam value_58 value_58)]) - [(lam self_34 [self_34 self_34]) - (lam self_34 - (lam xs_7 - (lam ys_8 - [(lam match_20 - (case - match_20 - (lam field_21 - (lam field_22 - [(lam x_13 - [(lam restX_14 - [(lam match_17 - (case - match_17 - (lam field_18 - (lam field_19 - [(lam y_15 - [(lam restY_16 - (case - [[(builtin equalsData) x_13] y_15] - [fromBool_9 (con bool False)] - [[[self_34 self_34] restX_14] restY_16])) - field_19]) - field_18])) - [fromBool_9 (con bool False)])) - ys_8]) - field_22]) - field_21])) - [(lam match_10 + [[(force (builtin mkCons)) + [[(builtin constrData) (con integer 1)] (con (list data) [])]] + (con (list data) [])]]]] + [[(force (builtin mkCons)) + [(lam field_6 + [[(builtin constrData) (con integer 0)] + [[(force (builtin mkCons)) field_6] (con (list data) [])]]) + [fromInt_5 (con integer 1)]]] + (con (list data) [])]]]) + (builtin iData)]) + (lam self_9 + [(lam match_19 + [(lam leaf_31 + (case + match_19 + (lam field_32 + (lam field_33 (case - match_10 - (lam field_11 (lam field_12 [fromBool_9 (con bool False)])) - [fromBool_9 (con bool True)])) - ys_8])) - xs_7])))]]) - (lam value_57 value_57)]) + field_33 + (lam field_34 + (lam field_35 + [(lam projection_44 + (case + projection_44 + (lam tag_41 + (lam fields_42 + (case + tag_41 + (case + field_35 + (lam field_37 + (lam field_38 + [(lam a_16 + [(lam b_17 [(lam c_18 [[[leaf_31 a_16] b_17] c_18]) field_35]) field_34]) + field_32])) + [(lam n_12 + [(lam x_13 [[(force (builtin mkCons)) n_12] (con (list data) [])]) field_34]) + field_32]) + (case + field_35 + (lam field_39 + (lam field_40 + [(lam a_16 + [(lam b_17 [(lam c_18 [[[leaf_31 a_16] b_17] c_18]) field_35]) field_34]) + field_32])) + [(lam a_14 + [(lam x_15 [[(force (builtin mkCons)) x_15] (con (list data) [])]) field_34]) + field_32])))))) + [(builtin unConstrData) field_32]])) + [(lam a_11 a_11) match_19]))) + (force [[(force (builtin trace)) [fromString_10 message_45]] (delay (error))]))) + (lam a_16 (lam b_17 (lam c_18 c_18)))]) + self_9])]) + (lam value_43 value_43)]) + (lam xs_7 + (lam ys_8 + [[(builtin equalsData) [(builtin listData) xs_7]] [(builtin listData) ys_8]]))]) (con string "unreachable")]) --- result (con bool True) --- logs [] --- budget -cpu: 4515570, memory: 18085 +cpu: 3812390, memory: 12649 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_fields_unwrap.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_fields_unwrap.snap index 2a8e124f..616c8f30 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_fields_unwrap.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__list_fields_unwrap.snap @@ -62,7 +62,8 @@ main#1 (lam value_27 value_27)]) (lam value_26 value_26)]) (lam arg_18 - [(lam match_25 + (case + arg_18 [[(force (builtin mkCons)) [[(lam field_19 (lam field_20 @@ -79,8 +80,7 @@ main#1 [[(force (builtin mkCons)) field_24] (con (list data) [])]]])) [fromBytes_21 (con bytestring #aa)]] [fromInt_22 (con integer 0)]]] - (con (list data) [])]]) - arg_18])]) + (con (list data) [])]]))]) (builtin iData)]) (builtin bData)]) --- result @@ -88,4 +88,4 @@ main#1 --- logs [] --- budget -cpu: 2670160, memory: 13349 +cpu: 2654160, memory: 13249 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__mixed_boolean_representations_short_circuit.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__mixed_boolean_representations_short_circuit.snap index 2f8c9177..f492172a 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__mixed_boolean_representations_short_circuit.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__mixed_boolean_representations_short_circuit.snap @@ -87,7 +87,7 @@ main#1 [(builtin unConstrData) match_26]]) value_25])]))]) (lam value_21 value_21)]) - (lam arg_19 [(lam match_20 (error)) arg_19])]) + (lam arg_19 (case arg_19 (error)))]) (lam value_18 value_18)]) --- result (con bool True) diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__native_unit_case_sequences_subject_before_body.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__native_unit_case_sequences_subject_before_body.snap new file mode 100644 index 00000000..975f3b83 --- /dev/null +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__native_unit_case_sequences_subject_before_body.snap @@ -0,0 +1,39 @@ +--- +source: crates/nash-codegen/src/build/tests/source/patterns.rs +description: "module Main exposing (..)\nimport Primitive exposing (..)\nmain : int\nmain =\n case trace \"subject\" () of\n () -> trace \"body\" 42\n" +--- +--- core +let message#9 : string = "subject" in +let message#10 : string = "body" in +let fromUnit#2 : unit -> unit = \value#6 : unit -> value#6 in +let fromString#3 : string -> string = \value#7 : string -> value#7 in +let fromInt#4 : int -> int = \value#8 : int -> value#8 in +let match#5 : unit = trace (fromString#3 message#9) in fromUnit#2 () in +let main#1 : int = trace (fromString#3 message#10) in fromInt#4 42 in +main#1 +--- uplc +(program 1.1.0 + [(lam message_9 + [(lam message_10 + [(lam fromUnit_2 + [(lam fromString_3 + [(lam fromInt_4 + (case + (force + [[(force (builtin trace)) [fromString_3 message_9]] + (delay [fromUnit_2 (con unit ())])]) + [(lam main_1 main_1) + (force + [[(force (builtin trace)) [fromString_3 message_10]] + (delay [fromInt_4 (con integer 42)])])])) + (lam value_8 value_8)]) + (lam value_7 value_7)]) + (lam value_6 value_6)]) + (con string "body")]) + (con string "subject")]) +--- result +(con integer 42) +--- logs +["subject", "body"] +--- budget +cpu: 871096, memory: 4864 diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__partial_big_boolean_application_is_strict.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__partial_big_boolean_application_is_strict.snap index 66d6870a..4c48ed4e 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__partial_big_boolean_application_is_strict.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__partial_big_boolean_application_is_strict.snap @@ -37,7 +37,7 @@ main#1 [(builtin unConstrData) match_13]]) value_12])]) (lam value_8 value_8)]) - (lam arg_6 [(lam match_7 (error)) arg_6])]) + (lam arg_6 (case arg_6 (error)))]) --- result error: ExplicitErrorTerm --- logs diff --git a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__test_init_3.snap b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__test_init_3.snap index 9a71feb2..c8c7f78e 100644 --- a/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__test_init_3.snap +++ b/crates/nash-codegen/src/build/tests/source/snapshots/nash_codegen__build__tests__source__patterns__test_init_3.snap @@ -21,7 +21,7 @@ case@List match#46 of let restY#41 : list 'erased = field#45 in case@Bool eq#42 x#38 y#40 of True -> self#16 self#16 restX#39 restY#41 - False -> fromBool#9 false) in + False -> false) in let eq#2 : Main.option 'erased -> Main.option 'erased -> bool = \a#7 : Main.option 'erased b#8 : Main.option 'erased -> let match#13 : (Main.option 'erased, Main.option 'erased) = constr 0 a#7 b#8 in let leaf#19 : 'erased = delay (fromBool#9 false) in case@Tag match#13 of @@ -140,7 +140,7 @@ main#1 [(lam restY_41 (case [[eq_42 x_38] y_40] - [fromBool_9 (con bool False)] + (con bool False) [[[self_16 self_16] restX_39] restY_41])) field_45]) field_44])) diff --git a/crates/nash-codegen/src/build/tests/wildcard_cases.rs b/crates/nash-codegen/src/build/tests/wildcard_cases.rs new file mode 100644 index 00000000..e03bad90 --- /dev/null +++ b/crates/nash-codegen/src/build/tests/wildcard_cases.rs @@ -0,0 +1,784 @@ +//! Executed source snapshots for wildcard expansion and shared branch helpers. +use super::core_eval; + +#[test] +fn little_wildcard_mixed_arities_trace_order() { + let evaluated = core_eval( + "little_wildcard_mixed_arities_trace_order", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" 9 + main = (choose Stop, choose Zero, choose (One 2), choose (Two 3 4)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 9) (con integer 9) (con integer 9))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", + "fallback" + ] + ); +} + +#[test] +fn little_wildcard_shared_failure_unselected() { + let evaluated = core_eval( + "little_wildcard_shared_failure_unselected", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" fail + main = choose Stop + "# + ), + ); + assert_eq!(evaluated.result, "(con integer 1)"); + assert_eq!(evaluated.logs, ["subject", "explicit"]); +} + +#[test] +fn little_wildcard_shared_failure_zero() { + let evaluated = core_eval( + "little_wildcard_shared_failure_zero", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose Zero + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn little_wildcard_shared_failure_one() { + let evaluated = core_eval( + "little_wildcard_shared_failure_one", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose (One 2) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn little_wildcard_shared_failure_two() { + let evaluated = core_eval( + "little_wildcard_shared_failure_two", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose (Two 3 4) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn little_wildcard_returns_captured_function() { + let evaluated = core_eval( + "little_wildcard_returns_captured_function", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : int -> choice -> (int -> int) + choose outer subject = + case trace "subject" subject of + Stop -> trace "explicit" (\n -> n) + _ -> trace "fallback" (\n -> addInteger outer n) + main = (choose 10 Stop 5, choose 10 Zero 5, choose 10 (One 2) 5, choose 10 (Two 3 4) 5) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 5) (con integer 15) (con integer 15) (con integer 15))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", + "fallback" + ] + ); +} + +#[test] +fn little_wildcard_binds_whole_and_captures_outer() { + let evaluated = core_eval( + "little_wildcard_binds_whole_and_captures_outer", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + read : choice -> int + read value = + case value of + Stop -> 0 + Zero -> 0 + One a -> a + Two a b -> addInteger (a) (b) + choose : int -> choice -> int + choose outer subject = + case trace "subject" subject of + Stop -> 1 + whole -> trace "fallback" (addInteger outer (read whole)) + main = (choose 10 Stop, choose 10 Zero, choose 10 (One 20), choose 10 (Two 30 40)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 10) (con integer 30) (con integer 80))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "fallback", "subject", "fallback", "subject", "fallback" + ] + ); +} + +#[test] +fn little_wildcard_shared_helper_receives_bound_values() { + let evaluated = core_eval( + "little_wildcard_shared_helper_receives_bound_values", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : (choice, int) -> int + choose subject = + case trace "subject" subject of + (Stop, _) -> 0 + (_, value) -> trace "shared" value + main = (choose (Stop, 1), choose (Zero, 11), choose (One 2, 22), choose (Two 3 4, 33)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 0) (con integer 11) (con integer 22) (con integer 33))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "shared", "subject", "shared", "subject", "shared" + ] + ); +} + +#[test] +fn little_wildcard_unknown_tag_fails_dispatch() { + let evaluated = core_eval( + "little_wildcard_unknown_tag_fails_dispatch", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + type rogue = R0 | R1 | R2 | R3 | R4 + choose : choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" 9 + main = choose (coerce R4) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject"]); +} + +#[test] +fn little_wildcard_only_does_not_inspect_unknown_tag() { + let evaluated = core_eval( + "little_wildcard_only_does_not_inspect_unknown_tag", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + type rogue = R0 | R1 | R2 | R3 | R4 + choose : choice -> int + choose subject = + case trace "subject" subject of + _ -> trace "fallback" 9 + main = choose (coerce R4) + "# + ), + ); + assert_eq!(evaluated.result, "(con integer 9)"); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn big_wildcard_mixed_arities_trace_order() { + let evaluated = core_eval( + "big_wildcard_mixed_arities_trace_order", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" 9 + main = (choose Stop, choose Zero, choose (One 2), choose (Two 3 4)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 9) (con integer 9) (con integer 9))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", + "fallback" + ] + ); +} + +#[test] +fn big_wildcard_shared_failure_unselected() { + let evaluated = core_eval( + "big_wildcard_shared_failure_unselected", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" fail + main = choose Stop + "# + ), + ); + assert_eq!(evaluated.result, "(con integer 1)"); + assert_eq!(evaluated.logs, ["subject", "explicit"]); +} + +#[test] +fn big_wildcard_shared_failure_zero() { + let evaluated = core_eval( + "big_wildcard_shared_failure_zero", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose Zero + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn big_wildcard_shared_failure_one() { + let evaluated = core_eval( + "big_wildcard_shared_failure_one", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose (One 2) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn big_wildcard_shared_failure_two() { + let evaluated = core_eval( + "big_wildcard_shared_failure_two", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> 1 + _ -> trace "fallback" fail + main = choose (Two 3 4) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn big_wildcard_returns_captured_function() { + let evaluated = core_eval( + "big_wildcard_returns_captured_function", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : int -> Choice -> (int -> int) + choose outer subject = + case trace "subject" subject of + Stop -> trace "explicit" (\n -> n) + _ -> trace "fallback" (\n -> addInteger outer n) + main = (choose 10 Stop 5, choose 10 Zero 5, choose 10 (One 2) 5, choose 10 (Two 3 4) 5) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 5) (con integer 15) (con integer 15) (con integer 15))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "explicit", "subject", "fallback", "subject", "fallback", "subject", + "fallback" + ] + ); +} + +#[test] +fn big_wildcard_binds_whole_and_captures_outer() { + let evaluated = core_eval( + "big_wildcard_binds_whole_and_captures_outer", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + read : Choice -> int + read value = + case value of + Stop -> 0 + Zero -> 0 + One a -> unIData a + Two a b -> addInteger (unIData a) (unIData b) + choose : int -> Choice -> int + choose outer subject = + case trace "subject" subject of + Stop -> 1 + whole -> trace "fallback" (addInteger outer (read whole)) + main = (choose 10 Stop, choose 10 Zero, choose 10 (One 20), choose 10 (Two 30 40)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 10) (con integer 30) (con integer 80))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "fallback", "subject", "fallback", "subject", "fallback" + ] + ); +} + +#[test] +fn big_wildcard_shared_helper_receives_bound_values() { + let evaluated = core_eval( + "big_wildcard_shared_helper_receives_bound_values", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : (Choice, int) -> int + choose subject = + case trace "subject" subject of + (Stop, _) -> 0 + (_, value) -> trace "shared" value + main = (choose (Stop, 1), choose (Zero, 11), choose (One 2, 22), choose (Two 3 4, 33)) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 0) (con integer 11) (con integer 22) (con integer 33))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "shared", "subject", "shared", "subject", "shared" + ] + ); +} + +#[test] +fn big_wildcard_unknown_tag_fails_dispatch() { + let evaluated = core_eval( + "big_wildcard_unknown_tag_fails_dispatch", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + Stop -> trace "explicit" 1 + _ -> trace "fallback" 9 + main = choose (coerce (constrData 59 [])) + "# + ), + ); + assert!( + evaluated.result.starts_with("error:"), + "{}", + evaluated.result + ); + assert_eq!(evaluated.logs, ["subject"]); +} + +#[test] +fn big_wildcard_only_does_not_inspect_unknown_tag() { + let evaluated = core_eval( + "big_wildcard_only_does_not_inspect_unknown_tag", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> int + choose subject = + case trace "subject" subject of + _ -> trace "fallback" 9 + main = choose (coerce (constrData 59 [])) + "# + ), + ); + assert_eq!(evaluated.result, "(con integer 9)"); + assert_eq!(evaluated.logs, ["subject", "fallback"]); +} + +#[test] +fn big_wildcard_does_not_extract_missing_fields() { + let evaluated = core_eval( + "big_wildcard_does_not_extract_missing_fields", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | One Int | Two Int Int + choose : Choice -> int + choose subject = + case subject of + Stop -> 1 + _ -> trace "fallback" 9 + main = (choose (coerce (constrData 1 [])), choose (coerce (constrData 2 []))) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 9) (con integer 9))" + ); + assert_eq!(evaluated.logs, ["fallback", "fallback"]); +} + +#[test] +fn little_wildcard_calls_user_continuation_only_when_selected() { + let evaluated = core_eval( + "little_wildcard_calls_user_continuation_only_when_selected", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : choice -> (int -> int) -> int + choose subject continue = + case trace "subject" subject of + Stop -> 0 + _ -> trace "fallback" (continue 9) + finish : int -> int + finish n = trace "continue" (addInteger n 100) + main = (choose Stop (\_ -> trace "wrong" fail), choose Zero finish, choose (One 2) finish, choose (Two 3 4) finish) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 0) (con integer 109) (con integer 109) (con integer 109))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "fallback", "continue", "subject", "fallback", "continue", + "subject", "fallback", "continue" + ] + ); +} + +#[test] +fn little_wildcard_inline_function_result_consumes_fields() { + let evaluated = core_eval( + "little_wildcard_inline_function_result_consumes_fields", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Two int int + choose : choice -> (int -> int) + choose subject = + case trace "subject" subject of + Stop -> \n -> n + _ -> trace "fallback" (\n -> addInteger n 1) + main = (choose Stop 10, choose (Two 3 4) 20) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 10) (con integer 21))" + ); + assert_eq!(evaluated.logs, ["subject", "subject", "fallback"]); +} + +#[test] +fn big_wildcard_calls_user_continuation_only_when_selected() { + let evaluated = core_eval( + "big_wildcard_calls_user_continuation_only_when_selected", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : Choice -> (int -> int) -> int + choose subject continue = + case trace "subject" subject of + Stop -> 0 + _ -> trace "fallback" (continue 9) + finish : int -> int + finish n = trace "continue" (addInteger n 100) + main = (choose Stop (\_ -> trace "wrong" fail), choose Zero finish, choose (One 2) finish, choose (Two 3 4) finish) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 0) (con integer 109) (con integer 109) (con integer 109))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "fallback", "continue", "subject", "fallback", "continue", + "subject", "fallback", "continue" + ] + ); +} + +#[test] +fn big_wildcard_inline_function_result_consumes_fields() { + let evaluated = core_eval( + "big_wildcard_inline_function_result_consumes_fields", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Two Int Int + choose : Choice -> (int -> int) + choose subject = + case trace "subject" subject of + Stop -> \n -> n + _ -> trace "fallback" (\n -> addInteger n 1) + main = (choose Stop 10, choose (Two 3 4) 20) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 10) (con integer 21))" + ); + assert_eq!(evaluated.logs, ["subject", "subject", "fallback"]); +} + +#[test] +fn little_wildcard_multiple_bindings_return_function() { + let evaluated = core_eval( + "little_wildcard_multiple_bindings_return_function", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type choice = Stop | Zero | One int | Two int int + choose : (choice, int, int) -> (int -> int) + choose subject = + case trace "subject" subject of + (Stop, _, _) -> \n -> n + (_, z, a) -> trace "shared" (\n -> subtractInteger (addInteger z n) a) + main = (choose (Stop, 90, 80) 1, choose (Zero, 21, 3) 1, choose (One 2, 31, 4) 1, choose (Two 3 4, 41, 5) 1) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 19) (con integer 28) (con integer 37))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "shared", "subject", "shared", "subject", "shared" + ] + ); +} + +#[test] +fn big_wildcard_multiple_bindings_return_function() { + let evaluated = core_eval( + "big_wildcard_multiple_bindings_return_function", + indoc::indoc!( + r#" + module Main exposing (..) + import Primitive exposing (..) + import Builtin exposing (..) + type Choice = Stop | Zero | One Int | Two Int Int + choose : (Choice, int, int) -> (int -> int) + choose subject = + case trace "subject" subject of + (Stop, _, _) -> \n -> n + (_, z, a) -> trace "shared" (\n -> subtractInteger (addInteger z n) a) + main = (choose (Stop, 90, 80) 1, choose (Zero, 21, 3) 1, choose (One 2, 31, 4) 1, choose (Two 3 4, 41, 5) 1) + "# + ), + ); + assert_eq!( + evaluated.result, + "(constr 0 (con integer 1) (con integer 19) (con integer 28) (con integer 37))" + ); + assert_eq!( + evaluated.logs, + [ + "subject", "subject", "shared", "subject", "shared", "subject", "shared" + ] + ); +} diff --git a/crates/nash-codegen/src/can_to_core.rs b/crates/nash-codegen/src/can_to_core.rs index edca1593..ba85b40c 100644 --- a/crates/nash-codegen/src/can_to_core.rs +++ b/crates/nash-codegen/src/can_to_core.rs @@ -670,7 +670,7 @@ impl<'a> Engine<'a, '_, '_> { /// Logical operators are identified by their resolved standard-library target. /// An unrelated user operator with the same spelling keeps normal call rules. pub(crate) fn short_circuit(reference: QualifiedName<'_>) -> Option { - if reference.home.package == Some(primitives::BASE) && reference.home.name == "Bool" { + if reference.home.package == Some(primitives::BASE) && reference.home.name == "Logic" { match reference.name { "and" => Some(true), "or" => Some(false), diff --git a/crates/nash-codegen/src/harness.rs b/crates/nash-codegen/src/harness.rs index bb266428..5e0dc56a 100644 --- a/crates/nash-codegen/src/harness.rs +++ b/crates/nash-codegen/src/harness.rs @@ -77,26 +77,10 @@ impl std::fmt::Display for Evaluated { } pub fn eval_core<'a>(arena: &'a Arena, core: &'a Core<'a>) -> Evaluated { - eval_core_with_costs(arena, core, None) -} - -pub fn eval_core_with_costs<'a>( - arena: &'a Arena, - core: &'a Core<'a>, - costs: Option<&[i64]>, -) -> Evaluated { let named = crate::lower::lower(arena, core).expect("valid lowered Core"); let term = debruijn::to_debruijn(arena, named).expect("closed term"); let program = Program::new(arena, Version::plutus_v3(arena), term); - let evaluation = match costs { - Some(costs) => program.eval_with_params( - arena, - nash_plutus::machine::PlutusVersion::V3, - costs, - ExBudget::default(), - ), - None => program.eval(arena), - }; + let evaluation = program.eval(arena); Evaluated { uplc: pretty::program(Program::new(arena, Version::plutus_v3(arena), named)), result: match evaluation.term { diff --git a/crates/nash-codegen/src/lower.rs b/crates/nash-codegen/src/lower.rs index af3154ae..a683220e 100644 --- a/crates/nash-codegen/src/lower.rs +++ b/crates/nash-codegen/src/lower.rs @@ -87,10 +87,17 @@ impl<'a> Lower<'a> { value, body, } => { + let unit_sequence = binder.ty + == nash_ir::ty::Ty::Const(&nash_ir::ty::ConstTy::Unit) + && !crate::build::names(body).contains(&binder.name.unique); let body = self.term(body)?; let value = self.term(value)?; - body.lambda(self.arena, self.name(binder.name)) - .apply(self.arena, value) + if unit_sequence { + Term::case(self.arena, value, self.arena.alloc_slice_copy(&[body])) + } else { + body.lambda(self.arena, self.name(binder.name)) + .apply(self.arena, value) + } } Core::Builtin { func, args } => { if args.len() > func.arity() { @@ -163,41 +170,6 @@ impl<'a> Lower<'a> { branches: &'a [Branch<'a>], default: Option<&'a Core<'a>>, ) -> Result, Error> { - if kind == CaseKind::Tag { - if default.is_some() { - return Err(Error::InvalidCase( - "tag defaults must be expanded using constructor arities", - )); - } - let mut ordered = branches.iter().collect::>(); - ordered.sort_by_key(|b| { - if let Test::Tag(tag) = b.test { - tag - } else { - u16::MAX - } - }); - let mut arms = Vec::new(); - for (i, b) in ordered.into_iter().enumerate() { - if b.test - != Test::Tag( - u16::try_from(i) - .map_err(|_| Error::InvalidCase("too many constructors"))?, - ) - { - return Err(Error::InvalidCase( - "tag branches must cover consecutive unique tags", - )); - } - let body = self.term(b.body)?; - arms.push(self.lambda(b.binders, body)); - } - return Ok(Term::case( - self.arena, - self.term(scrutinee)?, - self.arena.alloc_slice_copy(&arms), - )); - } let scrutinee = self.term(scrutinee)?; let fallback = match default { Some(c) => self.term(c)?, @@ -329,7 +301,37 @@ impl<'a> Lower<'a> { .lambda(self.arena, name) .apply(self.arena, scrutinee) } - CaseKind::Tag => unreachable!("tag case handled above"), + CaseKind::Tag => { + if default.is_some() { + return Err(Error::InvalidCase( + "tag defaults must be expanded using constructor arities", + )); + } + let mut ordered = branches.iter().collect::>(); + ordered.sort_by_key(|b| { + if let Test::Tag(tag) = b.test { + tag + } else { + u16::MAX + } + }); + let mut arms = Vec::new(); + for (i, b) in ordered.into_iter().enumerate() { + if b.test + != Test::Tag( + u16::try_from(i) + .map_err(|_| Error::InvalidCase("too many constructors"))?, + ) + { + return Err(Error::InvalidCase( + "tag branches must cover consecutive unique tags", + )); + } + let body = self.term(b.body)?; + arms.push(self.lambda(b.binders, body)); + } + Term::case(self.arena, scrutinee, self.arena.alloc_slice_copy(&arms)) + } }) } } diff --git a/crates/nash-codegen/src/lower/tests.rs b/crates/nash-codegen/src/lower/tests.rs index db1a358b..cdf07aea 100644 --- a/crates/nash-codegen/src/lower/tests.rs +++ b/crates/nash-codegen/src/lower/tests.rs @@ -50,6 +50,34 @@ fn boolean_case_does_not_evaluate_unselected_failure() { ); } +#[test] +fn unused_unit_binding_uses_case_and_preserves_sequencing() { + let arena = Arena::new(); + let b = Builder::new(&arena); + let unit = Binder { + name: b.fresh("unit"), + ty: Ty::Const(&ConstTy::Unit), + }; + let subject = b.trace( + b.lit(Constant::string(&arena, "subject")), + b.lit(Constant::unit(&arena)), + ); + let body = b.trace(b.lit(Constant::string(&arena, "body")), b.int(42)); + let core = b.let_(unit, subject, body); + assert!(matches!(lower(&arena, core).unwrap(), Term::Case { .. })); + let result = evaluate(&arena, core); + assert_eq!(result.term.unwrap(), Term::integer_from(&arena, 42)); + assert_eq!(result.info.logs, ["subject", "body"]); + + let failing = b.let_(unit, b.error(), body); + let result = evaluate(&arena, failing); + assert!(result.term.is_err()); + assert!(result.info.logs.is_empty()); + + let used = b.let_(unit, subject, b.var(unit.name)); + assert_eq!(evaluate(&arena, used).term.unwrap(), Term::unit(&arena)); +} + #[test] fn trace_precedes_failure() { let arena = Arena::new(); @@ -255,5 +283,3 @@ fn data_shapes_evaluate_once_and_only_unpack_the_selected_branch() { assert_eq!(result.info.logs, ["scrutinee", "branch"]); } } - -mod list_costs; diff --git a/crates/nash-codegen/src/lower/tests/list_costs.rs b/crates/nash-codegen/src/lower/tests/list_costs.rs deleted file mode 100644 index 56ba47b3..00000000 --- a/crates/nash-codegen/src/lower/tests/list_costs.rs +++ /dev/null @@ -1,230 +0,0 @@ -use super::*; -use nash_plutus::typ::Type; - -#[derive(Clone, Copy, Debug)] -enum Strategy { - Builtins, - DropHead, - Case, - DropCase, -} - -fn read<'a>( - b: &Builder<'a>, - list: &'a Core<'a>, - position: usize, - indices: &[usize], - strategy: Strategy, -) -> &'a Core<'a> { - let target = indices[0]; - let gap = target - position; - if matches!(strategy, Strategy::Builtins | Strategy::DropHead) { - let mut value = list; - if gap >= 2 && matches!(strategy, Strategy::DropHead) { - value = b.builtin(DefaultFunction::DropList, &[b.int(gap as i128), value]); - } else { - for _ in 0..gap { - value = b.builtin(DefaultFunction::TailList, &[value]); - } - } - let cursor = Binder { - name: b.fresh("cursor"), - ty: Ty::Erased, - }; - let shared = if matches!(value, Core::Var(_)) { - value - } else { - b.var(cursor.name) - }; - let head = b.builtin(DefaultFunction::HeadList, &[shared]); - let body = if indices.len() == 1 { - head - } else { - b.builtin( - DefaultFunction::AddInteger, - &[head, read(b, shared, target, &indices[1..], strategy)], - ) - }; - // Avoid an unused sharing let for an isolated read. - if indices.len() == 1 { - b.builtin(DefaultFunction::HeadList, &[value]) - } else if matches!(value, Core::Var(_)) { - body - } else { - b.let_(cursor, value, body) - } - } else { - let (value, position) = if gap >= 2 && matches!(strategy, Strategy::DropCase) { - ( - b.builtin(DefaultFunction::DropList, &[b.int(gap as i128), list]), - target, - ) - } else { - (list, position) - }; - let head = Binder { - name: b.fresh("head"), - ty: Ty::Erased, - }; - let tail = Binder { - name: b.fresh("tail"), - ty: Ty::Erased, - }; - let body = if position < target { - read(b, b.var(tail.name), position + 1, indices, strategy) - } else if indices.len() == 1 { - b.var(head.name) - } else { - b.builtin( - DefaultFunction::AddInteger, - &[ - b.var(head.name), - read(b, b.var(tail.name), position + 1, &indices[1..], strategy), - ], - ) - }; - b.case( - CaseKind::List, - value, - &[Branch { - test: Test::Cons, - binders: b.arena.alloc_slice_copy(&[head, tail]), - body, - }], - None, - ) - } -} - -#[test] -fn list_extraction_costs() { - let parameters: serde_json::Value = - serde_json::from_str(include_str!("mainnet-v3-epoch-656.json")).unwrap(); - let costs: Vec = serde_json::from_value(parameters["PlutusV3"].clone()).unwrap(); - let mut report = String::from("Mainnet epoch 656, protocol 11.0, Plutus V3 cost parameters\n"); - let mut descriptions = String::new(); - for length in [8, 64] { - for indices in [ - &[0][..], - &[1], - &[2], - &[3], - &[4], - &[5], - &[0, 1], - &[0, 1, 2, 3], - &[0, 3], - &[2, 5, 6], - ] { - let expected = format!("(con integer {})", indices.iter().sum::()); - for strategy in [ - Strategy::Builtins, - Strategy::DropHead, - Strategy::Case, - Strategy::DropCase, - ] { - let arena = Arena::new(); - let b = Builder::new(&arena); - let items = (0..length) - .map(|i| Constant::integer_from(&arena, i)) - .collect::>(); - let input = b.lit(Constant::proto_list( - &arena, - Type::integer(&arena), - arena.alloc_slice_copy(&items), - )); - let xs = Binder { - name: b.fresh("xs"), - ty: Ty::Erased, - }; - let core = b.let_(xs, input, read(&b, b.var(xs.name), 0, indices, strategy)); - let evaluated = crate::harness::eval_core_with_costs(&arena, core, Some(&costs)); - assert_eq!( - evaluated.result.split_whitespace().collect::>(), - expected.split_whitespace().collect::>() - ); - report.push_str(&format!( - "length={length} fields={indices:?} {strategy:?}: cpu={} memory={} result={}\n", - evaluated.budget.cpu, evaluated.budget.mem, evaluated.result - )); - if length == 8 { - descriptions.push_str(&format!( - "--- {indices:?} {strategy:?}\n{}\n", - nash_ir::pretty::pretty(core) - )); - } - } - } - for use_head in [false, true] { - let tail = format!("(con (list integer) {:?})", (1..length).collect::>()); - let expected = if use_head { - format!("(constr 0 (con integer 0) {tail})") - } else { - tail - }; - for use_case in [false, true] { - let arena = Arena::new(); - let b = Builder::new(&arena); - let items = (0..length) - .map(|i| Constant::integer_from(&arena, i)) - .collect::>(); - let input = b.lit(Constant::proto_list( - &arena, - Type::integer(&arena), - arena.alloc_slice_copy(&items), - )); - let xs = Binder { - name: b.fresh("xs"), - ty: Ty::Erased, - }; - let value = b.var(xs.name); - let body = if use_case { - let h = Binder { - name: b.fresh("h"), - ty: Ty::Erased, - }; - let t = Binder { - name: b.fresh("t"), - ty: Ty::Erased, - }; - let body = if use_head { - b.constr(0, &[b.var(h.name), b.var(t.name)]) - } else { - b.var(t.name) - }; - b.case( - CaseKind::List, - value, - &[Branch { - test: Test::Cons, - binders: arena.alloc_slice_copy(&[h, t]), - body, - }], - None, - ) - } else { - let tail = b.builtin(DefaultFunction::TailList, &[value]); - if use_head { - b.constr(0, &[b.builtin(DefaultFunction::HeadList, &[value]), tail]) - } else { - tail - } - }; - let core = b.let_(xs, input, body); - let evaluated = crate::harness::eval_core_with_costs(&arena, core, Some(&costs)); - assert_eq!( - evaluated.result.split_whitespace().collect::>(), - expected.split_whitespace().collect::>() - ); - report.push_str(&format!("length={length} head_and_tail={use_head} case={use_case}: cpu={} memory={} result={}\n", evaluated.budget.cpu, evaluated.budget.mem, evaluated.result)); - if length == 8 { - descriptions.push_str(&format!( - "--- head_and_tail={use_head} case={use_case}\n{}\n", - nash_ir::pretty::pretty(core) - )); - } - } - } - } - insta::with_settings!({description => descriptions, omit_expression => true}, { insta::assert_snapshot!(report); }); -} diff --git a/crates/nash-codegen/src/lower/tests/mainnet-v3-epoch-656.json b/crates/nash-codegen/src/lower/tests/mainnet-v3-epoch-656.json deleted file mode 100644 index 966a3824..00000000 --- a/crates/nash-codegen/src/lower/tests/mainnet-v3-epoch-656.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "source": "https://api.koios.rest/api/v1/epoch_params?epoch_no=eq.656&select=epoch_no,protocol_major,protocol_minor,cost_models", - "epoch": 656, - "protocol": "11.0", - "PlutusV3": [ - 100788, - 420, - 1, - 1, - 1000, - 173, - 0, - 1, - 1000, - 59957, - 4, - 1, - 11183, - 32, - 201305, - 8356, - 4, - 16000, - 100, - 16000, - 100, - 16000, - 100, - 16000, - 100, - 16000, - 100, - 16000, - 100, - 100, - 100, - 16000, - 100, - 94375, - 32, - 132994, - 32, - 61462, - 4, - 72010, - 178, - 0, - 1, - 22151, - 32, - 91189, - 769, - 4, - 2, - 85848, - 123203, - 7305, - -900, - 1716, - 960, - 57, - 85848, - 0, - 1, - 1, - 1000, - 42921, - 4, - 2, - 30623, - 28755, - 75, - 1, - 898148, - 27279, - 1, - 51775, - 558, - 1, - 39184, - 1000, - 60594, - 1, - 141895, - 32, - 83150, - 32, - 15299, - 32, - 76049, - 1, - 13169, - 4, - 22100, - 10, - 28999, - 74, - 1, - 28999, - 74, - 1, - 43285, - 552, - 1, - 44749, - 541, - 1, - 33852, - 32, - 68246, - 32, - 72362, - 32, - 7243, - 32, - 7391, - 32, - 11546, - 32, - 85848, - 123203, - 7305, - -900, - 1716, - 960, - 57, - 85848, - 0, - 1, - 90434, - 519, - 0, - 1, - 74433, - 32, - 85848, - 123203, - 7305, - -900, - 1716, - 960, - 57, - 85848, - 0, - 1, - 1, - 85848, - 123203, - 7305, - -900, - 1716, - 960, - 57, - 85848, - 0, - 1, - 955506, - 213312, - 0, - 2, - 270652, - 22588, - 4, - 1457325, - 64566, - 4, - 20467, - 1, - 4, - 0, - 141992, - 32, - 100788, - 420, - 1, - 1, - 81663, - 32, - 59498, - 32, - 20142, - 32, - 24588, - 32, - 20744, - 32, - 25933, - 32, - 24623, - 32, - 43053543, - 10, - 53384111, - 14333, - 10, - 43574283, - 26308, - 10, - 16000, - 100, - 16000, - 100, - 962335, - 18, - 2780678, - 6, - 442008, - 1, - 52538055, - 3756, - 18, - 267929, - 18, - 76433006, - 8868, - 18, - 52948122, - 18, - 1995836, - 36, - 3227919, - 12, - 901022, - 1, - 166917843, - 4307, - 36, - 284546, - 36, - 158221314, - 26549, - 36, - 74698472, - 36, - 333849714, - 1, - 254006273, - 72, - 2174038, - 72, - 2261318, - 64571, - 4, - 207616, - 8310, - 4, - 1293828, - 28716, - 63, - 0, - 1, - 1006041, - 43623, - 251, - 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 107878, - 680, - 0, - 1, - 95336, - 1, - 281145, - 18848, - 0, - 1, - 180194, - 159, - 1, - 1, - 158519, - 8942, - 0, - 1, - 159378, - 8813, - 0, - 1, - 107490, - 3298, - 1, - 106057, - 655, - 1, - 1964219, - 24520, - 3, - 607153, - 231697, - 53144, - 0, - 1, - 116711, - 1957, - 4, - 231883, - 10, - 1000, - 24838, - 7, - 1, - 232010, - 32, - 321837444, - 25087669, - 18, - 617887431, - 67302824, - 36, - 356924, - 18413, - 45, - 21, - 219951, - 9444, - 1, - 1000, - 172116, - 183150, - 6, - 24, - 21, - 213283, - 618401, - 1998, - 28258, - 1, - 1000, - 38159, - 2, - 22, - 1000, - 95933, - 1, - 1, - 11, - 1000, - 277577, - 12, - 21 - ] -} diff --git a/crates/nash-codegen/src/lower/tests/snapshots/nash_codegen__lower__tests__list_costs__list_extraction_costs.snap b/crates/nash-codegen/src/lower/tests/snapshots/nash_codegen__lower__tests__list_costs__list_extraction_costs.snap deleted file mode 100644 index 9ccf3c24..00000000 --- a/crates/nash-codegen/src/lower/tests/snapshots/nash_codegen__lower__tests__list_costs__list_extraction_costs.snap +++ /dev/null @@ -1,97 +0,0 @@ ---- -source: crates/nash-codegen/src/lower/tests/list_costs.rs -description: "--- [0] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList xs#1\n--- [0] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList xs#1\n--- [0] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [0] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [1] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList xs#1)\n--- [1] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList xs#1)\n--- [1] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> head#4\n--- [1] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> head#4\n--- [2] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList (tailList xs#1))\n--- [2] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (dropList 2 xs#1)\n--- [2] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> head#6\n--- [2] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List dropList 2 xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [3] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList (tailList (tailList xs#1)))\n--- [3] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (dropList 3 xs#1)\n--- [3] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> case@List tail#7 of\n Cons head#8 tail#9 -> head#8\n--- [3] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List dropList 3 xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [4] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList (tailList (tailList (tailList xs#1))))\n--- [4] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (dropList 4 xs#1)\n--- [4] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> case@List tail#7 of\n Cons head#8 tail#9 -> case@List tail#9 of\n Cons head#10 tail#11 -> head#10\n--- [4] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List dropList 4 xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [5] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (tailList (tailList (tailList (tailList (tailList xs#1)))))\n--- [5] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nheadList (dropList 5 xs#1)\n--- [5] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> case@List tail#7 of\n Cons head#8 tail#9 -> case@List tail#9 of\n Cons head#10 tail#11 -> case@List tail#11 of\n Cons head#12 tail#13 -> head#12\n--- [5] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List dropList 5 xs#1 of\n Cons head#2 tail#3 -> head#2\n--- [0, 1] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (headList (tailList xs#1))\n--- [0, 1] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (headList (tailList xs#1))\n--- [0, 1] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List tail#3 of\n Cons head#4 tail#5 -> head#4)\n--- [0, 1] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List tail#3 of\n Cons head#4 tail#5 -> head#4)\n--- [0, 1, 2, 3] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (let cursor#3 : 'erased = tailList xs#1 in\naddInteger (headList cursor#3) (let cursor#4 : 'erased = tailList cursor#3 in\naddInteger (headList cursor#4) (headList (tailList cursor#4))))\n--- [0, 1, 2, 3] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (let cursor#3 : 'erased = tailList xs#1 in\naddInteger (headList cursor#3) (let cursor#4 : 'erased = tailList cursor#3 in\naddInteger (headList cursor#4) (headList (tailList cursor#4))))\n--- [0, 1, 2, 3] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List tail#3 of\n Cons head#4 tail#5 -> addInteger head#4 (case@List tail#5 of\n Cons head#6 tail#7 -> addInteger head#6 (case@List tail#7 of\n Cons head#8 tail#9 -> head#8)))\n--- [0, 1, 2, 3] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List tail#3 of\n Cons head#4 tail#5 -> addInteger head#4 (case@List tail#5 of\n Cons head#6 tail#7 -> addInteger head#6 (case@List tail#7 of\n Cons head#8 tail#9 -> head#8)))\n--- [0, 3] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (headList (tailList (tailList (tailList xs#1))))\n--- [0, 3] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\naddInteger (headList xs#1) (headList (dropList 3 xs#1))\n--- [0, 3] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> case@List tail#7 of\n Cons head#8 tail#9 -> head#8)\n--- [0, 3] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List dropList 2 tail#3 of\n Cons head#4 tail#5 -> head#4)\n--- [2, 5, 6] Builtins\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nlet cursor#2 : 'erased = tailList (tailList xs#1) in\naddInteger (headList cursor#2) (let cursor#3 : 'erased = tailList (tailList (tailList cursor#2)) in\naddInteger (headList cursor#3) (headList (tailList cursor#3)))\n--- [2, 5, 6] DropHead\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nlet cursor#2 : 'erased = dropList 2 xs#1 in\naddInteger (headList cursor#2) (let cursor#3 : 'erased = dropList 3 cursor#2 in\naddInteger (headList cursor#3) (headList (tailList cursor#3)))\n--- [2, 5, 6] Case\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons head#2 tail#3 -> case@List tail#3 of\n Cons head#4 tail#5 -> case@List tail#5 of\n Cons head#6 tail#7 -> addInteger head#6 (case@List tail#7 of\n Cons head#8 tail#9 -> case@List tail#9 of\n Cons head#10 tail#11 -> case@List tail#11 of\n Cons head#12 tail#13 -> addInteger head#12 (case@List tail#13 of\n Cons head#14 tail#15 -> head#14))\n--- [2, 5, 6] DropCase\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List dropList 2 xs#1 of\n Cons head#2 tail#3 -> addInteger head#2 (case@List dropList 2 tail#3 of\n Cons head#4 tail#5 -> addInteger head#4 (case@List tail#5 of\n Cons head#6 tail#7 -> head#6))\n--- head_and_tail=false case=false\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ntailList xs#1\n--- head_and_tail=false case=true\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons h#2 t#3 -> t#3\n--- head_and_tail=true case=false\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\nconstr 0 (headList xs#1) (tailList xs#1)\n--- head_and_tail=true case=true\nlet xs#1 : 'erased = (con (list integer) [0, 1, 2, 3, 4, 5, 6, 7]) in\ncase@List xs#1 of\n Cons h#2 t#3 -> constr 0 h#2 t#3\n" ---- -Mainnet epoch 656, protocol 11.0, Plutus V3 cost parameters -length=8 fields=[0] Builtins: cpu=195250 memory=832 result=(con integer 0) -length=8 fields=[0] DropHead: cpu=195250 memory=832 result=(con integer 0) -length=8 fields=[0] Case: cpu=128100 memory=900 result=(con integer 0) -length=8 fields=[0] DropCase: cpu=128100 memory=900 result=(con integer 0) -length=8 fields=[1] Builtins: cpu=324913 memory=1164 result=(con integer 1) -length=8 fields=[1] DropHead: cpu=324913 memory=1164 result=(con integer 1) -length=8 fields=[1] Case: cpu=192100 memory=1300 result=(con integer 1) -length=8 fields=[1] DropCase: cpu=192100 memory=1300 result=(con integer 1) -length=8 fields=[2] Builtins: cpu=454576 memory=1496 result=(con integer 2) -length=8 fields=[2] DropHead: cpu=395875 memory=1336 result=(con integer 2) -length=8 fields=[2] Case: cpu=256100 memory=1700 result=(con integer 2) -length=8 fields=[2] DropCase: cpu=328725 memory=1404 result=(con integer 2) -length=8 fields=[3] Builtins: cpu=584239 memory=1828 result=(con integer 3) -length=8 fields=[3] DropHead: cpu=397832 memory=1336 result=(con integer 3) -length=8 fields=[3] Case: cpu=320100 memory=2100 result=(con integer 3) -length=8 fields=[3] DropCase: cpu=330682 memory=1404 result=(con integer 3) -length=8 fields=[4] Builtins: cpu=713902 memory=2160 result=(con integer 4) -length=8 fields=[4] DropHead: cpu=399789 memory=1336 result=(con integer 4) -length=8 fields=[4] Case: cpu=384100 memory=2500 result=(con integer 4) -length=8 fields=[4] DropCase: cpu=332639 memory=1404 result=(con integer 4) -length=8 fields=[5] Builtins: cpu=843565 memory=2492 result=(con integer 5) -length=8 fields=[5] DropHead: cpu=401746 memory=1336 result=(con integer 5) -length=8 fields=[5] Case: cpu=448100 memory=2900 result=(con integer 5) -length=8 fields=[5] DropCase: cpu=334596 memory=1404 result=(con integer 5) -length=8 fields=[0, 1] Builtins: cpu=621271 memory=1898 result=(con integer 1) -length=8 fields=[0, 1] DropHead: cpu=621271 memory=1898 result=(con integer 1) -length=8 fields=[0, 1] Case: cpu=357308 memory=1702 result=(con integer 1) -length=8 fields=[0, 1] DropCase: cpu=357308 memory=1702 result=(con integer 1) -length=8 fields=[0, 1, 2, 3] Builtins: cpu=1569313 memory=4630 result=(con integer 6) -length=8 fields=[0, 1, 2, 3] DropHead: cpu=1569313 memory=4630 result=(con integer 6) -length=8 fields=[0, 1, 2, 3] Case: cpu=815724 memory=3306 result=(con integer 6) -length=8 fields=[0, 1, 2, 3] DropCase: cpu=815724 memory=3306 result=(con integer 6) -length=8 fields=[0, 3] Builtins: cpu=880597 memory=2562 result=(con integer 3) -length=8 fields=[0, 3] DropHead: cpu=694190 memory=2070 result=(con integer 3) -length=8 fields=[0, 3] Case: cpu=485308 memory=2502 result=(con integer 3) -length=8 fields=[0, 3] DropCase: cpu=557933 memory=2206 result=(con integer 3) -length=8 fields=[2, 5, 6] Builtins: cpu=1661944 memory=4892 result=(con integer 13) -length=8 fields=[2, 5, 6] DropHead: cpu=1416836 memory=4240 result=(con integer 13) -length=8 fields=[2, 5, 6] Case: cpu=842516 memory=4104 result=(con integer 13) -length=8 fields=[2, 5, 6] DropCase: cpu=987766 memory=3512 result=(con integer 13) -length=8 head_and_tail=false case=false: cpu=193763 memory=832 result=(con (list integer) [1, 2, 3, 4, 5, 6, 7]) -length=8 head_and_tail=false case=true: cpu=128100 memory=900 result=(con (list integer) [1, 2, 3, 4, 5, 6, 7]) -length=8 head_and_tail=true case=false: cpu=356913 memory=1364 result=(constr 0 (con integer 0) (con (list integer) [1, 2, 3, 4, 5, 6, 7])) -length=8 head_and_tail=true case=true: cpu=160100 memory=1100 result=(constr 0 (con integer 0) (con (list integer) [1, 2, 3, 4, 5, 6, 7])) -length=64 fields=[0] Builtins: cpu=195250 memory=832 result=(con integer 0) -length=64 fields=[0] DropHead: cpu=195250 memory=832 result=(con integer 0) -length=64 fields=[0] Case: cpu=128100 memory=900 result=(con integer 0) -length=64 fields=[0] DropCase: cpu=128100 memory=900 result=(con integer 0) -length=64 fields=[1] Builtins: cpu=324913 memory=1164 result=(con integer 1) -length=64 fields=[1] DropHead: cpu=324913 memory=1164 result=(con integer 1) -length=64 fields=[1] Case: cpu=192100 memory=1300 result=(con integer 1) -length=64 fields=[1] DropCase: cpu=192100 memory=1300 result=(con integer 1) -length=64 fields=[2] Builtins: cpu=454576 memory=1496 result=(con integer 2) -length=64 fields=[2] DropHead: cpu=395875 memory=1336 result=(con integer 2) -length=64 fields=[2] Case: cpu=256100 memory=1700 result=(con integer 2) -length=64 fields=[2] DropCase: cpu=328725 memory=1404 result=(con integer 2) -length=64 fields=[3] Builtins: cpu=584239 memory=1828 result=(con integer 3) -length=64 fields=[3] DropHead: cpu=397832 memory=1336 result=(con integer 3) -length=64 fields=[3] Case: cpu=320100 memory=2100 result=(con integer 3) -length=64 fields=[3] DropCase: cpu=330682 memory=1404 result=(con integer 3) -length=64 fields=[4] Builtins: cpu=713902 memory=2160 result=(con integer 4) -length=64 fields=[4] DropHead: cpu=399789 memory=1336 result=(con integer 4) -length=64 fields=[4] Case: cpu=384100 memory=2500 result=(con integer 4) -length=64 fields=[4] DropCase: cpu=332639 memory=1404 result=(con integer 4) -length=64 fields=[5] Builtins: cpu=843565 memory=2492 result=(con integer 5) -length=64 fields=[5] DropHead: cpu=401746 memory=1336 result=(con integer 5) -length=64 fields=[5] Case: cpu=448100 memory=2900 result=(con integer 5) -length=64 fields=[5] DropCase: cpu=334596 memory=1404 result=(con integer 5) -length=64 fields=[0, 1] Builtins: cpu=621271 memory=1898 result=(con integer 1) -length=64 fields=[0, 1] DropHead: cpu=621271 memory=1898 result=(con integer 1) -length=64 fields=[0, 1] Case: cpu=357308 memory=1702 result=(con integer 1) -length=64 fields=[0, 1] DropCase: cpu=357308 memory=1702 result=(con integer 1) -length=64 fields=[0, 1, 2, 3] Builtins: cpu=1569313 memory=4630 result=(con integer 6) -length=64 fields=[0, 1, 2, 3] DropHead: cpu=1569313 memory=4630 result=(con integer 6) -length=64 fields=[0, 1, 2, 3] Case: cpu=815724 memory=3306 result=(con integer 6) -length=64 fields=[0, 1, 2, 3] DropCase: cpu=815724 memory=3306 result=(con integer 6) -length=64 fields=[0, 3] Builtins: cpu=880597 memory=2562 result=(con integer 3) -length=64 fields=[0, 3] DropHead: cpu=694190 memory=2070 result=(con integer 3) -length=64 fields=[0, 3] Case: cpu=485308 memory=2502 result=(con integer 3) -length=64 fields=[0, 3] DropCase: cpu=557933 memory=2206 result=(con integer 3) -length=64 fields=[2, 5, 6] Builtins: cpu=1661944 memory=4892 result=(con integer 13) -length=64 fields=[2, 5, 6] DropHead: cpu=1416836 memory=4240 result=(con integer 13) -length=64 fields=[2, 5, 6] Case: cpu=842516 memory=4104 result=(con integer 13) -length=64 fields=[2, 5, 6] DropCase: cpu=987766 memory=3512 result=(con integer 13) -length=64 head_and_tail=false case=false: cpu=193763 memory=832 result=(con (list integer) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]) -length=64 head_and_tail=false case=true: cpu=128100 memory=900 result=(con (list integer) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]) -length=64 head_and_tail=true case=false: cpu=356913 memory=1364 result=(constr 0 - (con integer 0) - (con (list integer) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63])) -length=64 head_and_tail=true case=true: cpu=160100 memory=1100 result=(constr 0 - (con integer 0) - (con (list integer) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63])) diff --git a/crates/nash-codegen/src/tests/integration.rs b/crates/nash-codegen/src/tests/integration.rs index b22f8d7f..e5b697bd 100644 --- a/crates/nash-codegen/src/tests/integration.rs +++ b/crates/nash-codegen/src/tests/integration.rs @@ -28,6 +28,10 @@ fn compile_selected( let mut interfaces = BTreeMap::from([("Builtin", nash_can::kinds::builtin_interface(bump))]); let mut modules = Vec::new(); for (text, package) in crate::harness::dependency_order([ + ( + include_str!("../../../nash-driver/base/src/Logic.nash"), + Some(primitives::BASE), + ), ( include_str!("../../../nash-driver/base/src/Function.nash"), Some(primitives::BASE), @@ -57,7 +61,7 @@ fn compile_selected( Some(primitives::BASE), ), ( - "module Logic exposing ((&&), (||), (==))\nimport Bool exposing (and, or)\nimport Builtin\ninfix right 2 (||) = or\ninfix right 3 (&&) = and\ninfix non 4 (==) = equal\nequal : int -> int -> bool\nequal = Builtin.equalsInteger\n", + "module TestLogic exposing ((==))\nimport Builtin\ninfix non 4 (==) = equal\nequal : int -> int -> bool\nequal = Builtin.equalsInteger\n", Some(primitives::BASE), ), ( @@ -226,6 +230,7 @@ fn captures_preserve_partial_application_order_and_lazy_branches() { import Builtin exposing (..) import Literal import Logic exposing (..) + import TestLogic exposing ((==)) compare : int -> int -> bool compare x = trace "partial" (\y -> Builtin.equalsInteger x y) one : int @@ -329,7 +334,7 @@ fn assertion_json_preserves_nested_call_delimiters_and_string_parentheses() { import Primitive exposing (..) import Builtin exposing (..) import Literal - import Logic exposing ((==)) + import TestLogic exposing ((==)) one : int one = 1 tests diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__captures_preserve_partial_application_order_and_lazy_branches_1_V3_Verbose.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__captures_preserve_partial_application_order_and_lazy_branches_1_V3_Verbose.snap index a0d8227a..eda1536b 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__captures_preserve_partial_application_order_and_lazy_branches_1_V3_Verbose.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__captures_preserve_partial_application_order_and_lazy_branches_1_V3_Verbose.snap @@ -19,63 +19,63 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [(lam i12 [(lam i13 [(lam i14 - [(lam i15 - [(lam i16 - [(lam i17 - [(lam i18 - [(lam i19 - [(lam i20 - [(lam i21 - [(lam i22 + (case + (force [[(force (builtin trace)) i14] (delay (con unit ()))]) + [(lam i15 + [(lam i16 + [(lam i17 + [(lam i18 + (case + (force [[(force (builtin trace)) i18] (delay (con unit ()))]) + [(lam i19 + [(lam i20 (case - [i18 i22] + [i17 i20] [[i11 i3] - (lam i23 - [(lam i24 - [(lam i25 - [(lam i26 - [(lam i27 + (lam i21 + [(lam i22 + [(lam i23 + [(lam i24 + [(lam i25 [[[i12 i5] - [[(lam i28 - [(lam i29 - [(lam i30 i30) - (lam i30 + [[(lam i26 + [(lam i27 + [(lam i28 i28) + (lam i28 (case - [[(builtin lessThanInteger) i30] [i26 (con integer 0)]] - [[i25 [[i25 i30] i28]] (builtin decodeUtf8)] - [[i25 - [[i25 [[i25 [[i25 i30] [(builtin subtractInteger) [i26 (con integer 0)]]]] i28]] + [[(builtin lessThanInteger) i28] [i24 (con integer 0)]] + [[i23 [[i23 i28] i26]] (builtin decodeUtf8)] + [[i23 + [[i23 [[i23 [[i23 i28] [(builtin subtractInteger) [i24 (con integer 0)]]]] i26]] (builtin decodeUtf8)]] - [(builtin appendString) [i29 i24]]]))]) - (lam i29 i29)]) - [(lam i28 [i28 i28]) - (lam i28 - (lam i29 + [(builtin appendString) [i27 i22]]]))]) + (lam i27 i27)]) + [(lam i26 [i26 i26]) + (lam i26 + (lam i27 (case - [[(builtin lessThanInteger) i29] [i26 (con integer 10)]] + [[(builtin lessThanInteger) i27] [i24 (con integer 10)]] [[(builtin appendByteString) - [[i28 i28] [[(builtin quotientInteger) i29] [i26 (con integer 10)]]]] + [[i26 i26] [[(builtin quotientInteger) i27] [i24 (con integer 10)]]]] [[(builtin consByteString) - [[(builtin addInteger) [i26 (con integer 48)]] - [[(builtin remainderInteger) i29] [i26 (con integer 10)]]]] - [i27 (con bytestring #)]]] - [[(builtin consByteString) [[(builtin addInteger) [i26 (con integer 48)]] i29]] - [i27 (con bytestring #)]])))]] - i16]] - (lam i28 (error))]) - (lam i27 i27)]) - (lam i26 i26)]) - (lam i25 (lam i26 [i26 i25]))]) + [[(builtin addInteger) [i24 (con integer 48)]] + [[(builtin remainderInteger) i27] [i24 (con integer 10)]]]] + [i25 (con bytestring #)]]] + [[(builtin consByteString) [[(builtin addInteger) [i24 (con integer 48)]] i27]] + [i25 (con bytestring #)]])))]] + i15]] + (lam i26 (error))]) + (lam i25 i25)]) + (lam i24 i24)]) + (lam i23 (lam i24 [i24 i23]))]) i4])] (con unit ()))) - i21]) - [i8 (con integer 2)]]) - (force [[(force (builtin trace)) i19] (delay (con unit ()))])]) + i19]) + [i8 (con integer 2)]])) [i6 i2]]) - [i13 i17]]) - i16]) - i9]) - (force [[(force (builtin trace)) i14] (delay (con unit ()))])]) + [i13 i16]]) + i15]) + i9])) [i6 i1]]) i7]) (lam i12 (lam i13 (lam i14 [[i11 [[(builtin appendString) i12] i13]] i14])))]) @@ -134,8 +134,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [i2 (con bool True)]]) (lam i6 (lam i7 [[[(force (builtin trace)) i6] i7] [i5 (con unit ())]]))]) (lam i5 i5)]) - (lam i4 - [(lam i5 (force [[(force (builtin trace)) [i3 i0]] (delay (error))])) i4])]) + (lam i4 (case i4 (force [[(force (builtin trace)) [i3 i0]] (delay (error))])))]) (lam i3 i3)]) (lam i2 i2)]) (con string "\0assert\0\48")]) @@ -173,8 +172,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport (lam i10 (lam i11 (lam i12 [[i9 [[(builtin appendString) i10] i11]] i12])))]) (lam i9 (lam i10 [[[(force (builtin trace)) i9] i10] [i8 (con unit ())]]))]) (lam i8 i8)]) - (lam i7 - [(lam i8 (force [[(force (builtin trace)) [i6 i0]] (delay (error))])) i7])]) + (lam i7 (case i7 (force [[(force (builtin trace)) [i6 i0]] (delay (error))])))]) (lam i6 i6)]) (lam i5 i5)]) (con string "\0assert\0\48\0\48\0")]) @@ -196,8 +194,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport (force [[(force (builtin trace)) [i2 i1]] (delay (error))]) [i5 (con unit ())])]) (lam i5 i5)]) - (lam i4 - [(lam i5 (force [[(force (builtin trace)) [i2 i0]] (delay (error))])) i4])]) + (lam i4 (case i4 (force [[(force (builtin trace)) [i2 i0]] (delay (error))])))]) (lam i3 i3)]) (lam i2 i2)]) (con string "wrong")]) diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__properties_thread_prng_bind_patterns_and_draw_without_running_body_1_V3_Verbose.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__properties_thread_prng_bind_patterns_and_draw_without_running_body_1_V3_Verbose.snap index 106dde0c..dd4fff30 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__properties_thread_prng_bind_patterns_and_draw_without_running_body_1_V3_Verbose.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__properties_thread_prng_bind_patterns_and_draw_without_running_body_1_V3_Verbose.snap @@ -45,27 +45,27 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport (lam i28 [(lam i29 [(lam i30 - [(lam i31 - [(lam i32 + (case + (force [[(force (builtin trace)) [i12 i2]] (delay [i13 (con unit ())])]) + [(lam i31 (case (case - i32 + i31 [i11 (con bool False)] [[(builtin equalsInteger) i29] [[(builtin addInteger) i23] [i10 (con integer 1)]]]) [[i16 i3] - (lam i33 - [(lam i34 - [(lam i35 - [(lam i36 - [(lam i37 [[[i17 i6] [i37 i32]] (lam i38 (error))]) - (lam i37 (case i37 [i36 i35] [i36 i34]))]) - (lam i36 i36)]) + (lam i32 + [(lam i33 + [(lam i34 + [(lam i35 + [(lam i36 [[[i17 i6] [i36 i31]] (lam i37 (error))]) + (lam i36 (case i36 [i35 i34] [i35 i33]))]) + (lam i35 i35)]) i5]) i4])] (con unit ()))) - i30]) - (force [[(force (builtin trace)) [i12 i2]] (delay [i13 (con unit ())])])]) + i30])) i28]) i27])))) i25]) @@ -149,10 +149,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [(lam i26 [(lam i27 [(lam i28 (constr 0 i28)) - (constr 0 - i27 - (lam i28 [(lam i29 [i19 i26]) i28]) - (lam i28 [(lam i29 [i20 i26]) i28]))]) + (constr 0 i27 (lam i28 (case i28 [i19 i26])) (lam i28 (case i28 [i20 i26])))]) i25]) i24])))) (constr 1))) diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_does_not_initialize_later_generators_V3_Verbose.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_does_not_initialize_later_generators_V3_Verbose.snap index 005146ab..45ec0431 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_does_not_initialize_later_generators_V3_Verbose.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_does_not_initialize_later_generators_V3_Verbose.snap @@ -226,10 +226,7 @@ description: "module Main exposing (..)\nimport Builtin\nimport Prop exposing (r [(lam i20 [(lam i21 [(lam i22 (constr 0 i22)) - (constr 0 - i21 - (lam i22 [(lam i23 [i13 i20]) i22]) - (lam i22 [(lam i23 [i14 i20]) i22]))]) + (constr 0 i21 (lam i22 (case i22 [i13 i20])) (lam i22 (case i22 [i14 i20])))]) i19]) i18])))) (constr 1))) diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V1_Silent.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V1_Silent.snap index 6fb73fde..6a2d450f 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V1_Silent.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V1_Silent.snap @@ -175,10 +175,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [(lam i16 [(lam i17 [(lam i18 (constr 0 i18)) - (constr 0 - i17 - (lam i18 [(lam i19 [i9 i16]) i18]) - (lam i18 [(lam i19 [i10 i16]) i18]))]) + (constr 0 i17 (lam i18 (case i18 [i9 i16])) (lam i18 (case i18 [i10 i16])))]) i15]) i14])))) (constr 1))) diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V2_Silent.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V2_Silent.snap index 6fb73fde..6a2d450f 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V2_Silent.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_2_V2_Silent.snap @@ -175,10 +175,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [(lam i16 [(lam i17 [(lam i18 (constr 0 i18)) - (constr 0 - i17 - (lam i18 [(lam i19 [i9 i16]) i18]) - (lam i18 [(lam i19 [i10 i16]) i18]))]) + (constr 0 i17 (lam i18 (case i18 [i9 i16])) (lam i18 (case i18 [i10 i16])))]) i15]) i14])))) (constr 1))) diff --git a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_3_V3_Silent.snap b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_3_V3_Silent.snap index 6fb73fde..6a2d450f 100644 --- a/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_3_V3_Silent.snap +++ b/crates/nash-codegen/src/tests/snapshots/nash_codegen__tests__integration__rejected_generator_skips_body_and_selected_target_is_enforced_3_V3_Silent.snap @@ -175,10 +175,7 @@ description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport [(lam i16 [(lam i17 [(lam i18 (constr 0 i18)) - (constr 0 - i17 - (lam i18 [(lam i19 [i9 i16]) i18]) - (lam i18 [(lam i19 [i10 i16]) i18]))]) + (constr 0 i17 (lam i18 (case i18 [i9 i16])) (lam i18 (case i18 [i10 i16])))]) i15]) i14])))) (constr 1))) diff --git a/crates/nash-docs/Cargo.toml b/crates/nash-docs/Cargo.toml new file mode 100644 index 00000000..b29dbb6d --- /dev/null +++ b/crates/nash-docs/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "nash-docs" +version = "0.1.0" +edition.workspace = true +description = "Documentation extraction and rendering for Nash" +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +bumpalo.workspace = true +tokio.workspace = true +serde_json.workspace = true +thiserror.workspace = true +nash-driver = { path = "../nash-driver", version = "0.11.0" } +nash-config = { path = "../nash-config", version = "0.5.0" } +nash-parse = { path = "../nash-parse", version = "0.8.0" } +nash-ast = { path = "../nash-ast", version = "0.11.0" } +nash-can = { path = "../nash-can", version = "0.12.0" } +nash-source = { path = "../nash-source", version = "0.9.0" } +nash-report = { path = "../nash-report", version = "0.5.3" } +serde.workspace = true +pulldown-cmark = { version = "0.13", default-features = false, features = ["html"] } + +[dev-dependencies] +tempfile = "3" +indoc.workspace = true +insta.workspace = true +url.workspace = true diff --git a/crates/nash-docs/src/assets/search.js b/crates/nash-docs/src/assets/search.js new file mode 100644 index 00000000..d9312683 --- /dev/null +++ b/crates/nash-docs/src/assets/search.js @@ -0,0 +1,35 @@ +(() => { + const root = new URL('.', document.currentScript.src); + const input = document.getElementById('search'); + const results = document.getElementById('search-results'); + const status = document.getElementById('search-status'); + let entries; + let failed = false; + const update = () => { + results.replaceChildren(); + const query = input.value.trim().toLowerCase(); + results.hidden = !query; + if (!query) { status.textContent = ''; return; } + if (failed) { status.textContent = 'Search unavailable. Browse the module links below.'; return; } + if (!entries) { status.textContent = 'Loading search…'; return; } + const matches = entries.filter(entry => `${entry.module} ${entry.name} ${entry.signature} ${entry.summary}`.toLowerCase().includes(query)); + status.textContent = `${matches.length} result${matches.length === 1 ? '' : 's'}`; + for (const entry of matches.slice(0, 40)) { + const link = document.createElement('a'); + link.href = new URL(entry.url, root).href; + link.textContent = entry.name; + const module = document.createElement('small'); + module.textContent = entry.module; + link.append(module); + results.append(link); + } + }; + input.addEventListener('input', update); + fetch(new URL('search.json', root)).then(response => { + if (!response.ok) throw new Error('Search unavailable'); + return response.json(); + }).then(data => { entries = data; update(); }).catch(() => { + failed = true; + update(); + }); +})(); diff --git a/crates/nash-docs/src/assets/style.css b/crates/nash-docs/src/assets/style.css new file mode 100644 index 00000000..2af4c5e6 --- /dev/null +++ b/crates/nash-docs/src/assets/style.css @@ -0,0 +1,38 @@ +:root { color-scheme: light dark; --bg: #fafaf8; --panel: #fff; --text: #20252b; --muted: #59636f; --line: #dce1e5; --accent: #176f65; } +* { box-sizing: border-box; } +body { margin: 0; background: var(--bg); color: var(--text); font: 16px/1.65 system-ui, sans-serif; } +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } +a:focus-visible, input:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; } +aside { position: fixed; inset: 0 auto 0 0; width: 270px; overflow-y: auto; padding: 28px 24px; border-right: 1px solid var(--line); background: var(--panel); } +.brand { display: block; margin-bottom: 28px; font-size: 26px; font-weight: 750; } +.brand span { display: block; color: var(--muted); font-size: 13px; font-weight: 450; letter-spacing: .08em; } +label { display: block; color: var(--muted); font-size: 13px; } +input { width: 100%; padding: 9px 10px; border: 1px solid var(--line); border-radius: 5px; background: var(--bg); color: var(--text); font: inherit; font-size: 14px; } +nav { display: grid; gap: 3px; margin-top: 20px; } +nav a { overflow-wrap: anywhere; padding: 3px 0; font-size: 14px; } +nav small { display: block; color: var(--muted); } +[hidden] { display: none; } +#search-status { font-size: 12px; color: var(--muted); } +main { max-width: 1250px; margin-left: 270px; padding: 40px 52px 100px; } +h1 { font-size: 38px; line-height: 1.2; margin: 0 0 28px; letter-spacing: -.03em; } +h2 { font-size: 21px; line-height: 1.4; overflow-wrap: anywhere; margin: 0; } +section { padding: 28px 0; border-top: 1px solid var(--line); scroll-margin-top: 20px; } +section header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 12px; } +.kind, .type-kind { color: var(--muted); font-size: 12px; } +.kind { text-transform: uppercase; letter-spacing: .06em; } +pre { overflow-x: auto; padding: 18px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; line-height: 1.6; } +code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .88em; } +p code { padding: 2px 4px; background: var(--panel); } +.keyword { color: #8b3895; font-weight: 600; } +.type { color: #236eb3; } +.string { color: #33772b; } +.number { color: #9c4e12; } +.operator { color: #9b3e3e; } +.comment { color: var(--muted); font-style: italic; } +table { border-collapse: collapse; } +th, td { border: 1px solid var(--line); padding: 8px 12px; text-align: left; } +.module-list { columns: 2; list-style: none; padding: 0; } +.module-list li { padding: 5px 0; } +@media (prefers-color-scheme: dark) { :root { --bg: #171c20; --panel: #1f262c; --text: #e2e8ed; --muted: #a3afb9; --line: #38444e; --accent: #72d4bd; } .keyword { color: #d5a0ed; } .type { color: #8dbefa; } .string { color: #a4d986; } .number { color: #f0bb79; } .operator { color: #eea6a2; } } +@media (max-width: 760px) { aside { position: static; width: 100%; max-height: 340px; border-right: 0; border-bottom: 1px solid var(--line); } main { margin-left: 0; padding: 30px 20px; } h1 { font-size: 30px; } .module-list { columns: 1; } } diff --git a/crates/nash-docs/src/extract.rs b/crates/nash-docs/src/extract.rs new file mode 100644 index 00000000..224947a5 --- /dev/null +++ b/crates/nash-docs/src/extract.rs @@ -0,0 +1,454 @@ +use crate::{Block, Declaration, DeclarationKind as K, DocsWarning, Extraction, ModuleDocs, types}; +use nash_can::Interface; +use nash_report::{ + localizer::Localizer, + render_type::{Ctx, src_to_doc}, +}; +use nash_source::{Comment, Docs, Module}; + +fn comment(comment: Option<&Comment<'_>>) -> String { + comment.map_or_else(String::new, |c| { + String::from_utf8_lossy(c.snippet.data).trim().to_owned() + }) +} + +/// Extract public declarations. Warnings never discard documentation. +pub fn extract(source: &Module<'_>, interface: &Interface<'_>) -> Extraction { + let name = interface.home.name.to_owned(); + let local = Localizer::from_module(source, &[]).with_package(interface.home.package); + let mut declarations = Vec::new(); + let mut warnings = Vec::new(); + let mut add = |line, name: &str, kind, signature, doc: String, require_doc| { + if require_doc && doc.is_empty() { + warnings.push(DocsWarning { + module: interface.home.name.into(), + name: name.into(), + message: "Export has no documentation comment.".into(), + }); + } + let type_kind = match kind { + K::Union => interface + .unions + .iter() + .find(|u| u.name == name) + .map(|u| types::kind(u.kind)), + K::Alias => interface + .aliases + .iter() + .find(|a| a.name == name) + .map(|a| types::kind(a.kind)), + _ => None, + }; + declarations.push(( + line, + Declaration { + name: name.into(), + kind, + signature, + type_kind, + doc, + }, + )); + }; + for value in interface.values { + let definition = source + .values + .iter() + .find(|v| v.value.name.value == value.name); + add( + definition.map_or(0, |v| v.region.start.line), + value.name, + K::Value, + format!( + "{} : {}", + value.name, + types::annotation(&local, value.annotation) + ), + comment(definition.and_then(|v| v.value.docs)), + true, + ); + } + for union in interface.unions.iter().filter_map(|u| u.to_public()) { + let definition = source + .unions + .iter() + .find(|u| u.value.name.value == union.name); + let mut signature = format!( + "type {}{}{}", + types::context(&local, union.context), + union.name, + parameters(union.parameters) + ); + if !union.ctors.is_empty() { + signature.push_str("\n = "); + signature.push_str( + &union + .ctors + .iter() + .map(|c| types::constructor(&local, c)) + .collect::>() + .join("\n | "), + ); + } + add( + definition.map_or(0, |v| v.region.start.line), + union.name, + K::Union, + signature, + comment(definition.and_then(|v| v.value.docs)), + true, + ); + } + for alias in interface.aliases.iter().filter_map(|a| a.to_public()) { + let definition = source + .aliases + .iter() + .find(|a| a.value.name.value == alias.name); + add( + definition.map_or(0, |v| v.region.start.line), + alias.name, + K::Alias, + format!( + "type alias {}{}{} = {}", + types::context(&local, alias.context), + alias.name, + parameters(alias.parameters), + types::typ(&local, &alias.typ.value, Ctx::None) + ), + comment(definition.and_then(|v| v.value.docs)), + true, + ); + } + for trait_ in interface.traits.iter().filter(|t| t.exported) { + let definition = source + .traits + .iter() + .find(|t| t.value.name.value == trait_.name); + let mut signature = format!( + "trait {}{}{} where", + types::context(&local, trait_.supers), + trait_.name, + parameters(trait_.parameters) + ); + for method in trait_.methods { + // The enclosing trait supplies its own predicate. + let context = &method.annotation.context[1..]; + signature.push_str(&format!( + "\n {} : {}{}", + method.name, + types::context(&local, context), + types::typ(&local, &method.annotation.typ.value, Ctx::None) + )); + } + add( + definition.map_or(0, |v| v.region.start.line), + trait_.name, + K::Trait, + signature, + comment(definition.and_then(|v| v.value.docs)), + true, + ); + } + for operator in interface.binops { + let definition = source.binops.iter().find(|b| b.value.op == operator.symbol); + let doc = comment( + source + .values + .iter() + .find(|v| { + operator.function.home == interface.home + && v.value.name.value == operator.function.name + }) + .and_then(|v| v.value.docs), + ); + let doc = if doc.is_empty() { + format!( + "Infix form of `{}.{}`.", + operator.function.home.name, operator.function.name + ) + } else { + doc + }; + let associativity = match operator.associativity { + nash_ast::Associativity::Left => "left", + nash_ast::Associativity::Right => "right", + nash_ast::Associativity::None => "non", + }; + add( + definition.map_or(0, |v| v.region.start.line), + &format!("({})", operator.symbol), + K::Operator, + format!( + "({}) : {}\ninfix {associativity} {} ({}) = {}", + operator.symbol, + types::annotation(&local, operator.annotation), + operator.precedence.0, + operator.symbol, + local + .to_doc(operator.function.home, operator.function.name) + .render(100, false) + ), + doc, + false, + ); + } + for implementation in source.impls { + let head = constraint(&implementation.value.head.value); + let context = implementation + .value + .context + .iter() + .map(|c| constraint(&c.value)) + .collect::>(); + let context = match context.as_slice() { + [] => String::new(), + [one] => format!("{one} => "), + _ => format!("({}) => ", context.join(", ")), + }; + let signature = format!("impl {context}{head}"); + add( + implementation.region.start.line, + &signature, + K::Implementation, + signature.clone(), + comment(implementation.value.docs), + false, + ); + } + declarations.sort_by_key(|(line, _)| *line); + let overview = match source.docs { + Docs::YesDocs { overview, .. } => comment(Some(overview)), + Docs::NoDocs(_) => String::new(), + }; + let mut pending: Vec<_> = declarations.into_iter().map(|(_, d)| Some(d)).collect(); + let mut blocks = Vec::new(); + let mut prose = String::new(); + let code_ranges: Vec<_> = pulldown_cmark::Parser::new(&overview) + .into_offset_iter() + .filter_map(|(event, range)| { + matches!( + event, + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(_)) + ) + .then_some(range) + }) + .collect(); + let mut seen = std::collections::HashSet::new(); + let mut lines = overview + .split_inclusive('\n') + .scan(0, |offset, line| { + let start = *offset; + *offset += line.len(); + Some((start, line.trim_end_matches('\n'))) + }) + .peekable(); + while let Some((offset, line)) = lines.next() { + let trimmed = line.trim_start(); + let directive = trimmed + .strip_prefix("@docs") + .filter(|rest| rest.is_empty() || rest.starts_with(char::is_whitespace)); + if let Some(rest) = directive.filter(|_| { + !code_ranges + .iter() + .any(|range| range.contains(&(offset + line.len() - trimmed.len()))) + }) { + push_prose(&mut blocks, &mut prose); + let mut names = rest.trim().to_owned(); + while names.is_empty() || names.ends_with(',') { + let Some((_, next)) = lines.peek().filter(|(_, next)| doc_names(next.trim())) + else { + break; + }; + names.push_str(next.trim()); + lines.next(); + } + if names.is_empty() { + warnings.push(DocsWarning { + module: name.clone(), + name: "@docs".into(), + message: "@docs requires at least one exported name.".into(), + }); + } + for item in names.split(',').map(str::trim).filter(|n| !n.is_empty()) { + let item = item.to_owned(); + if !seen.insert(item.clone()) { + warnings.push(DocsWarning { + module: name.clone(), + name: item, + message: "Repeated @docs entry.".into(), + }); + } else if let Some(entry) = pending + .iter_mut() + .find(|d| d.as_ref().is_some_and(|d| d.name == item)) + { + blocks.push(Block::Declaration(entry.take().unwrap())); + } else { + warnings.push(DocsWarning { + module: name.clone(), + name: item, + message: "@docs name is not exported by this module.".into(), + }); + } + } + } else { + prose.push_str(line); + prose.push('\n'); + } + } + push_prose(&mut blocks, &mut prose); + blocks.extend(pending.into_iter().flatten().map(Block::Declaration)); + Extraction { + module: ModuleDocs { name, blocks }, + warnings, + } +} + +fn doc_names(line: &str) -> bool { + !line.is_empty() + && line.trim_end_matches(',').split(',').all(|part| { + let name = part.trim(); + if name.starts_with('(') && name.ends_with(')') { + name.len() > 2 + && name[1..name.len() - 1] + .chars() + .all(|c| "+-/*=.$<>:&|^?%!~#".contains(c)) + } else { + name.starts_with(char::is_alphabetic) + && name + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '\'') + } + }) +} + +fn push_prose(blocks: &mut Vec, prose: &mut String) { + if !prose.trim().is_empty() { + blocks.push(Block::Text(prose.trim_matches('\n').to_owned())); + } + prose.clear(); +} +fn parameters(parameters: &[&str]) -> String { + parameters.iter().map(|p| format!(" '{p}")).collect() +} +fn constraint(constraint: &nash_source::Constraint<'_>) -> String { + let mut out = constraint.module.map_or_else( + || constraint.class.value.to_owned(), + |m| format!("{m}.{}", constraint.class.value), + ); + for arg in constraint.args { + out.push(' '); + out.push_str(&src_to_doc(Ctx::App, arg).render(100, false)); + } + out +} + +/// Compiler-owned modules have no source file, so document their actual catalog. +pub fn primitives() -> Vec { + use nash_ast::primitives::{ALIASES, BUILTINS, COERCE, PRIMITIVES, ReprTrait}; + let local = Localizer::from_names(["Primitive", "Builtin"]); + let builtins = BUILTINS + .iter() + .map(|b| { + Block::Declaration(Declaration { + name: b.name.into(), + kind: K::Builtin, + type_kind: None, + signature: format!( + "{} : {}{}", + b.name, + types::context(&local, b.context), + types::typ(&local, &b.typ.value, Ctx::None) + ), + doc: format!("Plutus Core `{}` builtin.", b.variant), + }) + }) + .collect(); + let mut primitive: Vec<_> = PRIMITIVES + .iter() + .map(|p| { + let mut doc = format!( + "{} representation; kind `{}`.", + match p.repr { + nash_ast::primitives::Repr::Big => "Data", + nash_ast::primitives::Repr::Const => "Constant", + nash_ast::primitives::Repr::Term => "Term", + }, + types::kind(p.kind) + ); + for (index, repr) in p.context { + doc.push_str(&format!( + " Parameter {} requires `{}`.", + index + 1, + repr.name() + )); + } + let mut signature = format!( + "type {}{}", + p.name, + (0..p.kind.arity()) + .map(|index| format!(" '{}", char::from(b'a' + index as u8))) + .collect::() + ); + if !p.ctors.is_empty() { + signature.push_str(" = "); + signature.push_str( + &p.ctors + .iter() + .map(|c| types::constructor(&local, c)) + .collect::>() + .join(" | "), + ); + } + Block::Declaration(Declaration { + name: p.name.into(), + kind: K::Primitive, + signature, + type_kind: Some(types::kind(p.kind)), + doc, + }) + }) + .collect(); + for alias in ALIASES { + primitive.push(Block::Declaration(Declaration { + name: alias.name.into(), + kind: K::Alias, + type_kind: Some(types::kind(alias.kind)), + signature: format!( + "type alias {}{}{} = {}", + types::context(&local, alias.context), + alias.name, + parameters(alias.parameters), + types::typ(&local, &alias.typ.value, Ctx::None) + ), + doc: + "Native map entries with storable keys and values; preserves order and duplicates." + .into(), + })); + } + for repr in ReprTrait::ALL { + primitive.push(Block::Declaration(Declaration { + name: repr.name().into(), + kind: K::Trait, + type_kind: None, + signature: format!("trait {} 'a", repr.name()), + doc: "Compiler-checked representation constraint; no runtime test is emitted.".into(), + })); + } + primitive.push(Block::Declaration(Declaration { + name: "coerce".into(), + kind: K::Value, + type_kind: None, + signature: format!("coerce : {}", types::annotation(&local, &COERCE)), + doc: "Unchecked coercion. The caller is responsible for the runtime representation.".into(), + })); + vec![ + ModuleDocs { + name: "Builtin".into(), + blocks: builtins, + }, + ModuleDocs { + name: "Primitive".into(), + blocks: primitive, + }, + ] +} diff --git a/crates/nash-docs/src/highlight.rs b/crates/nash-docs/src/highlight.rs new file mode 100644 index 00000000..0177f490 --- /dev/null +++ b/crates/nash-docs/src/highlight.rs @@ -0,0 +1,88 @@ +use bumpalo::Bump; + +pub fn escape(text: &str) -> String { + text.replace('&', "&") + .replace('<', "<") + .replace('>', ">") + .replace('"', """) + .replace('\'', "'") +} + +/// Highlight fragments with Nash's literal parsers and keyword/operator catalog. +/// Unfinished examples are still printable; unrecognized characters stay escaped. +pub fn highlight(source: &str) -> String { + let arena = Bump::new(); + let mut rest = source; + let mut output = String::new(); + while !rest.is_empty() { + let first = rest.chars().next().unwrap(); + let (len, class) = if rest.starts_with("--") { + (rest.find('\n').unwrap_or(rest.len()), "comment") + } else if rest.starts_with("{-") { + let mut depth = 1; + let mut end = 2; + while end < rest.len() && depth != 0 { + if rest[end..].starts_with("{-") { + depth += 1; + end += 2; + } else if rest[end..].starts_with("-}") { + depth -= 1; + end += 2; + } else { + end += rest[end..].chars().next().unwrap().len_utf8(); + } + } + (end, "comment") + } else if rest.starts_with('#') && rest.as_bytes().get(1) == Some(&b'"') + || first == '"' + || first.is_ascii_digit() + { + let mut parser = nash_parse::Parser::new(&arena, rest); + let class = if rest.starts_with("#\"") { + let _ = parser.bytes_literal(|_, _| (), |_, _, _| ()); + "string" + } else if first == '"' { + let _ = parser.string_literal(|_, _| (), |_, _, _| ()); + "string" + } else { + let _ = parser.number_literal(|_, _| (), |_, _, _| ()); + "number" + }; + ( + (rest.len() - parser.remaining().len()).max(first.len_utf8()), + class, + ) + } else if first.is_alphabetic() || first == '_' || first == '\'' { + let len = rest + .char_indices() + .take_while(|(_, c)| c.is_alphanumeric() || *c == '_' || *c == '\'') + .last() + .map_or(first.len_utf8(), |(i, c)| i + c.len_utf8()); + let word = &rest[..len]; + let class = if nash_parse::keyword::is_reserved(word) { + "keyword" + } else if first.is_uppercase() { + "type" + } else { + "" + }; + (len, class) + } else if first.is_ascii() && nash_parse::symbol::is_binop_char(first as u8) { + let len = rest + .bytes() + .take_while(|b| nash_parse::symbol::is_binop_char(*b)) + .count(); + (len, "operator") + } else { + (first.len_utf8(), "") + }; + let token = escape(&rest[..len]); + if class.is_empty() { + output.push_str(&token); + } else { + output.push_str(&format!("{token}")); + } + rest = &rest[len..]; + } + output +} diff --git a/crates/nash-docs/src/lib.rs b/crates/nash-docs/src/lib.rs new file mode 100644 index 00000000..79a2d30b --- /dev/null +++ b/crates/nash-docs/src/lib.rs @@ -0,0 +1,58 @@ +//! Owned documentation extracted from source comments and solved interfaces. +mod highlight; +pub mod project; +mod render; +pub use render::{Format, render}; +mod extract; +mod types; +pub use extract::{extract, primitives}; +use serde::Serialize; + +#[derive(Debug, Clone, Serialize)] +pub struct ModuleDocs { + pub name: String, + pub blocks: Vec, +} + +#[derive(Debug, Clone, Serialize)] +pub enum Block { + Text(String), + Declaration(Declaration), +} + +#[derive(Debug, Clone, Serialize)] +pub struct Declaration { + pub name: String, + pub kind: DeclarationKind, + pub signature: String, + pub type_kind: Option, + pub doc: String, +} + +#[derive(Debug, Clone, Copy, Serialize)] +pub enum DeclarationKind { + Value, + Union, + Alias, + Operator, + Trait, + Implementation, + Builtin, + Primitive, +} + +#[derive(Debug, Clone, Serialize)] +pub struct DocsWarning { + pub module: String, + pub name: String, + pub message: String, +} + +#[derive(Debug, Clone, Serialize)] +pub struct Extraction { + pub module: ModuleDocs, + pub warnings: Vec, +} + +#[cfg(test)] +mod tests; diff --git a/crates/nash-docs/src/project.rs b/crates/nash-docs/src/project.rs new file mode 100644 index 00000000..35f7f715 --- /dev/null +++ b/crates/nash-docs/src/project.rs @@ -0,0 +1,124 @@ +//! Run documentation extraction through the same solved frontend as builds. +use crate::{DocsWarning, ModuleDocs, extract, primitives}; +use nash_config::Config; +use nash_driver::{ + Database, DriverError, FileSystemSource, Project, build_graph_production, build_with, + bundled_base, +}; +use std::{ + collections::{BTreeMap, HashSet}, + path::Path, + sync::Arc, +}; +use tokio::sync::Mutex; + +pub struct Documentation { + pub compiler: nash_driver::BuildResult, + pub modules: Vec, + pub warnings: Vec, +} + +pub enum Input<'a> { + Base, + Project(&'a Path), +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + Driver(#[from] DriverError), + #[error( + "module {0} appears in multiple packages; generate documentation for each package separately" + )] + DuplicateModule(String), +} + +pub async fn build(input: Input<'_>) -> Result { + let db = Arc::new(Mutex::new(Database::new(FileSystemSource::new()))); + let base = matches!(input, Input::Base); + let mut packages = BTreeMap::new(); + let (origins, roots) = match input { + Input::Base => { + let modules = bundled_base::modules(); + let roots = modules.keys().cloned().collect::>(); + (modules, roots) + } + Input::Project(path) => { + let project = Project::load(path).await?; + for member in &project.members { + if let Config::Package(package) = &member.config { + packages.insert( + package.name.to_string(), + package + .exposed_modules + .flatten() + .into_iter() + .map(str::to_owned) + .collect::>(), + ); + } + } + let database = db.lock().await; + let origins = project.discover_modules_production(&database).await?; + let roots = project + .discover_own_modules(&database) + .await? + .into_keys() + .collect::>(); + (origins, roots) + } + }; + let graph = + build_graph_production(db.clone(), &origins.keys().cloned().collect::>()).await?; + let selected_roots = roots.clone(); + let (compiler, extracted) = build_with(db, &graph, &origins, move |solved| { + solved + .modules + .iter() + .filter(|m| { + selected_roots.contains(&m.uri) + && (base + || m.module.name.package.is_none_or(|p| { + packages + .get(&format!("{}/{}", p.author, p.project)) + .is_some_and(|exports| exports.contains(m.module.name.name)) + })) + }) + .map(|module| { + let parsed = nash_parse::Parser::new(solved.store, module.source) + .module() + .expect("solved source parses"); + let interface = + nash_can::from_module(solved.store, module.module, &module.annotations); + extract(&parsed, &interface) + }) + .collect::>() + }) + .await; + // The driver backend keeps one solved module per name. Detect collisions + // from its URI-keyed interfaces before an overwritten module can disappear. + for (uri, interface) in &compiler.interfaces { + if roots.contains(uri) + && compiler.interfaces.iter().any(|(other_uri, other)| { + uri != other_uri && interface.module_name == other.module_name + }) + { + return Err(Error::DuplicateModule(interface.module_name.clone())); + } + } + let mut modules = Vec::new(); + let mut warnings = Vec::new(); + for extraction in extracted.unwrap_or_default() { + modules.push(extraction.module); + warnings.extend(extraction.warnings); + } + if base && compiler.is_success() { + modules.extend(primitives()); + } + modules.sort_by(|a, b| a.name.cmp(&b.name)); + Ok(Documentation { + compiler, + modules, + warnings, + }) +} diff --git a/crates/nash-docs/src/render.rs b/crates/nash-docs/src/render.rs new file mode 100644 index 00000000..f80e51eb --- /dev/null +++ b/crates/nash-docs/src/render.rs @@ -0,0 +1,292 @@ +use crate::highlight::{escape, highlight}; +use crate::{Block, DeclarationKind, ModuleDocs}; +use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag, TagEnd}; +use serde::Serialize; +use std::collections::BTreeMap; + +pub const STYLE: &str = include_str!("assets/style.css"); +pub const SEARCH: &str = include_str!("assets/search.js"); + +#[derive(Clone, Copy, Debug)] +pub enum Format { + Html, + Markdown, +} + +#[derive(Serialize)] +struct SearchEntry<'a> { + module: &'a str, + name: &'a str, + kind: &'static str, + signature: &'a str, + summary: &'a str, + url: String, +} + +pub fn anchor(name: &str) -> String { + format!( + "entry-{}", + name.bytes().map(|b| format!("{b:02x}")).collect::() + ) +} +fn path(name: &str, extension: &str) -> String { + format!("{}.{extension}", name.replace('.', "/")) +} +fn kind(kind: DeclarationKind) -> &'static str { + match kind { + DeclarationKind::Value => "value", + DeclarationKind::Union => "type", + DeclarationKind::Alias => "alias", + DeclarationKind::Operator => "operator", + DeclarationKind::Trait => "trait", + DeclarationKind::Implementation => "implementation", + DeclarationKind::Builtin => "builtin", + DeclarationKind::Primitive => "primitive", + } +} + +/// Render a complete site or Markdown collection. I/O belongs to the frontend. +pub fn render(modules: &[ModuleDocs], format: Format) -> BTreeMap { + let mut modules: Vec<_> = modules.iter().collect(); + modules.sort_by(|a, b| a.name.cmp(&b.name)); + let mut files = BTreeMap::new(); + match format { + Format::Markdown => { + let mut index = "# Nash documentation\n\n".to_owned(); + for module in &modules { + let filename = path(&module.name, "md"); + index.push_str(&format!("- [{}]({filename})\n", module.name)); + files.insert(filename, markdown(module)); + } + files.insert("index.md".into(), index); + } + Format::Html => { + let mut index = "

Nash documentation

Public modules and their APIs.

    ".to_owned(); + let mut search = Vec::new(); + for module in &modules { + let filename = path(&module.name, "html"); + index.push_str(&format!( + "
  • {}
  • ", + escape(&filename), + escape(&module.name) + )); + let root = "../".repeat(module.name.matches('.').count()); + let mut body = format!("

    {}

    ", escape(&module.name)); + let overview = module + .blocks + .iter() + .filter_map(|block| match block { + Block::Text(text) => Some(text.as_str()), + _ => None, + }) + .collect::>() + .join("\n\n"); + let overview_parser = Parser::new(&overview); + for block in &module.blocks { + match block { + Block::Text(text) => body + .push_str(&prose(text, Some(overview_parser.reference_definitions()))), + Block::Declaration(entry) => { + let id = anchor(&entry.name); + body.push_str(&format!("
    {}

    {}

    {}
    ", kind(entry.kind), escape(&entry.name), highlight(&entry.signature))); + if let Some(kind) = &entry.type_kind { + body.push_str(&format!( + "

    Kind: {}

    ", + escape(kind) + )); + } + body.push_str(&prose(&entry.doc, None)); + body.push_str("
    \n"); + search.push(SearchEntry { + module: &module.name, + name: &entry.name, + kind: kind(entry.kind), + signature: &entry.signature, + summary: entry.doc.lines().next().unwrap_or(""), + url: format!("{filename}#{id}"), + }); + } + } + } + files.insert(filename, page(&module.name, &root, &modules, &body)); + } + index.push_str("
"); + files.insert( + "index.html".into(), + page("Nash documentation", "", &modules, &index), + ); + files.insert( + "search.json".into(), + serde_json::to_string_pretty(&search).expect("documentation strings serialize"), + ); + files.insert("style.css".into(), STYLE.into()); + files.insert("search.js".into(), SEARCH.into()); + } + } + files +} + +fn page(title: &str, root: &str, modules: &[&ModuleDocs], body: &str) -> String { + let links = modules + .iter() + .map(|module| { + format!( + "{}", + root, + escape(&path(&module.name, "html")), + escape(&module.name) + ) + }) + .collect::>() + .join("\n"); + format!( + r#" + + + + +{title} · Nash + + + + + +
{body}
+ + +"#, + title = escape(title) + ) +} + +fn safe_link(url: &str) -> bool { + !url.chars().any(char::is_control) + && url.split_once(':').is_none_or(|(scheme, _)| { + matches!( + scheme.to_ascii_lowercase().as_str(), + "http" | "https" | "mailto" + ) + }) +} +fn prose(source: &str, references: Option<&pulldown_cmark::RefDefs<'_>>) -> String { + let resolve = |link: pulldown_cmark::BrokenLink<'_>| { + references + .and_then(|refs| refs.get(&link.reference)) + .map(|definition| { + ( + definition.dest.to_string().into(), + definition.title.as_deref().unwrap_or("").to_string().into(), + ) + }) + }; + let mut parser = Parser::new_with_broken_link_callback( + source, + Options::ENABLE_TABLES | Options::ENABLE_STRIKETHROUGH, + Some(resolve), + ) + .peekable(); + let mut events = Vec::new(); + while let Some(event) = parser.next() { + match event { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(language))) + if language.split_whitespace().next() == Some("nash") => + { + let mut code = String::new(); + for part in parser.by_ref() { + match part { + Event::End(TagEnd::CodeBlock) => break, + Event::Text(text) => code.push_str(&text), + _ => {} + } + } + events.push(Event::Html( + format!( + "
{}
\n", + highlight(&code) + ) + .into(), + )); + } + Event::Html(html) | Event::InlineHtml(html) => events.push(Event::Text(html)), + Event::Start(Tag::Link { + link_type, + dest_url, + title, + id, + }) => events.push(Event::Start(Tag::Link { + link_type, + dest_url: if safe_link(&dest_url) { + dest_url + } else { + "".into() + }, + title, + id, + })), + Event::Start(Tag::Image { + link_type, + dest_url, + title, + id, + }) => events.push(Event::Start(Tag::Image { + link_type, + dest_url: if safe_link(&dest_url) { + dest_url + } else { + "".into() + }, + title, + id, + })), + other => events.push(other), + } + } + let mut html = String::new(); + pulldown_cmark::html::push_html(&mut html, events.into_iter()); + html +} + +pub fn markdown(module: &ModuleDocs) -> String { + let mut out = format!("# {}\n\n", module.name); + for block in &module.blocks { + match block { + Block::Text(text) => { + out.push_str(text); + out.push_str("\n\n"); + } + Block::Declaration(entry) => { + out.push_str(&format!( + "\n\n## {}\n\n", + anchor(&entry.name), + entry.name + )); + let fence = "`".repeat( + entry + .signature + .split(|c| c != '`') + .map(str::len) + .max() + .unwrap_or(0) + .max(2) + + 1, + ); + out.push_str(&format!("{fence}nash\n{}\n{fence}\n\n", entry.signature)); + if let Some(kind) = &entry.type_kind { + out.push_str(&format!("Kind: `{kind}`\n\n")); + } + if !entry.doc.is_empty() { + out.push_str(&entry.doc); + out.push_str("\n\n"); + } + } + } + } + out +} diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__compiler_owned_modules.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__compiler_owned_modules.snap new file mode 100644 index 00000000..24d471f2 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__compiler_owned_modules.snap @@ -0,0 +1,757 @@ +--- +source: crates/nash-docs/src/tests.rs +--- +- name: Builtin + blocks: + - Declaration: + name: addInteger + kind: Builtin + signature: "addInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `AddInteger` builtin." + - Declaration: + name: subtractInteger + kind: Builtin + signature: "subtractInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `SubtractInteger` builtin." + - Declaration: + name: multiplyInteger + kind: Builtin + signature: "multiplyInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `MultiplyInteger` builtin." + - Declaration: + name: divideInteger + kind: Builtin + signature: "divideInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `DivideInteger` builtin." + - Declaration: + name: quotientInteger + kind: Builtin + signature: "quotientInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `QuotientInteger` builtin." + - Declaration: + name: remainderInteger + kind: Builtin + signature: "remainderInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `RemainderInteger` builtin." + - Declaration: + name: modInteger + kind: Builtin + signature: "modInteger : int -> int -> int" + type_kind: ~ + doc: "Plutus Core `ModInteger` builtin." + - Declaration: + name: equalsInteger + kind: Builtin + signature: "equalsInteger : int -> int -> bool" + type_kind: ~ + doc: "Plutus Core `EqualsInteger` builtin." + - Declaration: + name: lessThanInteger + kind: Builtin + signature: "lessThanInteger : int -> int -> bool" + type_kind: ~ + doc: "Plutus Core `LessThanInteger` builtin." + - Declaration: + name: lessThanEqualsInteger + kind: Builtin + signature: "lessThanEqualsInteger : int -> int -> bool" + type_kind: ~ + doc: "Plutus Core `LessThanEqualsInteger` builtin." + - Declaration: + name: appendByteString + kind: Builtin + signature: "appendByteString : bytes -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `AppendByteString` builtin." + - Declaration: + name: consByteString + kind: Builtin + signature: "consByteString : int -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `ConsByteString` builtin." + - Declaration: + name: sliceByteString + kind: Builtin + signature: "sliceByteString : int -> int -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `SliceByteString` builtin." + - Declaration: + name: lengthOfByteString + kind: Builtin + signature: "lengthOfByteString : bytes -> int" + type_kind: ~ + doc: "Plutus Core `LengthOfByteString` builtin." + - Declaration: + name: indexByteString + kind: Builtin + signature: "indexByteString : bytes -> int -> int" + type_kind: ~ + doc: "Plutus Core `IndexByteString` builtin." + - Declaration: + name: equalsByteString + kind: Builtin + signature: "equalsByteString : bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `EqualsByteString` builtin." + - Declaration: + name: lessThanByteString + kind: Builtin + signature: "lessThanByteString : bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `LessThanByteString` builtin." + - Declaration: + name: lessThanEqualsByteString + kind: Builtin + signature: "lessThanEqualsByteString : bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `LessThanEqualsByteString` builtin." + - Declaration: + name: sha2_256 + kind: Builtin + signature: "sha2_256 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Sha2_256` builtin." + - Declaration: + name: sha3_256 + kind: Builtin + signature: "sha3_256 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Sha3_256` builtin." + - Declaration: + name: blake2b_256 + kind: Builtin + signature: "blake2b_256 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Blake2b_256` builtin." + - Declaration: + name: blake2b_224 + kind: Builtin + signature: "blake2b_224 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Blake2b_224` builtin." + - Declaration: + name: keccak_256 + kind: Builtin + signature: "keccak_256 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Keccak_256` builtin." + - Declaration: + name: ripemd_160 + kind: Builtin + signature: "ripemd_160 : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `Ripemd_160` builtin." + - Declaration: + name: verifyEd25519Signature + kind: Builtin + signature: "verifyEd25519Signature : bytes -> bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `VerifyEd25519Signature` builtin." + - Declaration: + name: verifyEcdsaSecp256k1Signature + kind: Builtin + signature: "verifyEcdsaSecp256k1Signature : bytes -> bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `VerifyEcdsaSecp256k1Signature` builtin." + - Declaration: + name: verifySchnorrSecp256k1Signature + kind: Builtin + signature: "verifySchnorrSecp256k1Signature : bytes -> bytes -> bytes -> bool" + type_kind: ~ + doc: "Plutus Core `VerifySchnorrSecp256k1Signature` builtin." + - Declaration: + name: appendString + kind: Builtin + signature: "appendString : string -> string -> string" + type_kind: ~ + doc: "Plutus Core `AppendString` builtin." + - Declaration: + name: equalsString + kind: Builtin + signature: "equalsString : string -> string -> bool" + type_kind: ~ + doc: "Plutus Core `EqualsString` builtin." + - Declaration: + name: encodeUtf8 + kind: Builtin + signature: "encodeUtf8 : string -> bytes" + type_kind: ~ + doc: "Plutus Core `EncodeUtf8` builtin." + - Declaration: + name: decodeUtf8 + kind: Builtin + signature: "decodeUtf8 : bytes -> string" + type_kind: ~ + doc: "Plutus Core `DecodeUtf8` builtin." + - Declaration: + name: ifThenElse + kind: Builtin + signature: "ifThenElse : bool -> 'a -> 'a -> 'a" + type_kind: ~ + doc: "Plutus Core `IfThenElse` builtin." + - Declaration: + name: chooseUnit + kind: Builtin + signature: "chooseUnit : unit -> 'a -> 'a" + type_kind: ~ + doc: "Plutus Core `ChooseUnit` builtin." + - Declaration: + name: trace + kind: Builtin + signature: "trace : string -> 'a -> 'a" + type_kind: ~ + doc: "Plutus Core `Trace` builtin." + - Declaration: + name: fstPair + kind: Builtin + signature: "fstPair : pair 'a 'b -> 'a" + type_kind: ~ + doc: "Plutus Core `FstPair` builtin." + - Declaration: + name: sndPair + kind: Builtin + signature: "sndPair : pair 'a 'b -> 'b" + type_kind: ~ + doc: "Plutus Core `SndPair` builtin." + - Declaration: + name: chooseList + kind: Builtin + signature: "chooseList : list 'a -> 'b -> 'b -> 'b" + type_kind: ~ + doc: "Plutus Core `ChooseList` builtin." + - Declaration: + name: mkCons + kind: Builtin + signature: "mkCons : 'a -> list 'a -> list 'a" + type_kind: ~ + doc: "Plutus Core `MkCons` builtin." + - Declaration: + name: headList + kind: Builtin + signature: "headList : list 'a -> 'a" + type_kind: ~ + doc: "Plutus Core `HeadList` builtin." + - Declaration: + name: tailList + kind: Builtin + signature: "tailList : list 'a -> list 'a" + type_kind: ~ + doc: "Plutus Core `TailList` builtin." + - Declaration: + name: nullList + kind: Builtin + signature: "nullList : list 'a -> bool" + type_kind: ~ + doc: "Plutus Core `NullList` builtin." + - Declaration: + name: dropList + kind: Builtin + signature: "dropList : int -> list 'a -> list 'a" + type_kind: ~ + doc: "Plutus Core `DropList` builtin." + - Declaration: + name: chooseData + kind: Builtin + signature: "chooseData : Data -> 'a -> 'a -> 'a -> 'a -> 'a -> 'a" + type_kind: ~ + doc: "Plutus Core `ChooseData` builtin." + - Declaration: + name: constrData + kind: Builtin + signature: "constrData : int -> list Data -> Data" + type_kind: ~ + doc: "Plutus Core `ConstrData` builtin." + - Declaration: + name: mapData + kind: Builtin + signature: "mapData : (Big 'a, Big 'b) => map 'a 'b -> Map 'a 'b" + type_kind: ~ + doc: "Plutus Core `MapData` builtin." + - Declaration: + name: listData + kind: Builtin + signature: "listData : Big 'a => list 'a -> List 'a" + type_kind: ~ + doc: "Plutus Core `ListData` builtin." + - Declaration: + name: iData + kind: Builtin + signature: "iData : int -> Int" + type_kind: ~ + doc: "Plutus Core `IData` builtin." + - Declaration: + name: bData + kind: Builtin + signature: "bData : bytes -> Bytes" + type_kind: ~ + doc: "Plutus Core `BData` builtin." + - Declaration: + name: unConstrData + kind: Builtin + signature: "unConstrData : Data -> pair int (list Data)" + type_kind: ~ + doc: "Plutus Core `UnConstrData` builtin." + - Declaration: + name: unMapData + kind: Builtin + signature: "unMapData : (Big 'a, Big 'b) => Map 'a 'b -> map 'a 'b" + type_kind: ~ + doc: "Plutus Core `UnMapData` builtin." + - Declaration: + name: unListData + kind: Builtin + signature: "unListData : Big 'a => List 'a -> list 'a" + type_kind: ~ + doc: "Plutus Core `UnListData` builtin." + - Declaration: + name: unIData + kind: Builtin + signature: "unIData : Int -> int" + type_kind: ~ + doc: "Plutus Core `UnIData` builtin." + - Declaration: + name: unBData + kind: Builtin + signature: "unBData : Bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `UnBData` builtin." + - Declaration: + name: equalsData + kind: Builtin + signature: "equalsData : Data -> Data -> bool" + type_kind: ~ + doc: "Plutus Core `EqualsData` builtin." + - Declaration: + name: serialiseData + kind: Builtin + signature: "serialiseData : Data -> bytes" + type_kind: ~ + doc: "Plutus Core `SerialiseData` builtin." + - Declaration: + name: mkPairData + kind: Builtin + signature: "mkPairData : (Big 'a, Big 'b) => 'a -> 'b -> pair 'a 'b" + type_kind: ~ + doc: "Plutus Core `MkPairData` builtin." + - Declaration: + name: mkNilData + kind: Builtin + signature: "mkNilData : unit -> list Data" + type_kind: ~ + doc: "Plutus Core `MkNilData` builtin." + - Declaration: + name: mkNilPairData + kind: Builtin + signature: "mkNilPairData : unit -> map Data Data" + type_kind: ~ + doc: "Plutus Core `MkNilPairData` builtin." + - Declaration: + name: bls12_381_g1_add + kind: Builtin + signature: "bls12_381_g1_add : bls_g1 -> bls_g1 -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_Add` builtin." + - Declaration: + name: bls12_381_g1_neg + kind: Builtin + signature: "bls12_381_g1_neg : bls_g1 -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_Neg` builtin." + - Declaration: + name: bls12_381_g1_scalarMul + kind: Builtin + signature: "bls12_381_g1_scalarMul : int -> bls_g1 -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_ScalarMul` builtin." + - Declaration: + name: bls12_381_g1_equal + kind: Builtin + signature: "bls12_381_g1_equal : bls_g1 -> bls_g1 -> bool" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_Equal` builtin." + - Declaration: + name: bls12_381_g1_compress + kind: Builtin + signature: "bls12_381_g1_compress : bls_g1 -> bytes" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_Compress` builtin." + - Declaration: + name: bls12_381_g1_uncompress + kind: Builtin + signature: "bls12_381_g1_uncompress : bytes -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_Uncompress` builtin." + - Declaration: + name: bls12_381_g1_hashToGroup + kind: Builtin + signature: "bls12_381_g1_hashToGroup : bytes -> bytes -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_HashToGroup` builtin." + - Declaration: + name: bls12_381_g1_multiScalarMul + kind: Builtin + signature: "bls12_381_g1_multiScalarMul : list int -> list bls_g1 -> bls_g1" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G1_MultiScalarMul` builtin." + - Declaration: + name: bls12_381_g2_add + kind: Builtin + signature: "bls12_381_g2_add : bls_g2 -> bls_g2 -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_Add` builtin." + - Declaration: + name: bls12_381_g2_neg + kind: Builtin + signature: "bls12_381_g2_neg : bls_g2 -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_Neg` builtin." + - Declaration: + name: bls12_381_g2_scalarMul + kind: Builtin + signature: "bls12_381_g2_scalarMul : int -> bls_g2 -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_ScalarMul` builtin." + - Declaration: + name: bls12_381_g2_equal + kind: Builtin + signature: "bls12_381_g2_equal : bls_g2 -> bls_g2 -> bool" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_Equal` builtin." + - Declaration: + name: bls12_381_g2_compress + kind: Builtin + signature: "bls12_381_g2_compress : bls_g2 -> bytes" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_Compress` builtin." + - Declaration: + name: bls12_381_g2_uncompress + kind: Builtin + signature: "bls12_381_g2_uncompress : bytes -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_Uncompress` builtin." + - Declaration: + name: bls12_381_g2_hashToGroup + kind: Builtin + signature: "bls12_381_g2_hashToGroup : bytes -> bytes -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_HashToGroup` builtin." + - Declaration: + name: bls12_381_g2_multiScalarMul + kind: Builtin + signature: "bls12_381_g2_multiScalarMul : list int -> list bls_g2 -> bls_g2" + type_kind: ~ + doc: "Plutus Core `Bls12_381_G2_MultiScalarMul` builtin." + - Declaration: + name: bls12_381_millerLoop + kind: Builtin + signature: "bls12_381_millerLoop : bls_g1 -> bls_g2 -> bls_mlr" + type_kind: ~ + doc: "Plutus Core `Bls12_381_MillerLoop` builtin." + - Declaration: + name: bls12_381_mulMlResult + kind: Builtin + signature: "bls12_381_mulMlResult : bls_mlr -> bls_mlr -> bls_mlr" + type_kind: ~ + doc: "Plutus Core `Bls12_381_MulMlResult` builtin." + - Declaration: + name: bls12_381_finalVerify + kind: Builtin + signature: "bls12_381_finalVerify : bls_mlr -> bls_mlr -> bool" + type_kind: ~ + doc: "Plutus Core `Bls12_381_FinalVerify` builtin." + - Declaration: + name: integerToByteString + kind: Builtin + signature: "integerToByteString : bool -> int -> int -> bytes" + type_kind: ~ + doc: "Plutus Core `IntegerToByteString` builtin." + - Declaration: + name: byteStringToInteger + kind: Builtin + signature: "byteStringToInteger : bool -> bytes -> int" + type_kind: ~ + doc: "Plutus Core `ByteStringToInteger` builtin." + - Declaration: + name: andByteString + kind: Builtin + signature: "andByteString : bool -> bytes -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `AndByteString` builtin." + - Declaration: + name: orByteString + kind: Builtin + signature: "orByteString : bool -> bytes -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `OrByteString` builtin." + - Declaration: + name: xorByteString + kind: Builtin + signature: "xorByteString : bool -> bytes -> bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `XorByteString` builtin." + - Declaration: + name: complementByteString + kind: Builtin + signature: "complementByteString : bytes -> bytes" + type_kind: ~ + doc: "Plutus Core `ComplementByteString` builtin." + - Declaration: + name: readBit + kind: Builtin + signature: "readBit : bytes -> int -> bool" + type_kind: ~ + doc: "Plutus Core `ReadBit` builtin." + - Declaration: + name: writeBits + kind: Builtin + signature: "writeBits : bytes -> list int -> bool -> bytes" + type_kind: ~ + doc: "Plutus Core `WriteBits` builtin." + - Declaration: + name: replicateByte + kind: Builtin + signature: "replicateByte : int -> int -> bytes" + type_kind: ~ + doc: "Plutus Core `ReplicateByte` builtin." + - Declaration: + name: shiftByteString + kind: Builtin + signature: "shiftByteString : bytes -> int -> bytes" + type_kind: ~ + doc: "Plutus Core `ShiftByteString` builtin." + - Declaration: + name: rotateByteString + kind: Builtin + signature: "rotateByteString : bytes -> int -> bytes" + type_kind: ~ + doc: "Plutus Core `RotateByteString` builtin." + - Declaration: + name: countSetBits + kind: Builtin + signature: "countSetBits : bytes -> int" + type_kind: ~ + doc: "Plutus Core `CountSetBits` builtin." + - Declaration: + name: findFirstSetBit + kind: Builtin + signature: "findFirstSetBit : bytes -> int" + type_kind: ~ + doc: "Plutus Core `FindFirstSetBit` builtin." + - Declaration: + name: expModInteger + kind: Builtin + signature: "expModInteger : int -> int -> int -> int" + type_kind: ~ + doc: "Plutus Core `ExpModInteger` builtin." + - Declaration: + name: lengthOfArray + kind: Builtin + signature: "lengthOfArray : array 'a -> int" + type_kind: ~ + doc: "Plutus Core `LengthOfArray` builtin." + - Declaration: + name: listToArray + kind: Builtin + signature: "listToArray : list 'a -> array 'a" + type_kind: ~ + doc: "Plutus Core `ListToArray` builtin." + - Declaration: + name: indexArray + kind: Builtin + signature: "indexArray : array 'a -> int -> 'a" + type_kind: ~ + doc: "Plutus Core `IndexArray` builtin." + - Declaration: + name: insertCoin + kind: Builtin + signature: "insertCoin : bytes -> bytes -> int -> value -> value" + type_kind: ~ + doc: "Plutus Core `InsertCoin` builtin." + - Declaration: + name: lookupCoin + kind: Builtin + signature: "lookupCoin : bytes -> bytes -> value -> int" + type_kind: ~ + doc: "Plutus Core `LookupCoin` builtin." + - Declaration: + name: unionValue + kind: Builtin + signature: "unionValue : value -> value -> value" + type_kind: ~ + doc: "Plutus Core `UnionValue` builtin." + - Declaration: + name: valueContains + kind: Builtin + signature: "valueContains : value -> value -> bool" + type_kind: ~ + doc: "Plutus Core `ValueContains` builtin." + - Declaration: + name: valueData + kind: Builtin + signature: "valueData : value -> Data" + type_kind: ~ + doc: "Plutus Core `ValueData` builtin." + - Declaration: + name: unValueData + kind: Builtin + signature: "unValueData : Data -> value" + type_kind: ~ + doc: "Plutus Core `UnValueData` builtin." + - Declaration: + name: scaleValue + kind: Builtin + signature: "scaleValue : int -> value -> value" + type_kind: ~ + doc: "Plutus Core `ScaleValue` builtin." +- name: Primitive + blocks: + - Declaration: + name: Data + kind: Primitive + signature: type Data = Constr (pair int (list Data)) | Map (map Data Data) | List (list Data) | I int | B bytes + type_kind: Type + doc: "Data representation; kind `Type`." + - Declaration: + name: Int + kind: Primitive + signature: type Int + type_kind: Type + doc: "Data representation; kind `Type`." + - Declaration: + name: Bytes + kind: Primitive + signature: type Bytes + type_kind: Type + doc: "Data representation; kind `Type`." + - Declaration: + name: List + kind: Primitive + signature: "type List 'a" + type_kind: Type -> Type + doc: "Data representation; kind `Type -> Type`. Parameter 1 requires `Big`." + - Declaration: + name: Map + kind: Primitive + signature: "type Map 'a 'b" + type_kind: Type -> Type -> Type + doc: "Data representation; kind `Type -> Type -> Type`. Parameter 1 requires `Big`. Parameter 2 requires `Big`." + - Declaration: + name: int + kind: Primitive + signature: type int + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: bytes + kind: Primitive + signature: type bytes + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: string + kind: Primitive + signature: type string + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: bool + kind: Primitive + signature: type bool = False | True + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: unit + kind: Primitive + signature: type unit + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: bls_g1 + kind: Primitive + signature: type bls_g1 + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: bls_g2 + kind: Primitive + signature: type bls_g2 + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: bls_mlr + kind: Primitive + signature: type bls_mlr + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: value + kind: Primitive + signature: type value + type_kind: Type + doc: "Constant representation; kind `Type`." + - Declaration: + name: list + kind: Primitive + signature: "type list 'a" + type_kind: Type -> Type + doc: "Constant representation; kind `Type -> Type`. Parameter 1 requires `Storable`." + - Declaration: + name: array + kind: Primitive + signature: "type array 'a" + type_kind: Type -> Type + doc: "Constant representation; kind `Type -> Type`. Parameter 1 requires `Storable`." + - Declaration: + name: pair + kind: Primitive + signature: "type pair 'a 'b" + type_kind: Type -> Type -> Type + doc: "Constant representation; kind `Type -> Type -> Type`. Parameter 1 requires `Storable`. Parameter 2 requires `Storable`." + - Declaration: + name: map + kind: Alias + signature: "type alias map 'k 'v = list (pair 'k 'v)" + type_kind: Type -> Type -> Type + doc: Native map entries with storable keys and values; preserves order and duplicates. + - Declaration: + name: Big + kind: Trait + signature: "trait Big 'a" + type_kind: ~ + doc: Compiler-checked representation constraint; no runtime test is emitted. + - Declaration: + name: Const + kind: Trait + signature: "trait Const 'a" + type_kind: ~ + doc: Compiler-checked representation constraint; no runtime test is emitted. + - Declaration: + name: Term + kind: Trait + signature: "trait Term 'a" + type_kind: ~ + doc: Compiler-checked representation constraint; no runtime test is emitted. + - Declaration: + name: Storable + kind: Trait + signature: "trait Storable 'a" + type_kind: ~ + doc: Compiler-checked representation constraint; no runtime test is emitted. + - Declaration: + name: Little + kind: Trait + signature: "trait Little 'a" + type_kind: ~ + doc: Compiler-checked representation constraint; no runtime test is emitted. + - Declaration: + name: coerce + kind: Value + signature: "coerce : 'a -> 'b" + type_kind: ~ + doc: Unchecked coercion. The caller is responsible for the runtime representation. diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__constrained_types.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__constrained_types.snap new file mode 100644 index 00000000..f3dde970 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__constrained_types.snap @@ -0,0 +1,18 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (render)\n{-| Render a value with its Show instance. -}\nrender : Show 'a => 'a -> string\nrender value = show value\n" +--- +module: + name: Example + blocks: + - Text: Render a value with its Show instance. + - Declaration: + name: render + kind: Value + signature: "render : Show.Show 'a => 'a -> string" + type_kind: ~ + doc: "" +warnings: + - module: Example + name: render + message: Export has no documentation comment. diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__highlight_fragments.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__highlight_fragments.snap new file mode 100644 index 00000000..4837f37b --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__highlight_fragments.snap @@ -0,0 +1,13 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "-- A comment\n{- Nested {- comment -} λ -}\nrun : int -> int\nrun value = if value < 0 then -value else value\nbytes = #\"00ab\"\ntext = \"\n\n[Unsafe link](javascript:alert%281%29)\n-}\nidentity x = x\n" +--- +--- Example.html + + + + + +Example · Nash + + + + + +

Example

Public API with a link.

+
value

identity

identity : 'a -> 'a

Preserve a value.

+
identity "hello"
+
+<script>alert("raw HTML")</script> +

Unsafe link

+
+
+ + + +--- index.html + + + + + +Nash documentation · Nash + + + + + +

Nash documentation

Public modules and their APIs.

+ + + +--- search.json +[ + { + "module": "Example", + "name": "identity", + "kind": "value", + "signature": "identity : 'a -> 'a", + "summary": "Preserve a value.", + "url": "Example.html#entry-6964656e74697479" + } +] diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__markdown_output.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__markdown_output.snap new file mode 100644 index 00000000..d3747f2f --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__markdown_output.snap @@ -0,0 +1,52 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (type box(..), identity, (%%))\n{-| # A small API\n\n@docs box, identity, (%%)\n-}\n\ninfix left 5 (%%) = combine\n\n{-| A little container. -}\ntype box 'a = Box 'a\n\n{-| Preserve a value.\n\n```nash\nidentity 42\n```\n-}\nidentity x = x\n\ncombine x y = x\n" +--- +--- Example.md +# Example + +# A small API + + + +## box + +```nash +type box 'a + = Box 'a +``` + +Kind: `Type -> Type` + +A little container. + + + +## identity + +```nash +identity : 'a -> 'a +``` + +Preserve a value. + +```nash +identity 42 +``` + + + +## (%%) + +```nash +(%%) : 'a -> 'b -> 'a +infix left 5 (%%) = combine +``` + +Infix form of `Example.combine`. + + +--- index.md +# Nash documentation + +- [Example](Example.md) diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__overview_markdown_boundaries.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__overview_markdown_boundaries.snap new file mode 100644 index 00000000..76759fa4 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__overview_markdown_boundaries.snap @@ -0,0 +1,22 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (first, second)\n{-| Order and prose.\n\n@docs\n second,\n## Keep this heading\n\n````nash\n```\n@docs first\n````\n\n @docs alsoCode\n\n@docs first\n-}\n{-| First value. -}\nfirst x = x\n{-| Second value. -}\nsecond x = x\n" +--- +module: + name: Example + blocks: + - Text: Order and prose. + - Declaration: + name: second + kind: Value + signature: "second : 'a -> 'a" + type_kind: ~ + doc: Second value. + - Text: "## Keep this heading\n\n````nash\n```\n@docs first\n````\n\n @docs alsoCode" + - Declaration: + name: first + kind: Value + signature: "first : 'a -> 'a" + type_kind: ~ + doc: First value. +warnings: [] diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__project_exports.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__project_exports.snap new file mode 100644 index 00000000..1e288ab8 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__project_exports.snap @@ -0,0 +1,27 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Public.Api exposing (answer)\n{-| The answer. -}\nanswer = 42\n" +--- + + + + + +Public.Api · Nash + + + + + +

Public.Api

The answer.

+
value

answer

answer : Literal.FromInt 'a => 'a
+
+ + diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__public_declarations.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__public_declarations.snap new file mode 100644 index 00000000..68d51d25 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__public_declarations.snap @@ -0,0 +1,52 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (id, type box(..), type secret, type record, Keep, (%%))\n{-| Example API.\n\n@docs Keep, id\n\nTypes below.\n\n@docs box, record, secret, (%%)\n-}\n\ninfix left 5 (%%) = combine\n\n{-| Keep a value unchanged. -}\ntrait Keep 'a where\n keep : 'a -> 'a\n\n{-| Identity implementation. -}\nimpl Keep int where\n keep x = x\n\n{-| Preserve the argument. -}\nid x = x\n\n{-| One little payload. -}\ntype box 'a = Box 'a\n\n{-| A hidden constructor. -}\ntype secret = Secret int\n\n{-| A labeled record. -}\ntype alias record = { value : int }\n\ncombine x y = x\nprivate x = x\n" +--- +module: + name: Example + blocks: + - Text: Example API. + - Declaration: + name: Keep + kind: Trait + signature: "trait Keep 'a where\n keep : 'a -> 'a" + type_kind: ~ + doc: Keep a value unchanged. + - Declaration: + name: id + kind: Value + signature: "id : 'a -> 'a" + type_kind: ~ + doc: Preserve the argument. + - Text: Types below. + - Declaration: + name: box + kind: Union + signature: "type box 'a\n = Box 'a" + type_kind: Type -> Type + doc: One little payload. + - Declaration: + name: record + kind: Alias + signature: "type alias record = { value : int }" + type_kind: Type + doc: A labeled record. + - Declaration: + name: secret + kind: Union + signature: type secret + type_kind: Type + doc: A hidden constructor. + - Declaration: + name: (%%) + kind: Operator + signature: "(%%) : 'a -> 'b -> 'a\ninfix left 5 (%%) = combine" + type_kind: ~ + doc: "Infix form of `Example.combine`." + - Declaration: + name: impl Keep int + kind: Implementation + signature: impl Keep int + type_kind: ~ + doc: Identity implementation. +warnings: [] diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__same_trait_method_constraint.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__same_trait_method_constraint.snap new file mode 100644 index 00000000..1f7bc087 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__same_trait_method_constraint.snap @@ -0,0 +1,18 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (Keep)\n{-| A method may require the same trait at another type. -}\ntrait Keep 'a where\n other : Keep 'b => 'b -> 'a\n" +--- +module: + name: Example + blocks: + - Text: A method may require the same trait at another type. + - Declaration: + name: Keep + kind: Trait + signature: "trait Keep 'a where\n other : Keep 'b => 'b -> 'a" + type_kind: ~ + doc: "" +warnings: + - module: Example + name: Keep + message: Export has no documentation comment. diff --git a/crates/nash-docs/src/snapshots/nash_docs__tests__warnings_keep_output.snap b/crates/nash-docs/src/snapshots/nash_docs__tests__warnings_keep_output.snap new file mode 100644 index 00000000..e0def918 --- /dev/null +++ b/crates/nash-docs/src/snapshots/nash_docs__tests__warnings_keep_output.snap @@ -0,0 +1,25 @@ +--- +source: crates/nash-docs/src/tests.rs +description: "module Example exposing (id)\n{-| Still rendered.\n\n@docs id, missing, id\n\n```nash\n@docs notADirective\n```\n-}\nid x = x\n" +--- +module: + name: Example + blocks: + - Text: Still rendered. + - Declaration: + name: id + kind: Value + signature: "id : 'a -> 'a" + type_kind: ~ + doc: "" + - Text: "```nash\n@docs notADirective\n```" +warnings: + - module: Example + name: id + message: Export has no documentation comment. + - module: Example + name: missing + message: "@docs name is not exported by this module." + - module: Example + name: id + message: Repeated @docs entry. diff --git a/crates/nash-docs/src/tests.rs b/crates/nash-docs/src/tests.rs new file mode 100644 index 00000000..2ee8a4d2 --- /dev/null +++ b/crates/nash-docs/src/tests.rs @@ -0,0 +1,374 @@ +use super::*; +use nash_driver::{Database, InMemorySource, build_graph_production, build_with, bundled_base}; +use std::sync::Arc; +use tokio::sync::Mutex; +use url::Url; + +async fn documented(source: &str) -> Extraction { + let uri = Url::parse("file:///docs/src/Example.nash").unwrap(); + let memory = InMemorySource::with_files([(uri.clone(), source.into())]); + let mut origins = bundled_base::modules(); + origins.insert(uri.clone(), None); + let db = Arc::new(Mutex::new(Database::new(memory))); + let graph = build_graph_production(db.clone(), &origins.keys().cloned().collect::>()) + .await + .unwrap(); + let (result, docs) = build_with(db, &graph, &origins, move |solved| { + let module = solved.modules.iter().find(|m| m.uri == uri).unwrap(); + let source = nash_parse::Parser::new(solved.store, module.source) + .module() + .unwrap(); + extract( + &source, + &nash_can::from_module(solved.store, module.module, &module.annotations), + ) + }) + .await; + assert!(result.is_success(), "{:?}", result.ordered_reports()); + docs.unwrap() +} + +macro_rules! assert_docs_snapshot { + ($source:expr) => {{ + let source = indoc::indoc!($source); + let output = documented(source).await; + insta::with_settings!({description => source, omit_expression => true}, { insta::assert_yaml_snapshot!(output); }); + }}; +} + +#[tokio::test] +async fn public_declarations() { + assert_docs_snapshot!( + r#" + module Example exposing (id, type box(..), type secret, type record, Keep, (%%)) + {-| Example API. + + @docs Keep, id + + Types below. + + @docs box, record, secret, (%%) + -} + + infix left 5 (%%) = combine + + {-| Keep a value unchanged. -} + trait Keep 'a where + keep : 'a -> 'a + + {-| Identity implementation. -} + impl Keep int where + keep x = x + + {-| Preserve the argument. -} + id x = x + + {-| One little payload. -} + type box 'a = Box 'a + + {-| A hidden constructor. -} + type secret = Secret int + + {-| A labeled record. -} + type alias record = { value : int } + + combine x y = x + private x = x + "# + ); +} + +#[tokio::test] +async fn warnings_keep_output() { + assert_docs_snapshot!( + r#" + module Example exposing (id) + {-| Still rendered. + + @docs id, missing, id + + ```nash + @docs notADirective + ``` + -} + id x = x + "# + ); +} + +#[tokio::test] +async fn constrained_types() { + assert_docs_snapshot!( + r#" + module Example exposing (render) + {-| Render a value with its Show instance. -} + render : Show 'a => 'a -> string + render value = show value + "# + ); +} + +#[test] +fn compiler_owned_modules() { + insta::with_settings!({omit_expression => true}, { insta::assert_yaml_snapshot!(primitives()); }); +} + +#[tokio::test] +async fn base_documentation() { + let docs = project::build(project::Input::Base).await.unwrap(); + assert!( + docs.compiler.is_success(), + "{:?}", + docs.compiler.ordered_reports() + ); + assert!(docs.warnings.is_empty(), "{:?}", docs.warnings); + assert_eq!(docs.modules.len(), bundled_base::modules().len() + 2); + let files = render(&docs.modules, Format::Html); + let index = &files["index.html"]; + for module in &docs.modules { + let path = format!("{}.html", module.name.replace('.', "/")); + assert!(index.contains(&format!("href=\"{path}\""))); + assert!(files.contains_key(&path)); + } + let search: serde_json::Value = serde_json::from_str(&files["search.json"]).unwrap(); + for entry in search.as_array().unwrap() { + let (path, anchor) = entry["url"].as_str().unwrap().split_once('#').unwrap(); + assert!(files[path].contains(&format!("id=\"{anchor}\""))); + } +} + +#[tokio::test] +async fn same_trait_method_constraint() { + assert_docs_snapshot!( + r#" + module Example exposing (Keep) + {-| A method may require the same trait at another type. -} + trait Keep 'a where + other : Keep 'b => 'b -> 'a + "# + ); +} + +#[tokio::test] +async fn overview_markdown_boundaries() { + assert_docs_snapshot!( + r#" + module Example exposing (first, second) + {-| Order and prose. + + @docs + second, + ## Keep this heading + + ````nash + ``` + @docs first + ```` + + @docs alsoCode + + @docs first + -} + {-| First value. -} + first x = x + {-| Second value. -} + second x = x + "# + ); +} + +macro_rules! assert_render_snapshot { + ($format:expr, $source:expr) => {{ + let source = indoc::indoc!($source); + let docs = documented(source).await; + let files = render(&[docs.module], $format); + insta::with_settings!({description => source, omit_expression => true}, { + let output = files.into_iter() + .filter(|(path, _)| !path.ends_with(".css") && !path.ends_with(".js")) + .map(|(path, content)| format!("--- {path}\n{content}")) + .collect::>().join("\n"); + insta::assert_snapshot!(output); + }); + }}; +} + +#[tokio::test] +async fn markdown_output() { + assert_render_snapshot!( + Format::Markdown, + r#" + module Example exposing (type box(..), identity, (%%)) + {-| # A small API + + @docs box, identity, (%%) + -} + + infix left 5 (%%) = combine + + {-| A little container. -} + type box 'a = Box 'a + + {-| Preserve a value. + + ```nash + identity 42 + ``` + -} + identity x = x + + combine x y = x + "# + ); +} + +#[tokio::test] +async fn html_output() { + assert_render_snapshot!( + Format::Html, + r#" + module Example exposing (identity) + {-| **Public API** with [a link][guide]. + + @docs identity + + [guide]: https://example.com + -} + + {-| Preserve a value. + + ```nash + identity "hello" + ``` + + + + [Unsafe link](javascript:alert%281%29) + -} + identity x = x + "# + ); +} + +#[test] +fn highlight_fragments() { + let source = indoc::indoc!( + r##" + -- A comment + {- Nested {- comment -} λ -} + run : int -> int + run value = if value < 0 then -value else value + bytes = #"00ab" + text = "