commit
28553e3d03
|
@ -2,6 +2,26 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||
dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiken"
|
||||
version = "0.0.15"
|
||||
|
@ -19,11 +39,22 @@ dependencies = [
|
|||
"uplc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiken-lang"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chumsky",
|
||||
"internment",
|
||||
"miette",
|
||||
"pretty_assertions",
|
||||
"vec1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.57"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
|
@ -62,9 +93,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
|
|||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
@ -94,17 +125,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.18"
|
||||
name = "chumsky"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
|
||||
checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4"
|
||||
dependencies = [
|
||||
"ahash 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
|
@ -112,9 +152,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.1.18"
|
||||
version = "3.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
|
||||
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
@ -125,13 +165,41 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.0"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"lazy_static",
|
||||
"proc-macro-hack",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "cryptoxide"
|
||||
version = "0.4.2"
|
||||
|
@ -139,10 +207,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "129eabb7b0b78644a3a7e7cf220714aba47463bb281f69fa7a71ca5d12564cca"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
name = "ctor"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
@ -181,9 +265,12 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -208,9 +295,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.1"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -225,6 +312,16 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "internment"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a798d7677f07d6f1e77be484ea8626ddb1566194de399f1206306820c406371"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
|
@ -239,9 +336,19 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
version = "0.2.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
|
@ -252,6 +359,29 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miette"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28d6092d7e94a90bb9ea8e6c26c99d5d112d49dda2afdb4f7ea8cf09e1a5a6d"
|
||||
dependencies = [
|
||||
"miette-derive",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miette-derive"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f2485ed7d1fe80704928e3eb86387439609bd0c6bb96db8208daa364cfd1e09"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minicbor"
|
||||
version = "0.18.0"
|
||||
|
@ -283,16 +413,31 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.1"
|
||||
name = "once_cell"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallas-addresses"
|
||||
version = "0.14.0-alpha.3"
|
||||
version = "0.14.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92140c1ffe3d3b71ad41c3879a506e34feb6ea42e5d75e02285c1483dd4a28b6"
|
||||
checksum = "1188a2434037b74129f8d209a37a1d09721b900e6e378255db1a91abc37199bc"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -304,9 +449,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-codec"
|
||||
version = "0.14.0-alpha.3"
|
||||
version = "0.14.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "749de2b1953b806a9f3e2b7d6cfee48a474c709b160eb143e34ab62a9a8eac97"
|
||||
checksum = "65c035a772aa84e858e53b7c98e6036eaa216d8a699bb9c826787722bde13d05"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"minicbor",
|
||||
|
@ -315,9 +460,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-crypto"
|
||||
version = "0.14.0-alpha.3"
|
||||
version = "0.14.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb57716e86f5c131ee8da655361dd8b9ec83a23c92c2a2ad3fb75352936fd5d"
|
||||
checksum = "2841f9225dcd6a78c6f386d4d5e76bcdbecd7b4489455b2d2485b105bf4c0499"
|
||||
dependencies = [
|
||||
"cryptoxide",
|
||||
"hex",
|
||||
|
@ -329,9 +474,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-primitives"
|
||||
version = "0.14.0-alpha.3"
|
||||
version = "0.14.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d0711ac752a723c39c02204bf70de9173a83f2de29a2356256dd3b85ce7fd8a"
|
||||
checksum = "3e51824547f7a1e1a6574ecec4bf8557f3819f435132873c0bae97acba81cbb1"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -345,9 +490,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-traverse"
|
||||
version = "0.14.0-alpha.3"
|
||||
version = "0.14.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8aa8f851594c1e23f95ff533824fa8cff2c012d99fbcdcf82d1006237411d582"
|
||||
checksum = "3291d1ae31cd803b9142fb32e1fcb0a58fc1d65b3bbe1d527d14b322db6eb019"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"pallas-addresses",
|
||||
|
@ -357,6 +502,29 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peg"
|
||||
version = "0.8.0"
|
||||
|
@ -402,6 +570,18 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"diff",
|
||||
"output_vt100",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -427,10 +607,16 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -469,9 +655,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -499,9 +685,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
@ -517,18 +703,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.26"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
|
@ -558,19 +744,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.144"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -588,6 +780,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
@ -596,9 +794,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.95"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
|
||||
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -630,30 +828,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
checksum = "0a99cb8c4b9a8ef0e7907cd3b617cc8dc04d571c4e73c8ae403d80ac160bb122"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
checksum = "3a891860d3c8d66fec8e73ddb3765f90082374dbaaa833407b904a94f1a7eb43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.1"
|
||||
|
@ -662,15 +869,21 @@ checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "uplc"
|
||||
|
@ -693,6 +906,12 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec1"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc1631c774f0f9570797191e01247cbefde789eebfbf128074cb934115a6133"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -744,3 +963,52 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["crates/cli", "crates/flat", "crates/uplc"]
|
||||
members = ["crates/*"]
|
||||
|
|
|
@ -7,6 +7,15 @@ use clap::{Parser, Subcommand};
|
|||
#[clap(version, about, long_about = None)]
|
||||
#[clap(propagate_version = true)]
|
||||
pub enum Args {
|
||||
/// Build an aiken project
|
||||
Build,
|
||||
/// Start a development server
|
||||
Dev,
|
||||
/// Create a new aiken project
|
||||
New {
|
||||
/// Project name
|
||||
name: PathBuf,
|
||||
},
|
||||
/// A subcommand for working with transactions
|
||||
#[clap(subcommand)]
|
||||
Tx(TxCommand),
|
||||
|
@ -50,39 +59,56 @@ pub enum TxCommand {
|
|||
/// Commands for working with Untyped Plutus Core
|
||||
#[derive(Subcommand)]
|
||||
pub enum UplcCommand {
|
||||
/// Evaluate an Untyped Plutus Core program
|
||||
Eval {
|
||||
script: PathBuf,
|
||||
|
||||
#[clap(short, long)]
|
||||
flat: bool,
|
||||
|
||||
/// Arguments to pass to the uplc program
|
||||
args: Vec<String>,
|
||||
},
|
||||
/// Encode textual Untyped Plutus Core to flat bytes
|
||||
Flat {
|
||||
/// Textual Untyped Plutus Core file
|
||||
input: PathBuf,
|
||||
#[clap(short, long)]
|
||||
print: bool,
|
||||
|
||||
/// Output file name
|
||||
#[clap(short, long)]
|
||||
out: Option<String>,
|
||||
#[clap(short, long)]
|
||||
cbor_hex: bool,
|
||||
},
|
||||
/// Decode flat bytes to textual Untyped Plutus Core
|
||||
Unflat {
|
||||
input: PathBuf,
|
||||
|
||||
/// Print output instead of saving to file
|
||||
#[clap(short, long)]
|
||||
print: bool,
|
||||
#[clap(short, long)]
|
||||
out: Option<String>,
|
||||
|
||||
#[clap(short, long)]
|
||||
cbor_hex: bool,
|
||||
},
|
||||
/// Format an Untyped Plutus Core program
|
||||
Fmt {
|
||||
/// Textual Untyped Plutus Core file
|
||||
input: PathBuf,
|
||||
|
||||
/// Print output instead of saving to file
|
||||
#[clap(short, long)]
|
||||
print: bool,
|
||||
},
|
||||
/// Evaluate an Untyped Plutus Core program
|
||||
Eval {
|
||||
script: PathBuf,
|
||||
/// Decode flat bytes to textual Untyped Plutus Core
|
||||
Unflat {
|
||||
/// Flat encoded Untyped Plutus Core file
|
||||
input: PathBuf,
|
||||
|
||||
/// Output file name
|
||||
#[clap(short, long)]
|
||||
flat: bool,
|
||||
/// Arguments to pass to the uplc program
|
||||
args: Vec<String>,
|
||||
out: Option<String>,
|
||||
|
||||
/// Print output instead of saving to file
|
||||
#[clap(short, long)]
|
||||
print: bool,
|
||||
|
||||
#[clap(short, long)]
|
||||
cbor_hex: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,31 @@ fn main() -> anyhow::Result<()> {
|
|||
let args = Args::default();
|
||||
|
||||
match args {
|
||||
Args::Build => {
|
||||
// 1. load and parse modules
|
||||
// * lib - contains modules, types, and functions
|
||||
// * contracts - contains validators
|
||||
// * scripts - contains native scripts dsl
|
||||
// 2. type check everything
|
||||
// 3. generate uplc and policy/address if relevant
|
||||
todo!()
|
||||
}
|
||||
|
||||
Args::Dev => {
|
||||
// launch a development server
|
||||
// this should allow people to test
|
||||
// their contracts over http
|
||||
todo!()
|
||||
}
|
||||
|
||||
Args::New { name } => {
|
||||
if !name.exists() {
|
||||
fs::create_dir_all(name.join("lib"))?;
|
||||
fs::create_dir_all(name.join("policies"))?;
|
||||
fs::create_dir_all(name.join("scripts"))?;
|
||||
}
|
||||
}
|
||||
|
||||
Args::Tx(tx_cmd) => match tx_cmd {
|
||||
TxCommand::Simulate {
|
||||
input,
|
||||
|
@ -161,6 +186,7 @@ fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
UplcCommand::Fmt { input, print } => {
|
||||
let code = std::fs::read_to_string(&input)?;
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "aiken-lang"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chumsky = "0.8.0"
|
||||
internment = "0.7.0"
|
||||
miette = "5.2.0"
|
||||
vec1 = "1.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
|
@ -0,0 +1,547 @@
|
|||
use std::{collections::HashMap, fmt, ops::Range, sync::Arc};
|
||||
|
||||
use internment::Intern;
|
||||
|
||||
use crate::{
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
tipo::{self, PatternConstructor, Type, ValueConstructor},
|
||||
};
|
||||
|
||||
pub type TypedModule = Module<tipo::Module, TypedDefinition>;
|
||||
pub type UntypedModule = Module<(), UntypedDefinition>;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ModuleKind {
|
||||
Contract,
|
||||
Lib,
|
||||
Script,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Module<Info, Definitions> {
|
||||
pub name: Vec<String>,
|
||||
pub docs: Vec<String>,
|
||||
pub type_info: Info,
|
||||
pub definitions: Vec<Definitions>,
|
||||
pub kind: ModuleKind,
|
||||
}
|
||||
|
||||
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>;
|
||||
pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
|
||||
Fn {
|
||||
arguments: Vec<Arg<T>>,
|
||||
body: Expr,
|
||||
doc: Option<String>,
|
||||
location: Span,
|
||||
name: String,
|
||||
public: bool,
|
||||
return_annotation: Option<Annotation>,
|
||||
return_type: T,
|
||||
},
|
||||
|
||||
TypeAlias {
|
||||
alias: String,
|
||||
annotation: Annotation,
|
||||
doc: Option<String>,
|
||||
location: Span,
|
||||
parameters: Vec<String>,
|
||||
public: bool,
|
||||
tipo: T,
|
||||
},
|
||||
|
||||
DataType {
|
||||
constructors: Vec<RecordConstructor<T>>,
|
||||
doc: Option<String>,
|
||||
location: Span,
|
||||
name: String,
|
||||
opaque: bool,
|
||||
parameters: Vec<String>,
|
||||
public: bool,
|
||||
typed_parameters: Vec<T>,
|
||||
},
|
||||
|
||||
Use {
|
||||
as_name: Option<String>,
|
||||
location: Span,
|
||||
module: Vec<String>,
|
||||
package: PackageName,
|
||||
unqualified: Vec<UnqualifiedImport>,
|
||||
},
|
||||
|
||||
ModuleConstant {
|
||||
doc: Option<String>,
|
||||
location: Span,
|
||||
public: bool,
|
||||
name: String,
|
||||
annotation: Option<Annotation>,
|
||||
value: Box<Constant<T, ConstantRecordTag>>,
|
||||
tipo: T,
|
||||
},
|
||||
}
|
||||
|
||||
pub type TypedConstant = Constant<Arc<Type>, String>;
|
||||
pub type UntypedConstant = Constant<(), ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Constant<T, RecordTag> {
|
||||
Int {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
String {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Pair {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
},
|
||||
|
||||
List {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
tipo: T,
|
||||
},
|
||||
|
||||
Record {
|
||||
location: Span,
|
||||
module: Option<String>,
|
||||
name: String,
|
||||
args: Vec<CallArg<Self>>,
|
||||
tag: RecordTag,
|
||||
tipo: T,
|
||||
field_map: Option<FieldMap>,
|
||||
},
|
||||
|
||||
ByteString {
|
||||
location: Span,
|
||||
// segments: Vec<BitStringSegment<Self, T>>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
module: Option<String>,
|
||||
name: String,
|
||||
constructor: Option<Box<ValueConstructor>>,
|
||||
tipo: T,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CallArg<A> {
|
||||
pub label: Option<String>,
|
||||
pub location: Span,
|
||||
pub value: A,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FieldMap {
|
||||
pub arity: usize,
|
||||
pub fields: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RecordConstructor<T> {
|
||||
pub location: Span,
|
||||
pub name: String,
|
||||
pub arguments: Vec<RecordConstructorArg<T>>,
|
||||
pub documentation: Option<String>,
|
||||
pub sugar: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RecordConstructorArg<T> {
|
||||
pub label: Option<String>,
|
||||
// ast
|
||||
pub annotation: Annotation,
|
||||
pub location: Span,
|
||||
pub tipo: T,
|
||||
pub doc: Option<String>,
|
||||
}
|
||||
|
||||
pub type UntypedArg = Arg<()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Arg<T> {
|
||||
pub arg_name: ArgName,
|
||||
pub location: Span,
|
||||
pub annotation: Option<Annotation>,
|
||||
pub tipo: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ArgName {
|
||||
Discard {
|
||||
name: String,
|
||||
location: Span,
|
||||
},
|
||||
LabeledDiscard {
|
||||
label: String,
|
||||
name: String,
|
||||
location: Span,
|
||||
},
|
||||
Named {
|
||||
name: String,
|
||||
location: Span,
|
||||
},
|
||||
NamedLabeled {
|
||||
name: String,
|
||||
label: String,
|
||||
location: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct UnqualifiedImport {
|
||||
pub location: Span,
|
||||
pub name: String,
|
||||
pub as_name: Option<String>,
|
||||
pub layer: Layer,
|
||||
}
|
||||
|
||||
// TypeAst
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Annotation {
|
||||
Constructor {
|
||||
location: Span,
|
||||
module: Option<String>,
|
||||
name: String,
|
||||
arguments: Vec<Self>,
|
||||
},
|
||||
|
||||
Fn {
|
||||
location: Span,
|
||||
arguments: Vec<Self>,
|
||||
ret: Box<Self>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
name: String,
|
||||
},
|
||||
|
||||
Tuple {
|
||||
location: Span,
|
||||
elems: Vec<Self>,
|
||||
},
|
||||
|
||||
Hole {
|
||||
location: Span,
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Layer {
|
||||
Value,
|
||||
Type,
|
||||
}
|
||||
|
||||
impl Default for Layer {
|
||||
fn default() -> Self {
|
||||
Layer::Value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum BinOp {
|
||||
// Boolean logic
|
||||
And,
|
||||
Or,
|
||||
|
||||
// Equality
|
||||
Eq,
|
||||
NotEq,
|
||||
|
||||
// Order comparison
|
||||
LtInt,
|
||||
LtEqInt,
|
||||
GtEqInt,
|
||||
GtInt,
|
||||
|
||||
// Maths
|
||||
AddInt,
|
||||
SubInt,
|
||||
MultInt,
|
||||
DivInt,
|
||||
ModInt,
|
||||
}
|
||||
|
||||
pub type UntypedPattern = Pattern<(), ()>;
|
||||
pub type TypedPattern = Pattern<PatternConstructor, Arc<Type>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Pattern<Constructor, Type> {
|
||||
Int {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Float {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
String {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
/// The creation of a variable.
|
||||
/// e.g. `assert [this_is_a_var, .._] = x`
|
||||
Var {
|
||||
location: Span,
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// A reference to a variable in a bit string. This is always a variable
|
||||
/// being used rather than a new variable being assigned.
|
||||
VarUsage {
|
||||
location: Span,
|
||||
name: String,
|
||||
tipo: Type,
|
||||
},
|
||||
|
||||
/// A name given to a sub-pattern using the `as` keyword.
|
||||
/// e.g. `assert #(1, [_, _] as the_list) = x`
|
||||
Assign {
|
||||
name: String,
|
||||
location: Span,
|
||||
pattern: Box<Self>,
|
||||
},
|
||||
|
||||
/// A pattern that binds to any value but does not assign a variable.
|
||||
/// Always starts with an underscore.
|
||||
Discard {
|
||||
name: String,
|
||||
location: Span,
|
||||
},
|
||||
|
||||
List {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
tail: Option<Box<Self>>,
|
||||
},
|
||||
|
||||
/// The constructor for a custom type. Starts with an uppercase letter.
|
||||
Constructor {
|
||||
location: Span,
|
||||
name: String,
|
||||
arguments: Vec<CallArg<Self>>,
|
||||
module: Option<String>,
|
||||
constructor: Constructor,
|
||||
with_spread: bool,
|
||||
tipo: Type,
|
||||
},
|
||||
|
||||
Tuple {
|
||||
location: Span,
|
||||
elems: Vec<Self>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AssignmentKind {
|
||||
Let,
|
||||
Assert,
|
||||
}
|
||||
|
||||
pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor, Type>>;
|
||||
|
||||
pub type UntypedMultiPattern = MultiPattern<(), ()>;
|
||||
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
|
||||
|
||||
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>, String>;
|
||||
|
||||
pub type UntypedClause = Clause<UntypedExpr, (), (), ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Clause<Expr, PatternConstructor, Type, RecordTag> {
|
||||
pub location: Span,
|
||||
pub pattern: MultiPattern<PatternConstructor, Type>,
|
||||
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
|
||||
pub guard: Option<ClauseGuard<Type, RecordTag>>,
|
||||
pub then: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ClauseGuard<Type, RecordTag> {
|
||||
Equals {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
NotEquals {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
GtInt {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
GtEqInt {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
LtInt {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
LtEqInt {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
Or {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
And {
|
||||
location: Span,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
tipo: Type,
|
||||
name: String,
|
||||
},
|
||||
|
||||
TupleIndex {
|
||||
location: Span,
|
||||
index: u64,
|
||||
tipo: Type,
|
||||
tuple: Box<Self>,
|
||||
},
|
||||
|
||||
Constant(Constant<Type, RecordTag>),
|
||||
}
|
||||
|
||||
pub struct TypedRecordUpdateArg {
|
||||
pub label: String,
|
||||
pub location: Span,
|
||||
pub value: TypedExpr,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct UntypedRecordUpdateArg {
|
||||
pub label: String,
|
||||
// pub location: SrcSpan,
|
||||
pub value: UntypedExpr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RecordUpdateSpread {
|
||||
pub base: Box<UntypedExpr>,
|
||||
pub location: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TodoKind {
|
||||
Keyword,
|
||||
EmptyFunction,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct SrcId(Intern<Vec<String>>);
|
||||
|
||||
impl SrcId {
|
||||
#[cfg(test)]
|
||||
pub fn empty() -> Self {
|
||||
SrcId(Intern::new(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Span {
|
||||
pub src: SrcId,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
impl Span {
|
||||
#[cfg(test)]
|
||||
pub fn empty() -> Self {
|
||||
use chumsky::Span;
|
||||
|
||||
Self::new(SrcId::empty(), 0..0)
|
||||
}
|
||||
|
||||
pub fn src(&self) -> SrcId {
|
||||
self.src
|
||||
}
|
||||
|
||||
pub fn range(&self) -> Range<usize> {
|
||||
use chumsky::Span;
|
||||
|
||||
self.start()..self.end()
|
||||
}
|
||||
|
||||
pub fn union(self, other: Self) -> Self {
|
||||
use chumsky::Span;
|
||||
|
||||
assert_eq!(
|
||||
self.src, other.src,
|
||||
"attempted to union spans with different sources"
|
||||
);
|
||||
|
||||
Self {
|
||||
start: self.start().min(other.start()),
|
||||
end: self.end().max(other.end()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Span {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}:{:?}", self.src, self.range())
|
||||
}
|
||||
}
|
||||
|
||||
impl chumsky::Span for Span {
|
||||
type Context = SrcId;
|
||||
|
||||
type Offset = usize;
|
||||
|
||||
fn new(context: Self::Context, range: Range<Self::Offset>) -> Self {
|
||||
assert!(range.start <= range.end);
|
||||
|
||||
Self {
|
||||
src: context,
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
}
|
||||
}
|
||||
|
||||
fn context(&self) -> Self::Context {
|
||||
self.src
|
||||
}
|
||||
|
||||
fn start(&self) -> Self::Offset {
|
||||
self.start
|
||||
}
|
||||
|
||||
fn end(&self) -> Self::Offset {
|
||||
self.end
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
pub enum Origin {
|
||||
Src,
|
||||
Test,
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
use std::{collections::HashSet, fmt};
|
||||
|
||||
use crate::{ast::Span, token::Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError {
|
||||
kind: ErrorKind,
|
||||
span: Span,
|
||||
#[allow(dead_code)]
|
||||
while_parsing: Option<(Span, &'static str)>,
|
||||
expected: HashSet<Pattern>,
|
||||
label: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
pub fn merge(mut self, other: Self) -> Self {
|
||||
// TODO: Use HashSet
|
||||
for expected in other.expected.into_iter() {
|
||||
self.expected.insert(expected);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ParseError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.kind == other.kind && self.span == other.span && self.label == other.label
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Pattern>> chumsky::Error<T> for ParseError {
|
||||
type Span = Span;
|
||||
|
||||
type Label = &'static str;
|
||||
|
||||
fn expected_input_found<Iter: IntoIterator<Item = Option<T>>>(
|
||||
span: Self::Span,
|
||||
expected: Iter,
|
||||
found: Option<T>,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: found
|
||||
.map(Into::into)
|
||||
.map(ErrorKind::Unexpected)
|
||||
.unwrap_or(ErrorKind::UnexpectedEnd),
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: expected
|
||||
.into_iter()
|
||||
.map(|x| x.map(Into::into).unwrap_or(Pattern::End))
|
||||
.collect(),
|
||||
label: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_label(mut self, label: Self::Label) -> Self {
|
||||
self.label.get_or_insert(label);
|
||||
self
|
||||
}
|
||||
|
||||
fn merge(self, other: Self) -> Self {
|
||||
ParseError::merge(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ErrorKind {
|
||||
UnexpectedEnd,
|
||||
Unexpected(Pattern),
|
||||
Unclosed {
|
||||
start: Pattern,
|
||||
before_span: Span,
|
||||
before: Option<Pattern>,
|
||||
},
|
||||
NoEndBranch,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Pattern {
|
||||
Char(char),
|
||||
Token(Token),
|
||||
Literal,
|
||||
TypeIdent,
|
||||
TermIdent,
|
||||
End,
|
||||
}
|
||||
|
||||
impl From<char> for Pattern {
|
||||
fn from(c: char) -> Self {
|
||||
Self::Char(c)
|
||||
}
|
||||
}
|
||||
impl From<Token> for Pattern {
|
||||
fn from(tok: Token) -> Self {
|
||||
Self::Token(tok)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Pattern {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Pattern::Token(token) => write!(f, "{}", token),
|
||||
Pattern::Char(c) => write!(f, "{:?}", c),
|
||||
Pattern::Literal => write!(f, "literal"),
|
||||
Pattern::TypeIdent => write!(f, "type name"),
|
||||
Pattern::TermIdent => write!(f, "identifier"),
|
||||
Pattern::End => write!(f, "end of input"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use vec1::Vec1;
|
||||
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, Pattern, RecordUpdateSpread, Span,
|
||||
TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg,
|
||||
},
|
||||
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
|
||||
};
|
||||
|
||||
pub enum TypedExpr {
|
||||
Int {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Float {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
value: String,
|
||||
},
|
||||
|
||||
String {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Sequence {
|
||||
location: Span,
|
||||
expressions: Vec<Self>,
|
||||
},
|
||||
|
||||
/// A chain of pipe expressions.
|
||||
/// By this point the type checker has expanded it into a series of
|
||||
/// assignments and function calls, but we still have a Pipeline AST node as
|
||||
/// even though it is identical to `Sequence` we want to use different
|
||||
/// locations when showing it in error messages, etc.
|
||||
Pipeline {
|
||||
location: Span,
|
||||
expressions: Vec<Self>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
constructor: ValueConstructor,
|
||||
name: String,
|
||||
},
|
||||
|
||||
Fn {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
is_capture: bool,
|
||||
args: Vec<Arg<Arc<Type>>>,
|
||||
body: Box<Self>,
|
||||
return_annotation: Option<Annotation>,
|
||||
},
|
||||
|
||||
List {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
elements: Vec<Self>,
|
||||
tail: Option<Box<Self>>,
|
||||
},
|
||||
|
||||
Call {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
fun: Box<Self>,
|
||||
args: Vec<CallArg<Self>>,
|
||||
},
|
||||
|
||||
BinOp {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
name: BinOp,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
Assignment {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
value: Box<Self>,
|
||||
pattern: Pattern<PatternConstructor, Arc<Type>>,
|
||||
kind: AssignmentKind,
|
||||
},
|
||||
|
||||
Try {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
value: Box<Self>,
|
||||
then: Box<Self>,
|
||||
pattern: Pattern<PatternConstructor, Arc<Type>>,
|
||||
},
|
||||
|
||||
When {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>,
|
||||
},
|
||||
|
||||
RecordAccess {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
label: String,
|
||||
index: u64,
|
||||
record: Box<Self>,
|
||||
},
|
||||
|
||||
ModuleSelect {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
label: String,
|
||||
module_name: String,
|
||||
module_alias: String,
|
||||
constructor: ModuleValueConstructor,
|
||||
},
|
||||
|
||||
Tuple {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
elems: Vec<Self>,
|
||||
},
|
||||
|
||||
TupleIndex {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
index: u64,
|
||||
tuple: Box<Self>,
|
||||
},
|
||||
|
||||
Todo {
|
||||
location: Span,
|
||||
label: Option<String>,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
RecordUpdate {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
spread: Box<Self>,
|
||||
args: Vec<TypedRecordUpdateArg>,
|
||||
},
|
||||
|
||||
Negate {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum UntypedExpr {
|
||||
Int {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Float {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
String {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
|
||||
Sequence {
|
||||
location: Span,
|
||||
expressions: Vec<Self>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
name: String,
|
||||
},
|
||||
|
||||
Fn {
|
||||
location: Span,
|
||||
is_capture: bool,
|
||||
arguments: Vec<Arg<()>>,
|
||||
body: Box<Self>,
|
||||
return_annotation: Option<Annotation>,
|
||||
},
|
||||
|
||||
List {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
tail: Option<Box<Self>>,
|
||||
},
|
||||
|
||||
Call {
|
||||
location: Span,
|
||||
fun: Box<Self>,
|
||||
arguments: Vec<CallArg<Self>>,
|
||||
},
|
||||
|
||||
BinOp {
|
||||
location: Span,
|
||||
name: BinOp,
|
||||
left: Box<Self>,
|
||||
right: Box<Self>,
|
||||
},
|
||||
|
||||
PipeLine {
|
||||
expressions: Vec1<Self>,
|
||||
},
|
||||
|
||||
Assignment {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
pattern: Pattern<(), ()>,
|
||||
kind: AssignmentKind,
|
||||
annotation: Option<Annotation>,
|
||||
},
|
||||
|
||||
Try {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
pattern: Pattern<(), ()>,
|
||||
then: Box<Self>,
|
||||
annotation: Option<Annotation>,
|
||||
},
|
||||
|
||||
Case {
|
||||
location: Span,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, (), (), ()>>,
|
||||
},
|
||||
|
||||
FieldAccess {
|
||||
location: Span,
|
||||
label: String,
|
||||
container: Box<Self>,
|
||||
},
|
||||
|
||||
Tuple {
|
||||
location: Span,
|
||||
elems: Vec<Self>,
|
||||
},
|
||||
|
||||
TupleIndex {
|
||||
location: Span,
|
||||
index: u64,
|
||||
tuple: Box<Self>,
|
||||
},
|
||||
|
||||
Todo {
|
||||
kind: TodoKind,
|
||||
location: Span,
|
||||
label: Option<String>,
|
||||
},
|
||||
|
||||
RecordUpdate {
|
||||
location: Span,
|
||||
constructor: Box<Self>,
|
||||
spread: RecordUpdateSpread,
|
||||
arguments: Vec<UntypedRecordUpdateArg>,
|
||||
},
|
||||
|
||||
Negate {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
},
|
||||
}
|
||||
|
||||
impl UntypedExpr {
|
||||
pub fn append_in_sequence(self, next: Self) -> Self {
|
||||
let location = Span {
|
||||
start: self.location().start,
|
||||
end: next.location().end,
|
||||
..self.location()
|
||||
};
|
||||
|
||||
match self {
|
||||
Self::Sequence {
|
||||
mut expressions, ..
|
||||
} => {
|
||||
expressions.push(next);
|
||||
Self::Sequence {
|
||||
location,
|
||||
expressions,
|
||||
}
|
||||
}
|
||||
_ => Self::Sequence {
|
||||
location,
|
||||
expressions: vec![self, next],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn location(&self) -> Span {
|
||||
match self {
|
||||
Self::Try { then, .. } => then.location(),
|
||||
Self::PipeLine { expressions, .. } => expressions.last().location(),
|
||||
Self::Fn { location, .. }
|
||||
| Self::Var { location, .. }
|
||||
| Self::Int { location, .. }
|
||||
| Self::Todo { location, .. }
|
||||
| Self::Case { location, .. }
|
||||
| Self::Call { location, .. }
|
||||
| Self::List { location, .. }
|
||||
| Self::Float { location, .. }
|
||||
| Self::BinOp { location, .. }
|
||||
| Self::Tuple { location, .. }
|
||||
| Self::String { location, .. }
|
||||
| Self::Assignment { location, .. }
|
||||
| Self::TupleIndex { location, .. }
|
||||
| Self::FieldAccess { location, .. }
|
||||
| Self::RecordUpdate { location, .. }
|
||||
| Self::Negate { location, .. } => *location,
|
||||
Self::Sequence {
|
||||
location,
|
||||
expressions,
|
||||
..
|
||||
} => expressions.last().map(Self::location).unwrap_or(*location),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{ast::Span, error::ParseError, token::Token};
|
||||
|
||||
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
||||
let int = text::int(10).map(|value| Token::Int { value });
|
||||
|
||||
let op = choice((
|
||||
just("==").to(Token::EqualEqual),
|
||||
just('=').to(Token::Equal),
|
||||
just("..").to(Token::Dot),
|
||||
just('.').to(Token::Dot),
|
||||
just("!=").to(Token::NotEqual),
|
||||
just('!').to(Token::Bang),
|
||||
just("<=").to(Token::LessEqual),
|
||||
just('<').to(Token::Less),
|
||||
just(">=").to(Token::GreaterEqual),
|
||||
just('>').to(Token::Greater),
|
||||
just('+').to(Token::Plus),
|
||||
just("->").to(Token::RArrow),
|
||||
just('-').to(Token::Minus),
|
||||
just('*').to(Token::Star),
|
||||
just('/').to(Token::Slash),
|
||||
just('%').to(Token::Percent),
|
||||
just("|>").to(Token::Pipe),
|
||||
just(',').to(Token::Comma),
|
||||
just(':').to(Token::Colon),
|
||||
));
|
||||
|
||||
let grouping = choice((
|
||||
just('(').to(Token::LeftParen),
|
||||
just(')').to(Token::RightParen),
|
||||
just('[').to(Token::LeftSquare),
|
||||
just(']').to(Token::RightSquare),
|
||||
just('{').to(Token::LeftBrace),
|
||||
just('}').to(Token::RightBrace),
|
||||
));
|
||||
|
||||
let escape = just('\\').ignore_then(
|
||||
just('\\')
|
||||
.or(just('/'))
|
||||
.or(just('"'))
|
||||
.or(just('b').to('\x08'))
|
||||
.or(just('f').to('\x0C'))
|
||||
.or(just('n').to('\n'))
|
||||
.or(just('r').to('\r'))
|
||||
.or(just('t').to('\t')),
|
||||
);
|
||||
|
||||
let string = just('"')
|
||||
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
|
||||
.then_ignore(just('"'))
|
||||
.collect::<String>()
|
||||
.map(|value| Token::String { value })
|
||||
.labelled("string");
|
||||
|
||||
let keyword = text::ident().map(|s: String| match s.as_str() {
|
||||
"as" => Token::As,
|
||||
"assert" => Token::Assert,
|
||||
"const" => Token::Const,
|
||||
"fn" => Token::Fn,
|
||||
"if" => Token::If,
|
||||
"is" => Token::Is,
|
||||
"let" => Token::Let,
|
||||
"opaque" => Token::Opaque,
|
||||
"pub" => Token::Pub,
|
||||
"use" => Token::Use,
|
||||
"todo" => Token::Todo,
|
||||
"try" => Token::Try,
|
||||
"type" => Token::Type,
|
||||
"when" => Token::When,
|
||||
_ => {
|
||||
if s.chars().next().map_or(false, |c| c.is_uppercase()) {
|
||||
Token::UpName {
|
||||
// TODO: do not allow _ in upname
|
||||
name: s,
|
||||
}
|
||||
} else if s.starts_with('_') {
|
||||
Token::DiscardName {
|
||||
// TODO: do not allow uppercase letters in discard name
|
||||
name: s,
|
||||
}
|
||||
} else {
|
||||
Token::Name {
|
||||
// TODO: do not allow uppercase letters in name
|
||||
name: s,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let token = choice((keyword, int, op, grouping, string))
|
||||
.or(any().map(Token::Error).validate(|t, span, emit| {
|
||||
emit(ParseError::expected_input_found(
|
||||
span,
|
||||
None,
|
||||
Some(t.clone()),
|
||||
));
|
||||
t
|
||||
}))
|
||||
.map_with_span(move |token, span| (token, span))
|
||||
.padded()
|
||||
.recover_with(skip_then_retry_until([]));
|
||||
|
||||
let comments = just("//")
|
||||
.then_ignore(
|
||||
just('(')
|
||||
.ignore_then(take_until(just(")#")).ignored())
|
||||
.or(none_of('\n').ignored().repeated().ignored()),
|
||||
)
|
||||
.padded()
|
||||
.ignored()
|
||||
.repeated();
|
||||
|
||||
token
|
||||
.padded_by(comments)
|
||||
.repeated()
|
||||
.padded()
|
||||
.then_ignore(end())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast::{Span, SrcId},
|
||||
lexer,
|
||||
token::Token,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn simple() {
|
||||
let code = "pub type |> >=\n{ Thing _na_thing name";
|
||||
let len = code.chars().count();
|
||||
|
||||
let span = |i| Span::new(SrcId::empty(), i..i + 1);
|
||||
|
||||
assert_eq!(
|
||||
lexer::lexer()
|
||||
.parse(chumsky::Stream::from_iter(
|
||||
span(len),
|
||||
code.chars().enumerate().map(|(i, c)| (c, span(i))),
|
||||
))
|
||||
.map(|tokens| tokens.into_iter().map(|(tok, _)| tok).collect::<Vec<_>>()),
|
||||
Ok(vec![
|
||||
Token::Pub,
|
||||
Token::Type,
|
||||
Token::Pipe,
|
||||
Token::GreaterEqual,
|
||||
Token::LeftBrace,
|
||||
Token::UpName {
|
||||
name: "Thing".to_string()
|
||||
},
|
||||
Token::DiscardName {
|
||||
name: "_na_thing".to_string()
|
||||
},
|
||||
Token::Name {
|
||||
name: "name".to_string()
|
||||
}
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
pub mod ast;
|
||||
pub mod build;
|
||||
pub mod error;
|
||||
pub mod expr;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod tipo;
|
||||
pub mod token;
|
|
@ -0,0 +1,811 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast::{self, BinOp, TodoKind},
|
||||
error::ParseError,
|
||||
expr,
|
||||
token::Token,
|
||||
};
|
||||
|
||||
pub fn module_parser(
|
||||
kind: ast::ModuleKind,
|
||||
) -> impl Parser<Token, ast::UntypedModule, Error = ParseError> {
|
||||
choice((
|
||||
import_parser(),
|
||||
data_parser(),
|
||||
type_alias_parser(),
|
||||
fn_parser(),
|
||||
))
|
||||
.repeated()
|
||||
.then_ignore(end())
|
||||
.map(move |definitions| ast::UntypedModule {
|
||||
kind,
|
||||
definitions,
|
||||
docs: vec![],
|
||||
name: vec![],
|
||||
type_info: (),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn import_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
let unqualified_import = choice((
|
||||
select! {Token::Name { name } => name}.then(
|
||||
just(Token::As)
|
||||
.ignore_then(select! {Token::Name { name } => name})
|
||||
.or_not(),
|
||||
),
|
||||
select! {Token::UpName { name } => name}.then(
|
||||
just(Token::As)
|
||||
.ignore_then(select! {Token::UpName { name } => name})
|
||||
.or_not(),
|
||||
),
|
||||
))
|
||||
.map_with_span(|(name, as_name), span| ast::UnqualifiedImport {
|
||||
name,
|
||||
location: span,
|
||||
as_name,
|
||||
layer: Default::default(),
|
||||
});
|
||||
|
||||
let unqualified_imports = just(Token::Dot)
|
||||
.ignore_then(
|
||||
unqualified_import
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.or_not();
|
||||
|
||||
let as_name = just(Token::As)
|
||||
.ignore_then(select! {Token::Name { name } => name})
|
||||
.or_not();
|
||||
|
||||
let module_path = select! {Token::Name { name } => name}
|
||||
.separated_by(just(Token::Slash))
|
||||
.then(unqualified_imports)
|
||||
.then(as_name);
|
||||
|
||||
just(Token::Use).ignore_then(module_path).map_with_span(
|
||||
|((module, unqualified), as_name), span| ast::UntypedDefinition::Use {
|
||||
module,
|
||||
as_name,
|
||||
unqualified: unqualified.unwrap_or_default(),
|
||||
package: (),
|
||||
location: span,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn data_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
let unlabeled_constructor_type_args = type_parser()
|
||||
.map_with_span(|annotation, span| ast::RecordConstructorArg {
|
||||
label: None,
|
||||
annotation,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
location: span,
|
||||
})
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen));
|
||||
|
||||
let constructors = select! {Token::UpName { name } => name}
|
||||
.then(
|
||||
choice((
|
||||
labeled_constructor_type_args(),
|
||||
unlabeled_constructor_type_args,
|
||||
))
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(name, arguments), span| ast::RecordConstructor {
|
||||
location: span,
|
||||
arguments: arguments.unwrap_or_default(),
|
||||
name,
|
||||
documentation: None,
|
||||
sugar: false,
|
||||
})
|
||||
.repeated()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
|
||||
|
||||
let record_sugar = labeled_constructor_type_args().map_with_span(|arguments, span| {
|
||||
vec![ast::RecordConstructor {
|
||||
location: span,
|
||||
arguments,
|
||||
documentation: None,
|
||||
name: String::from("_replace"),
|
||||
sugar: true,
|
||||
}]
|
||||
});
|
||||
|
||||
pub_parser()
|
||||
.then(just(Token::Opaque).ignored().or_not())
|
||||
.or_not()
|
||||
.then(type_name_with_args())
|
||||
.then(choice((constructors, record_sugar)))
|
||||
.map_with_span(|((pub_opaque, (name, parameters)), constructors), span| {
|
||||
ast::UntypedDefinition::DataType {
|
||||
location: span,
|
||||
constructors: constructors
|
||||
.into_iter()
|
||||
.map(|mut constructor| {
|
||||
if constructor.sugar {
|
||||
constructor.name = name.clone();
|
||||
}
|
||||
|
||||
constructor
|
||||
})
|
||||
.collect(),
|
||||
doc: None,
|
||||
name,
|
||||
opaque: pub_opaque
|
||||
.map(|(_, opt_opaque)| opt_opaque.is_some())
|
||||
.unwrap_or(false),
|
||||
parameters: parameters.unwrap_or_default(),
|
||||
public: pub_opaque.is_some(),
|
||||
typed_parameters: vec![],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn type_alias_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
pub_parser()
|
||||
.or_not()
|
||||
.then(type_name_with_args())
|
||||
.then_ignore(just(Token::Equal))
|
||||
.then(type_parser())
|
||||
.map_with_span(|((opt_pub, (alias, parameters)), annotation), span| {
|
||||
ast::UntypedDefinition::TypeAlias {
|
||||
alias,
|
||||
annotation,
|
||||
doc: None,
|
||||
location: span,
|
||||
parameters: parameters.unwrap_or_default(),
|
||||
public: opt_pub.is_some(),
|
||||
tipo: (),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fn_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
pub_parser()
|
||||
.or_not()
|
||||
.then_ignore(just(Token::Fn))
|
||||
.then(select! {Token::Name {name} => name})
|
||||
.then(
|
||||
fn_param_parser()
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
)
|
||||
.then(just(Token::RArrow).ignore_then(type_parser()).or_not())
|
||||
.then_ignore(just(Token::LeftBrace))
|
||||
.then(expr_seq_parser())
|
||||
.then_ignore(just(Token::RightBrace))
|
||||
.map_with_span(
|
||||
|((((opt_pub, name), arguments), return_annotation), body), span| {
|
||||
ast::UntypedDefinition::Fn {
|
||||
arguments,
|
||||
body,
|
||||
doc: None,
|
||||
location: span,
|
||||
name,
|
||||
public: opt_pub.is_some(),
|
||||
return_annotation,
|
||||
return_type: (),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||
choice((
|
||||
select! {Token::Name {name} => name}
|
||||
.then(select! {Token::DiscardName {name} => name})
|
||||
.map_with_span(|(label, name), span| ast::ArgName::LabeledDiscard {
|
||||
label,
|
||||
name,
|
||||
location: span,
|
||||
}),
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgName::Discard {
|
||||
name,
|
||||
location: span,
|
||||
}
|
||||
}),
|
||||
select! {Token::Name {name} => name}
|
||||
.then(select! {Token::Name {name} => name})
|
||||
.map_with_span(|(label, name), span| ast::ArgName::NamedLabeled {
|
||||
label,
|
||||
name,
|
||||
location: span,
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
||||
name,
|
||||
location: span,
|
||||
}),
|
||||
))
|
||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||
location: span,
|
||||
annotation,
|
||||
tipo: (),
|
||||
arg_name,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
choice((
|
||||
just(Token::Try)
|
||||
.ignore_then(pattern_parser())
|
||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
||||
.then_ignore(just(Token::Equal))
|
||||
.then(expr_parser())
|
||||
.then(r.clone())
|
||||
.map_with_span(|(((pattern, annotation), value), then_), span| {
|
||||
expr::UntypedExpr::Try {
|
||||
location: span,
|
||||
value: Box::new(value),
|
||||
pattern,
|
||||
then: Box::new(then_),
|
||||
annotation,
|
||||
}
|
||||
}),
|
||||
expr_parser()
|
||||
.then(r.repeated())
|
||||
.map_with_span(|(expr, exprs), _span| {
|
||||
exprs
|
||||
.into_iter()
|
||||
.fold(expr, |acc, elem| acc.append_in_sequence(elem))
|
||||
}),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
|
||||
recursive(|_r| {
|
||||
let op = choice((
|
||||
just(Token::Star).to(BinOp::MultInt),
|
||||
just(Token::Slash).to(BinOp::DivInt),
|
||||
just(Token::Percent).to(BinOp::ModInt),
|
||||
));
|
||||
|
||||
let product = expr_unit_parser()
|
||||
.then(op.then(expr_unit_parser()).repeated())
|
||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
||||
location: a.location().union(b.location()),
|
||||
name: op,
|
||||
left: Box::new(a),
|
||||
right: Box::new(b),
|
||||
})
|
||||
.boxed();
|
||||
|
||||
let op = choice((
|
||||
just(Token::Plus).to(BinOp::AddInt),
|
||||
just(Token::Minus).to(BinOp::SubInt),
|
||||
));
|
||||
|
||||
product
|
||||
.clone()
|
||||
.then(op.then(product).repeated())
|
||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
||||
location: a.location().union(b.location()),
|
||||
name: op,
|
||||
left: Box::new(a),
|
||||
right: Box::new(b),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr_unit_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
|
||||
choice((
|
||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||
expr::UntypedExpr::String {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
select! { Token::Int {value} => value}.map_with_span(|value, span| {
|
||||
expr::UntypedExpr::Int {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
select! {
|
||||
Token::Name { name } => name,
|
||||
Token::UpName { name } => name,
|
||||
}
|
||||
.map_with_span(|name, span| expr::UntypedExpr::Var {
|
||||
location: span,
|
||||
name,
|
||||
}),
|
||||
just(Token::Todo)
|
||||
.ignore_then(
|
||||
select! {Token::String {value} => value}
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|label, span| expr::UntypedExpr::Todo {
|
||||
kind: TodoKind::Keyword,
|
||||
location: span,
|
||||
label,
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn type_parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
choice((
|
||||
select! {Token::DiscardName { name } => name}.map_with_span(|name, span| {
|
||||
ast::Annotation::Hole {
|
||||
location: span,
|
||||
name,
|
||||
}
|
||||
}),
|
||||
just(Token::Fn)
|
||||
.ignore_then(
|
||||
r.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
)
|
||||
.then_ignore(just(Token::RArrow))
|
||||
.then(r.clone())
|
||||
.map_with_span(|(arguments, ret), span| ast::Annotation::Fn {
|
||||
location: span,
|
||||
arguments,
|
||||
ret: Box::new(ret),
|
||||
}),
|
||||
select! {Token::UpName { name } => name}
|
||||
.then(
|
||||
r.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(name, arguments), span| ast::Annotation::Constructor {
|
||||
location: span,
|
||||
module: None,
|
||||
name,
|
||||
arguments: arguments.unwrap_or_default(),
|
||||
}),
|
||||
select! {Token::Name { name } => name}
|
||||
.then(
|
||||
just(Token::Dot)
|
||||
.ignore_then(select! {Token::UpName {name} => name})
|
||||
.then(
|
||||
r.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.or_not(),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(mod_name, opt_dot), span| {
|
||||
if let Some((name, arguments)) = opt_dot {
|
||||
ast::Annotation::Constructor {
|
||||
location: span,
|
||||
module: Some(mod_name),
|
||||
name,
|
||||
arguments: arguments.unwrap_or_default(),
|
||||
}
|
||||
} else {
|
||||
ast::Annotation::Var {
|
||||
location: span,
|
||||
name: mod_name,
|
||||
}
|
||||
}
|
||||
}),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn labeled_constructor_type_args(
|
||||
) -> impl Parser<Token, Vec<ast::RecordConstructorArg<()>>, Error = ParseError> {
|
||||
select! {Token::Name {name} => name}
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(type_parser())
|
||||
.map_with_span(|(name, annotation), span| ast::RecordConstructorArg {
|
||||
label: Some(name),
|
||||
annotation,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
location: span,
|
||||
})
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
||||
}
|
||||
|
||||
pub fn type_name_with_args() -> impl Parser<Token, (String, Option<Vec<String>>), Error = ParseError>
|
||||
{
|
||||
just(Token::Type).ignore_then(
|
||||
select! {Token::UpName { name } => name}.then(
|
||||
select! {Token::Name { name } => name}
|
||||
.separated_by(just(Token::Comma))
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.or_not(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pub_parser() -> impl Parser<Token, (), Error = ParseError> {
|
||||
just(Token::Pub).ignored()
|
||||
}
|
||||
|
||||
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
let constructor_pattern_arg_parser = choice((
|
||||
select! {Token::Name {name} => name}
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(r.clone())
|
||||
.map_with_span(|(name, pattern), span| ast::CallArg {
|
||||
location: span,
|
||||
label: Some(name),
|
||||
value: pattern,
|
||||
}),
|
||||
r.map_with_span(|pattern, span| ast::CallArg {
|
||||
location: span,
|
||||
value: pattern,
|
||||
label: None,
|
||||
}),
|
||||
));
|
||||
|
||||
let constructor_pattern_args_parser = constructor_pattern_arg_parser
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.then(
|
||||
just(Token::DotDot)
|
||||
.then_ignore(just(Token::Comma).or_not())
|
||||
.ignored()
|
||||
.or_not(),
|
||||
)
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.or_not()
|
||||
.map(|opt_args| {
|
||||
opt_args
|
||||
.map(|(a, b)| (a, b.is_some()))
|
||||
.unwrap_or_else(|| (vec![], false))
|
||||
});
|
||||
|
||||
let constructor_pattern_parser =
|
||||
select! {Token::UpName { name } => name}.then(constructor_pattern_args_parser);
|
||||
|
||||
choice((
|
||||
select! { Token::Name {name} => name }
|
||||
.then(
|
||||
just(Token::Dot)
|
||||
.ignore_then(constructor_pattern_parser.clone())
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(name, opt_pattern), span| {
|
||||
if let Some((c_name, (arguments, with_spread))) = opt_pattern {
|
||||
ast::UntypedPattern::Constructor {
|
||||
location: span,
|
||||
name: c_name,
|
||||
arguments,
|
||||
module: Some(name),
|
||||
constructor: (),
|
||||
with_spread,
|
||||
tipo: (),
|
||||
}
|
||||
} else {
|
||||
ast::UntypedPattern::Var {
|
||||
location: span,
|
||||
name,
|
||||
}
|
||||
}
|
||||
}),
|
||||
constructor_pattern_parser.map_with_span(|(name, (arguments, with_spread)), span| {
|
||||
ast::UntypedPattern::Constructor {
|
||||
location: span,
|
||||
name,
|
||||
arguments,
|
||||
module: None,
|
||||
constructor: (),
|
||||
with_spread,
|
||||
tipo: (),
|
||||
}
|
||||
}),
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::UntypedPattern::Discard {
|
||||
name,
|
||||
location: span,
|
||||
}
|
||||
}),
|
||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||
ast::UntypedPattern::String {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
select! {Token::Int {value} => value}.map_with_span(|value, span| {
|
||||
ast::UntypedPattern::Int {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
))
|
||||
.then(
|
||||
just(Token::As)
|
||||
.ignore_then(select! { Token::Name {name} => name})
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(pattern, opt_as), span| {
|
||||
if let Some(name) = opt_as {
|
||||
ast::UntypedPattern::Assign {
|
||||
name,
|
||||
location: span,
|
||||
pattern: Box::new(pattern),
|
||||
}
|
||||
} else {
|
||||
pattern
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chumsky::prelude::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::{
|
||||
ast::{self, Span, SrcId},
|
||||
expr, lexer,
|
||||
parser::module_parser,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn simple() {
|
||||
let code = r#"
|
||||
use std/list
|
||||
use std/address.{Address as A, thing as w}
|
||||
use std/tx as t
|
||||
|
||||
type Option(a) {
|
||||
Some(a, Int)
|
||||
None
|
||||
Wow { name: Int, age: Int }
|
||||
}
|
||||
|
||||
pub opaque type User {
|
||||
name: _w
|
||||
}
|
||||
|
||||
type Thing = Option(Int)
|
||||
|
||||
pub type Me = Option(String)
|
||||
|
||||
pub fn add_one(a) {
|
||||
a + 1
|
||||
}
|
||||
"#;
|
||||
let len = code.chars().count();
|
||||
|
||||
let span = |i| Span::new(SrcId::empty(), i..i + 1);
|
||||
|
||||
let tokens = lexer::lexer()
|
||||
.parse(chumsky::Stream::from_iter(
|
||||
span(len),
|
||||
code.chars().enumerate().map(|(i, c)| (c, span(i))),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let res = module_parser(ast::ModuleKind::Script)
|
||||
.parse(chumsky::Stream::from_iter(span(len), tokens.into_iter()))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
res,
|
||||
ast::UntypedModule {
|
||||
docs: vec![],
|
||||
kind: ast::ModuleKind::Script,
|
||||
name: vec![],
|
||||
type_info: (),
|
||||
definitions: vec![
|
||||
ast::UntypedDefinition::Use {
|
||||
location: Span::new(SrcId::empty(), 13..25),
|
||||
module: vec!["std".to_string(), "list".to_string()],
|
||||
as_name: None,
|
||||
unqualified: vec![],
|
||||
package: (),
|
||||
},
|
||||
ast::UntypedDefinition::Use {
|
||||
location: Span::new(SrcId::empty(), 38..80),
|
||||
module: vec!["std".to_string(), "address".to_string()],
|
||||
as_name: None,
|
||||
unqualified: vec![
|
||||
ast::UnqualifiedImport {
|
||||
as_name: Some("A".to_string()),
|
||||
location: Span::new(SrcId::empty(), 55..67),
|
||||
layer: Default::default(),
|
||||
name: "Address".to_string()
|
||||
},
|
||||
ast::UnqualifiedImport {
|
||||
as_name: Some("w".to_string()),
|
||||
location: Span::new(SrcId::empty(), 69..79),
|
||||
layer: Default::default(),
|
||||
name: "thing".to_string()
|
||||
}
|
||||
],
|
||||
package: (),
|
||||
},
|
||||
ast::UntypedDefinition::Use {
|
||||
location: Span::new(SrcId::empty(), 93..108),
|
||||
module: vec!["std".to_string(), "tx".to_string()],
|
||||
as_name: Some("t".to_string()),
|
||||
unqualified: vec![],
|
||||
package: (),
|
||||
},
|
||||
ast::UntypedDefinition::DataType {
|
||||
location: Span::new(SrcId::empty(), 122..240),
|
||||
constructors: vec![
|
||||
ast::RecordConstructor {
|
||||
location: Span::new(SrcId::empty(), 153..165),
|
||||
name: "Some".to_string(),
|
||||
arguments: vec![
|
||||
ast::RecordConstructorArg {
|
||||
label: None,
|
||||
annotation: ast::Annotation::Var {
|
||||
location: Span::new(SrcId::empty(), 158..159),
|
||||
name: "a".to_string(),
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 158..159),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},
|
||||
ast::RecordConstructorArg {
|
||||
label: None,
|
||||
annotation: ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 161..164),
|
||||
module: None,
|
||||
name: "Int".to_string(),
|
||||
arguments: vec![],
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 161..164),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},
|
||||
],
|
||||
documentation: None,
|
||||
sugar: false,
|
||||
},
|
||||
ast::RecordConstructor {
|
||||
location: Span::new(SrcId::empty(), 180..184),
|
||||
name: "None".to_string(),
|
||||
arguments: vec![],
|
||||
documentation: None,
|
||||
sugar: false,
|
||||
},
|
||||
ast::RecordConstructor {
|
||||
location: Span::new(SrcId::empty(), 199..226),
|
||||
name: "Wow".to_string(),
|
||||
arguments: vec![
|
||||
ast::RecordConstructorArg {
|
||||
label: Some("name".to_string(),),
|
||||
annotation: ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 211..214),
|
||||
module: None,
|
||||
name: "Int".to_string(),
|
||||
arguments: vec![],
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 205..214),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},
|
||||
ast::RecordConstructorArg {
|
||||
label: Some("age".to_string(),),
|
||||
annotation: ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 221..224),
|
||||
module: None,
|
||||
name: "Int".to_string(),
|
||||
arguments: vec![],
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 216..224),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},
|
||||
],
|
||||
documentation: None,
|
||||
sugar: false,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
name: "Option".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec!["a".to_string(),],
|
||||
public: false,
|
||||
typed_parameters: vec![],
|
||||
},
|
||||
ast::UntypedDefinition::DataType {
|
||||
location: Span::new(SrcId::empty(), 254..313),
|
||||
constructors: vec![ast::RecordConstructor {
|
||||
location: Span::new(SrcId::empty(), 275..313),
|
||||
name: "User".to_string(),
|
||||
arguments: vec![ast::RecordConstructorArg {
|
||||
label: Some("name".to_string()),
|
||||
annotation: ast::Annotation::Hole {
|
||||
location: Span::new(SrcId::empty(), 297..299),
|
||||
name: "_w".to_string(),
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 291..299),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},],
|
||||
documentation: None,
|
||||
sugar: true,
|
||||
},],
|
||||
doc: None,
|
||||
name: "User".to_string(),
|
||||
opaque: true,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
typed_parameters: vec![],
|
||||
},
|
||||
ast::UntypedDefinition::TypeAlias {
|
||||
alias: "Thing".to_string(),
|
||||
annotation: ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 340..351),
|
||||
module: None,
|
||||
name: "Option".to_string(),
|
||||
arguments: vec![ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 347..350),
|
||||
module: None,
|
||||
name: "Int".to_string(),
|
||||
arguments: vec![],
|
||||
},],
|
||||
},
|
||||
doc: None,
|
||||
location: Span::new(SrcId::empty(), 327..351),
|
||||
parameters: vec![],
|
||||
public: false,
|
||||
tipo: (),
|
||||
},
|
||||
ast::UntypedDefinition::TypeAlias {
|
||||
alias: "Me".to_string(),
|
||||
annotation: ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 379..393),
|
||||
module: None,
|
||||
name: "Option".to_string(),
|
||||
arguments: vec![ast::Annotation::Constructor {
|
||||
location: Span::new(SrcId::empty(), 386..392),
|
||||
module: None,
|
||||
name: "String".to_string(),
|
||||
arguments: vec![],
|
||||
},],
|
||||
},
|
||||
doc: None,
|
||||
location: Span::new(SrcId::empty(), 365..393),
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
tipo: (),
|
||||
},
|
||||
ast::UntypedDefinition::Fn {
|
||||
arguments: vec![ast::Arg {
|
||||
arg_name: ast::ArgName::Named {
|
||||
name: "a".to_string(),
|
||||
location: Span::new(SrcId::empty(), 422..423),
|
||||
},
|
||||
location: Span::new(SrcId::empty(), 422..423),
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},],
|
||||
body: expr::UntypedExpr::BinOp {
|
||||
location: Span::new(SrcId::empty(), 441..446),
|
||||
name: ast::BinOp::AddInt,
|
||||
left: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new(SrcId::empty(), 441..442),
|
||||
name: "a".to_string(),
|
||||
}),
|
||||
right: Box::new(expr::UntypedExpr::Int {
|
||||
location: Span::new(SrcId::empty(), 445..446),
|
||||
value: "1".to_string(),
|
||||
}),
|
||||
},
|
||||
doc: None,
|
||||
location: Span::new(SrcId::empty(), 407..460),
|
||||
name: "add_one".to_string(),
|
||||
public: true,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
},
|
||||
]
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
use std::{cell::RefCell, collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
ast::{Constant, FieldMap, Span, TypedConstant},
|
||||
build::Origin,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
/// A nominal (named) type such as `Int`, `Float`, or a programmer defined
|
||||
/// custom type such as `Person`. The type can take other types as
|
||||
/// arguments (aka "generics" or "parametric polymorphism").
|
||||
///
|
||||
/// If the type is defined in the Gleam prelude the `module` field will be
|
||||
/// empty, otherwise it will contain the name of the module that
|
||||
/// defines the type.
|
||||
///
|
||||
App {
|
||||
public: bool,
|
||||
module: Vec<String>,
|
||||
name: String,
|
||||
args: Vec<Arc<Type>>,
|
||||
},
|
||||
|
||||
/// The type of a function. It takes arguments and returns a value.
|
||||
///
|
||||
Fn {
|
||||
args: Vec<Arc<Type>>,
|
||||
retrn: Arc<Type>,
|
||||
},
|
||||
|
||||
/// A type variable. See the contained `TypeVar` enum for more information.
|
||||
///
|
||||
Var { tipo: Arc<RefCell<TypeVar>> },
|
||||
|
||||
/// A tuple is an ordered collection of 0 or more values, each of which
|
||||
/// can have a different type, so the `tuple` type is the sum of all the
|
||||
/// contained types.
|
||||
///
|
||||
Tuple { elems: Vec<Arc<Type>> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TypeVar {
|
||||
/// Unbound is an unbound variable. It is one specific type but we don't
|
||||
/// know what yet in the inference process. It has a unique id which can be used to
|
||||
/// identify if two unbound variable Rust values are the same Gleam type variable
|
||||
/// instance or not.
|
||||
///
|
||||
Unbound { id: u64 },
|
||||
/// Link is type variable where it was an unbound variable but we worked out
|
||||
/// that it is some other type and now we point to that one.
|
||||
///
|
||||
Link { tipo: Arc<Type> },
|
||||
/// A Generic variable stands in for any possible type and cannot be
|
||||
/// specialised to any one type
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```gleam
|
||||
/// type Cat(a) {
|
||||
/// Cat(name: a)
|
||||
/// }
|
||||
/// // a is TypeVar::Generic
|
||||
/// ```
|
||||
///
|
||||
Generic { id: u64 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ValueConstructor {
|
||||
pub public: bool,
|
||||
pub variant: ValueConstructorVariant,
|
||||
pub tipo: Arc<Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ValueConstructorVariant {
|
||||
/// A locally defined variable or function parameter
|
||||
LocalVariable { location: Span },
|
||||
|
||||
/// A module constant
|
||||
ModuleConstant {
|
||||
location: Span,
|
||||
module: String,
|
||||
literal: Constant<Arc<Type>, String>,
|
||||
},
|
||||
|
||||
/// A function belonging to the module
|
||||
ModuleFn {
|
||||
name: String,
|
||||
field_map: Option<FieldMap>,
|
||||
module: Vec<String>,
|
||||
arity: usize,
|
||||
location: Span,
|
||||
},
|
||||
|
||||
/// A constructor for a custom type
|
||||
Record {
|
||||
name: String,
|
||||
arity: usize,
|
||||
field_map: Option<FieldMap>,
|
||||
location: Span,
|
||||
module: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Module {
|
||||
pub name: Vec<String>,
|
||||
pub origin: Origin,
|
||||
pub package: String,
|
||||
pub types: HashMap<String, TypeConstructor>,
|
||||
pub types_constructors: HashMap<String, Vec<String>>,
|
||||
pub values: HashMap<String, ValueConstructor>,
|
||||
pub accessors: HashMap<String, AccessorsMap>,
|
||||
}
|
||||
|
||||
pub struct TypeConstructor {
|
||||
pub public: bool,
|
||||
pub origin: Span,
|
||||
pub module: Vec<String>,
|
||||
pub parameters: Vec<Arc<Type>>,
|
||||
pub typ: Arc<Type>,
|
||||
}
|
||||
|
||||
pub struct AccessorsMap {
|
||||
pub public: bool,
|
||||
pub tipo: Arc<Type>,
|
||||
pub accessors: HashMap<String, RecordAccessor>,
|
||||
}
|
||||
|
||||
pub struct RecordAccessor {
|
||||
// TODO: smaller int. Doesn't need to be this big
|
||||
pub index: u64,
|
||||
pub label: String,
|
||||
pub tipo: Arc<Type>,
|
||||
}
|
||||
|
||||
pub enum PatternConstructor {
|
||||
Record {
|
||||
name: String,
|
||||
field_map: Option<FieldMap>,
|
||||
},
|
||||
}
|
||||
|
||||
pub enum ModuleValueConstructor {
|
||||
Record {
|
||||
name: String,
|
||||
arity: usize,
|
||||
type_: Arc<Type>,
|
||||
field_map: Option<FieldMap>,
|
||||
location: Span,
|
||||
},
|
||||
|
||||
Fn {
|
||||
location: Span,
|
||||
},
|
||||
|
||||
Constant {
|
||||
literal: TypedConstant,
|
||||
location: Span,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
|
||||
pub enum Token {
|
||||
Error(char),
|
||||
Name { name: String },
|
||||
UpName { name: String },
|
||||
DiscardName { name: String },
|
||||
Int { value: String },
|
||||
String { value: String },
|
||||
// Groupings
|
||||
LeftParen, // (
|
||||
RightParen, // )
|
||||
LeftSquare, // [
|
||||
RightSquare, // }
|
||||
LeftBrace, // {
|
||||
RightBrace, // }
|
||||
// Int Operators
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
Slash,
|
||||
Less,
|
||||
Greater,
|
||||
LessEqual,
|
||||
GreaterEqual,
|
||||
Percent,
|
||||
// ByteString Operators
|
||||
PlusDot, // '+.'
|
||||
MinusDot, // '-.'
|
||||
StarDot, // '*.'
|
||||
SlashDot, // '/.'
|
||||
LessDot, // '<.'
|
||||
GreaterDot, // '>.'
|
||||
LessEqualDot, // '<=.'
|
||||
GreaterEqualDot, // '>=.'
|
||||
// Other Punctuation
|
||||
Colon,
|
||||
Comma,
|
||||
Hash, // '#'
|
||||
Bang, // '!'
|
||||
Equal,
|
||||
EqualEqual, // '=='
|
||||
NotEqual, // '!='
|
||||
Vbar, // '|'
|
||||
VbarVbar, // '||'
|
||||
AmperAmper, // '&&'
|
||||
Pipe, // '|>'
|
||||
Dot, // '.'
|
||||
RArrow, // '->'
|
||||
DotDot, // '..'
|
||||
EndOfFile,
|
||||
// Extra
|
||||
CommentNormal,
|
||||
CommentDoc,
|
||||
CommentModule,
|
||||
EmptyLine,
|
||||
// Keywords (alphabetically):
|
||||
As,
|
||||
Assert,
|
||||
Const,
|
||||
Fn,
|
||||
If,
|
||||
Is,
|
||||
Let,
|
||||
Opaque,
|
||||
Pub,
|
||||
Use,
|
||||
Todo,
|
||||
Try,
|
||||
Type,
|
||||
When,
|
||||
}
|
||||
|
||||
impl fmt::Display for Token {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s = match self {
|
||||
Token::Error(c) => {
|
||||
write!(f, "\"{}\"", c)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Token::Name { name } => name,
|
||||
Token::UpName { name } => name,
|
||||
Token::DiscardName { name } => name,
|
||||
Token::Int { value } => value,
|
||||
Token::String { value } => value,
|
||||
Token::LeftParen => "(",
|
||||
Token::RightParen => ")",
|
||||
Token::LeftSquare => "[",
|
||||
Token::RightSquare => "]",
|
||||
Token::LeftBrace => "{",
|
||||
Token::RightBrace => "}",
|
||||
Token::Plus => "+",
|
||||
Token::Minus => "-",
|
||||
Token::Star => "*",
|
||||
Token::Slash => "/",
|
||||
Token::Less => "<",
|
||||
Token::Greater => ">",
|
||||
Token::LessEqual => "<=",
|
||||
Token::GreaterEqual => ">=",
|
||||
Token::Percent => "%",
|
||||
Token::PlusDot => "+.",
|
||||
Token::MinusDot => "-.",
|
||||
Token::StarDot => "*.",
|
||||
Token::SlashDot => "/.",
|
||||
Token::LessDot => "<.",
|
||||
Token::GreaterDot => ">.",
|
||||
Token::LessEqualDot => "<=.",
|
||||
Token::GreaterEqualDot => ">=.",
|
||||
Token::Colon => ":",
|
||||
Token::Comma => ",",
|
||||
Token::Hash => "#",
|
||||
Token::Bang => "!",
|
||||
Token::Equal => "=",
|
||||
Token::EqualEqual => "==",
|
||||
Token::NotEqual => "!=",
|
||||
Token::Vbar => "|",
|
||||
Token::VbarVbar => "||",
|
||||
Token::AmperAmper => "&&",
|
||||
Token::Pipe => "|>",
|
||||
Token::Dot => ".",
|
||||
Token::RArrow => "->",
|
||||
Token::DotDot => "..",
|
||||
Token::EndOfFile => "EOF",
|
||||
Token::CommentNormal => "//",
|
||||
Token::CommentDoc => "///",
|
||||
Token::CommentModule => "////",
|
||||
Token::EmptyLine => "EMPTYLINE",
|
||||
Token::As => "as",
|
||||
Token::Assert => "assert",
|
||||
Token::When => "when",
|
||||
Token::Is => "is",
|
||||
Token::Const => "const",
|
||||
Token::Fn => "fn",
|
||||
Token::If => "if",
|
||||
Token::Use => "import",
|
||||
Token::Let => "let",
|
||||
Token::Opaque => "opaque",
|
||||
Token::Pub => "pub",
|
||||
Token::Todo => "todo",
|
||||
Token::Try => "try",
|
||||
Token::Type => "type",
|
||||
};
|
||||
write!(f, "\"{}\"", s)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// imports
|
||||
use std/address.Address as A // alias
|
||||
|
||||
use std/list.{map, foldl} // access module members in one import
|
||||
|
||||
// `///` used for document generation
|
||||
|
||||
// Records (single constructor `data` type)
|
||||
pub type Datum {
|
||||
signer: Address,
|
||||
}
|
||||
|
||||
// above is suger for
|
||||
pub type Datum {
|
||||
Datum { signer: Address },
|
||||
}
|
||||
|
||||
// type aliases
|
||||
type A = Address
|
||||
|
||||
// multiple constructors and a `generic`
|
||||
pub type Redeemer(a) {
|
||||
// records wrapped in parens
|
||||
Buy(Address, a),
|
||||
// records wrapped in curlies
|
||||
Sell { address: Address, some_thing: a },
|
||||
}
|
||||
|
||||
pub fn main(datum: Datum, redeemer: Redeemer, ctx: ScriptContext) {
|
||||
[1, 2, 3]
|
||||
|> list.map(fn(x) -> x + 1)
|
||||
}
|
||||
|
||||
// named and anonymous functions
|
||||
fn(x) -> x + 1
|
||||
|
||||
fn add_one(x) -> x + 1
|
||||
|
||||
fn(x: Int) -> x + 1
|
||||
|
||||
fn add_one(label x: Int) -> x + 1
|
||||
|
||||
fn(x: Int) {
|
||||
x + 1
|
||||
}
|
||||
|
||||
fn(x: Int) -> Int {
|
||||
x + 1
|
||||
}
|
||||
|
||||
fn add_one(x: Int) -> Int {
|
||||
x + 1
|
||||
}
|
||||
|
||||
// can be curried
|
||||
fn add(a, b) {
|
||||
a + 1
|
||||
}
|
||||
|
||||
let add_one = add(1)
|
||||
|
||||
// matching
|
||||
when redeemer is {
|
||||
Buyer(address, thing) -> do_stuff(),
|
||||
Seller { address, some_thing } -> do_seller_stuff(),
|
||||
}
|
Loading…
Reference in New Issue