diff --git a/.vscode/launch.json b/.vscode/launch.json index 395b5bd..063fb73 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { "name": "(Windows) Launch", "type": "cppvsdbg", @@ -33,10 +34,10 @@ // }, "program": "${workspaceFolder}/target/debug/cli", - "args":["--llvm", "-o", "./test_output.llvm", "./sample.fb"], + "args":["--llvm", "-o", "./test_output.llvm", "./other_sample.fb"], "cwd": "${workspaceFolder}", "env": {"RUST_BACKTRACE": "1"}, - "console": "externalTerminal", + "console": "integratedTerminal", "preLaunchTask": "build" } ] diff --git a/Cargo.lock b/Cargo.lock index 2533f75..0918e8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,66 +4,73 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "bimap" @@ -73,18 +80,18 @@ checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ - "libc", + "shlex", ] [[package]] name = "clap" -version = "4.4.18" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -92,9 +99,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -104,9 +111,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", @@ -116,9 +123,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cli" @@ -131,9 +138,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "compiler" @@ -142,27 +149,34 @@ dependencies = [ "bimap", "itertools 0.11.0", "lazy_static", + "pretty_assertions", "regex", "thiserror", "utf8-chars", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "inkwell" -version = "0.4.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#e06002337432622c4d271108bb298b500f5bea56" +version = "0.5.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#4028abc9d147e5b0a16acedc7047545fc2213c3f" dependencies = [ "either", "inkwell_internals", @@ -174,14 +188,20 @@ dependencies = [ [[package]] name = "inkwell_internals" -version = "0.9.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#e06002337432622c4d271108bb298b500f5bea56" +version = "0.10.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#4028abc9d147e5b0a16acedc7047545fc2213c3f" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.11.0" @@ -193,9 +213,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -206,15 +226,15 @@ version = "0.1.0" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "llvm-codegen" @@ -222,29 +242,30 @@ version = "0.1.0" dependencies = [ "compiler", "inkwell", - "itertools 0.12.1", + "itertools 0.13.0", "multimap", "self_cell", ] [[package]] name = "llvm-sys" -version = "150.1.3" +version = "180.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd60e740af945d99c2446a52e3ab8cdba2f740a40a16c51f6871bdea2abc687" +checksum = "778fa5fa02e32728e718f11eec147e6f134137399ab02fd2c13d32476337affa" dependencies = [ + "anyhow", "cc", "lazy_static", "libc", - "regex", + "regex-lite", "semver", ] [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "multimap" @@ -261,29 +282,39 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -293,64 +324,76 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -359,18 +402,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -385,18 +428,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8-chars" -version = "3.0.1" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08465e4e09f9ac32d8bc0967565046ec27a9078f82fe738da658ccd689c2c277" +checksum = "bb8b618e8c34f77c00710bbe6adaff80f3c856296be49241071e1aa08df45cec" dependencies = [ "arrayvec", ] [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "windows-sys" @@ -409,13 +452,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -424,42 +468,54 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "yansi" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/cli/src/main.rs b/cli/src/main.rs index af7180b..5e655c0 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -32,88 +32,90 @@ fn main() { }, ); - let (program, _warnings) = compiler::from_file(&args.file, fwd_decl.clone(), [ - ( - "+".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 - types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 - types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 - types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 - types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 - ] - ), - ( - "-".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 - types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 - types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 - types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 - types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 - ] - ), - ( - "*".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 - types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 - types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 - types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 - types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 - ] - ), - ( - "/".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 - types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 - types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 - types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 - types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 - ] - ), - ( - "&&".to_string(), - vec![ - types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), - ] - ), - ( - "||".to_string(), - vec![ - types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), - ] - ), - ( - "==".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::BOOL)), // float64 -> float64 -> bool - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::BOOL)), // float32 -> float32 -> bool - types::INT64.fn_ty(&types::INT64.fn_ty(&types::BOOL)), // int64 -> int64 -> bool - types::INT32.fn_ty(&types::INT32.fn_ty(&types::BOOL)), // int32 -> int32 -> bool - types::INT16.fn_ty(&types::INT16.fn_ty(&types::BOOL)), // int16 -> int16 -> bool - types::INT8.fn_ty(&types::INT8.fn_ty(&types::BOOL)), // int8 -> int8 -> bool - types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), // bool -> bool -> bool - ] - ), - ( - "!=".to_string(), - vec![ - types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::BOOL)), // float64 -> float64 -> bool - types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::BOOL)), // float32 -> float32 -> bool - types::INT64.fn_ty(&types::INT64.fn_ty(&types::BOOL)), // int64 -> int64 -> bool - types::INT32.fn_ty(&types::INT32.fn_ty(&types::BOOL)), // int32 -> int32 -> bool - types::INT16.fn_ty(&types::INT16.fn_ty(&types::BOOL)), // int16 -> int16 -> bool - types::INT8.fn_ty(&types::INT8.fn_ty(&types::BOOL)), // int8 -> int8 -> bool - types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), // bool -> bool -> bool - ] - ), - ].into(),"jit".to_string()); + let (program, _warnings) = compiler::from_file( + &args.file, + fwd_decl.clone(), + [ + ( + "+".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 + types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 + types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 + types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 + types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 + ], + ), + ( + "-".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 + types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 + types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 + types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 + types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 + ], + ), + ( + "*".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 + types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 + types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 + types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 + types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 + ], + ), + ( + "/".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::FLOAT64)), // float64 -> float64 -> float64 + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::FLOAT32)), // float32 -> float32 -> float32 + types::INT64.fn_ty(&types::INT64.fn_ty(&types::INT64)), // int64 -> int64 -> int64 + types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32)), // int32 -> int32 -> int32 + types::INT16.fn_ty(&types::INT16.fn_ty(&types::INT16)), // int16 -> int16 -> int16 + types::INT8.fn_ty(&types::INT8.fn_ty(&types::INT8)), // int8 -> int8 -> int8 + ], + ), + ( + "&&".to_string(), + vec![types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL))], + ), + ( + "||".to_string(), + vec![types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL))], + ), + ( + "==".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::BOOL)), // float64 -> float64 -> bool + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::BOOL)), // float32 -> float32 -> bool + types::INT64.fn_ty(&types::INT64.fn_ty(&types::BOOL)), // int64 -> int64 -> bool + types::INT32.fn_ty(&types::INT32.fn_ty(&types::BOOL)), // int32 -> int32 -> bool + types::INT16.fn_ty(&types::INT16.fn_ty(&types::BOOL)), // int16 -> int16 -> bool + types::INT8.fn_ty(&types::INT8.fn_ty(&types::BOOL)), // int8 -> int8 -> bool + types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), // bool -> bool -> bool + ], + ), + ( + "!=".to_string(), + vec![ + types::FLOAT64.fn_ty(&types::FLOAT64.fn_ty(&types::BOOL)), // float64 -> float64 -> bool + types::FLOAT32.fn_ty(&types::FLOAT32.fn_ty(&types::BOOL)), // float32 -> float32 -> bool + types::INT64.fn_ty(&types::INT64.fn_ty(&types::BOOL)), // int64 -> int64 -> bool + types::INT32.fn_ty(&types::INT32.fn_ty(&types::BOOL)), // int32 -> int32 -> bool + types::INT16.fn_ty(&types::INT16.fn_ty(&types::BOOL)), // int16 -> int16 -> bool + types::INT8.fn_ty(&types::INT8.fn_ty(&types::BOOL)), // int8 -> int8 -> bool + types::BOOL.fn_ty(&types::BOOL.fn_ty(&types::BOOL)), // bool -> bool -> bool + ], + ), + ] + .into(), + "jit".to_string(), + ); match program { Err(errors) => { @@ -122,14 +124,13 @@ fn main() { } } Ok(ast) => { - - if args.run { + if dbg!(args.run) { let mut jit = llvm_codegen::create_jit_runtime(); jit.add_declarations(ast.declarations); unsafe { jit.run_function::("main", ()); } - } else if args.output_llvm { + } else if dbg!(args.output_llvm) { llvm_codegen::compile_file(ast, args.file, args.out_file, fwd_decl) } } diff --git a/cli/test.fb b/cli/test.fb index ef51e8b..1f1f6b9 100644 --- a/cli/test.fb +++ b/cli/test.fb @@ -44,7 +44,7 @@ let show_something_else _ : () -> bool = let test (a:(int32,int32)) = let x : int32 = 0; return x; - +for enum Result = | Ok T | Err E let main _ : () -> () = // let a : bool = true; // let x : int32 = 0; diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index bd2464e..7c2d36c 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -17,3 +17,7 @@ regex = "1.6.0" lazy_static = "1.4.0" bimap = "0.6.3" thiserror = "1.0.57" + + +[dev-dependencies] +pretty_assertions = "1.4" \ No newline at end of file diff --git a/compiler/src/ast.rs b/compiler/src/ast.rs index a05d459..9db7b35 100644 --- a/compiler/src/ast.rs +++ b/compiler/src/ast.rs @@ -83,6 +83,124 @@ impl ModuleDeclaration { .flat_map(|it| it.get_dependencies()) .collect() } + + pub fn get_types(&self) -> HashMap { + self.declarations + .iter() + .flat_map(|decl| match decl { + TopLevelDeclaration::Value(_) => [].into(), + TopLevelDeclaration::Mod(m) => m.get_types(), + TopLevelDeclaration::TypeDefinition(TypeDefinition::Alias(new, old)) => { + [(new.clone(), old.clone())].into() + } + TopLevelDeclaration::TypeDefinition(TypeDefinition::Struct(s)) => [( + s.ident.clone(), + ResolvedType::User { + name: s.ident.clone(), + generics: s + .generics + .as_ref() + .map(|generics| { + generics + .decls + .iter() + .map(|(loc, name)| ResolvedType::Generic { + name: name.clone(), + loc: *loc, + }) + .collect() + }) + .unwrap_or_default(), + loc: s.loc, + }, + )] + .into(), + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(e)) => { + let base_ty = ResolvedType::User { + name: e.ident.clone(), + generics: e + .generics + .as_ref() + .map(|generics| { + generics + .decls + .iter() + .map(|(loc, name)| ResolvedType::Generic { + name: name.clone(), + loc: *loc, + }) + .collect() + }) + .unwrap_or_default(), + loc: e.loc, + }; + let mut out = vec![(e.ident.clone(), base_ty.clone())]; + + for variant in &e.values { + let ident = variant.get_ident(); + let new_ident = format!("{}::{}", &e.ident, ident); + let generics = e + .generics + .as_ref() + .map(|generics| { + generics + .decls + .iter() + .map(|(loc, name)| ResolvedType::Generic { + name: name.clone(), + loc: *loc, + }) + .collect() + }) + .unwrap_or_default(); + match variant { + EnumVariant::Unit { ident:_, loc } => out.push(( + new_ident.clone(), + ResolvedType::Dependent { + base: base_ty.clone().into(), + ident: new_ident.clone(), + actual: ResolvedType::Void.into(), + generics, + loc: *loc, + }, + )), + EnumVariant::Tuple { ident:_, ty, loc } => out.push(( + new_ident.clone(), + ResolvedType::Dependent { + base: base_ty.clone().into(), + ident: new_ident, + actual: ty.clone().into(), + generics, + loc: *loc, + }, + )), + EnumVariant::Struct { + ident:_, loc, .. + } => { + + out.push(( + new_ident.clone(), + ResolvedType::Dependent { + base: base_ty.clone().into(), + ident: new_ident.clone(), + actual: ResolvedType::User { + name: new_ident, + generics:generics.clone(), + loc: *loc, + } + .into(), + generics, + loc: *loc, + }, + )) + } + } + } + HashMap::from_iter(out) + } + }) + .collect() + } } #[derive(PartialEq, Debug)] @@ -94,7 +212,6 @@ pub enum TopLevelDeclaration { Value(TopLevelValue), } - impl TopLevelDeclaration { pub(crate) fn replace(&mut self, nice_name: &str, actual: &str) { match self { @@ -107,9 +224,7 @@ impl TopLevelDeclaration { fn get_dependencies(&self) -> HashMap> { match self { TopLevelDeclaration::Mod(m) => m.get_dependencies(), - TopLevelDeclaration::Value(v) =>{ - [(v.ident.clone(), v.get_dependencies())].into() - } , + TopLevelDeclaration::Value(v) => [(v.ident.clone(), v.get_dependencies())].into(), TopLevelDeclaration::TypeDefinition(_) => [].into(), } } @@ -117,26 +232,33 @@ impl TopLevelDeclaration { #[derive(PartialEq, Debug)] pub struct TopLevelValue { - pub loc : crate::Location, + pub loc: crate::Location, pub is_op: bool, - pub ident : String, - pub args : Vec, - pub ty:Option, - pub value : ValueType, - pub generics : Option, - pub abi : Option, + pub ident: String, + pub args: Vec, + pub ty: Option, + pub value: ValueType, + pub generics: Option, + pub abi: Option, } impl TopLevelValue { - fn replace(&mut self, nice_name:&str, actual:&str) { + fn replace(&mut self, nice_name: &str, actual: &str) { if let Some(ty) = self.ty.as_mut() { - *ty = ty.replace(nice_name,actual); + *ty = ty.replace(nice_name, actual); } self.value.replace(nice_name, actual); + for arg in &mut self.args { + arg.replace(nice_name, actual); + } } fn get_dependencies(&self) -> HashSet { - let mut values = self.args.iter().flat_map(ArgDeclaration::get_idents).collect_vec(); + let mut values = self + .args + .iter() + .flat_map(ArgDeclaration::get_idents) + .collect_vec(); values.push(self.ident.clone()); self.value.get_dependencies(values) } @@ -151,7 +273,7 @@ pub struct GenericsDecl { pub enum TypeDefinition { Alias(String, ResolvedType), #[allow(unused)] - Enum(EnumDeclation), + Enum(EnumDeclaration), Struct(StructDefinition), } @@ -159,7 +281,7 @@ impl TypeDefinition { pub(crate) fn get_ident(&self) -> String { match self { TypeDefinition::Alias(name, _) => name.clone(), - TypeDefinition::Enum(_) => todo!(), + TypeDefinition::Enum(enum_) => enum_.ident.clone(), TypeDefinition::Struct(strct) => strct.ident.clone(), } } @@ -167,11 +289,46 @@ impl TypeDefinition { fn replace(&mut self, nice_name: &str, actual: &str) { match self { Self::Alias(_, ty) => *ty = ty.replace(nice_name, actual), - Self::Enum(_) => todo!(), + Self::Enum(enum_) => { + if enum_.ident == nice_name { + enum_.ident = actual.to_string(); + } + if let Some(generics) = &enum_.generics { + if generics + .decls + .iter() + .find(|(_, ident)| ident == nice_name) + .is_some() + { + return; + } + } + for variant in &mut enum_.values { + match variant { + EnumVariant::Unit { .. } => (), + EnumVariant::Tuple { ty, .. } => *ty = ty.replace(nice_name, actual), + EnumVariant::Struct { fields, .. } => { + for field in fields { + field.ty = field.ty.replace(nice_name, actual); + } + } + } + } + } Self::Struct(strct) => { if strct.ident == nice_name { strct.ident = actual.to_string(); } + if let Some(generics) = &strct.generics { + if generics + .decls + .iter() + .find(|(_, ident)| ident == nice_name) + .is_some() + { + return; + } + } for field in &mut strct.values { field.ty = field.ty.replace(nice_name, actual); } @@ -179,9 +336,9 @@ impl TypeDefinition { } } } - +/// {generics} enum {ident} = {values} #[derive(PartialEq, Debug, Clone)] -pub struct EnumDeclation { +pub struct EnumDeclaration { pub ident: String, pub generics: Option, pub values: Vec, @@ -191,9 +348,30 @@ pub struct EnumDeclation { #[derive(PartialEq, Debug, Clone)] #[allow(unused)] pub enum EnumVariant { - Unit(String, crate::Location), - Tuple(String, Vec, crate::Location), - Struct(String, StructDefinition, crate::Location), + /// | {ident} + Unit { ident: String, loc: crate::Location }, + /// | {ident} ({ty*}) + Tuple { + ident: String, + ty: ResolvedType, + loc: crate::Location, + }, + /// | {ident} {{ {feilddecl*} }} + Struct { + ident: String, + fields: Vec, + loc: crate::Location, + }, +} + +impl EnumVariant { + pub fn get_ident(&self) -> String { + match self { + Self::Struct { ident, .. } | Self::Unit { ident, .. } | Self::Tuple { ident, .. } => { + ident.clone() + } + } + } } #[derive(PartialEq, Debug, Clone)] @@ -214,71 +392,97 @@ pub struct FieldDecl { #[derive(PartialEq, Debug, Clone)] pub enum ArgDeclaration { Simple { - loc : crate::Location, + loc: crate::Location, ident: String, - ty:Option, + ty: Option, }, DestructureTuple(Vec, Option, crate::Location), DestructureStruct { - loc:crate::Location, - struct_ident : String, - fields : Vec, - renamed_fields : HashMap + loc: crate::Location, + struct_ident: String, + fields: Vec, + renamed_fields: HashMap, }, Discard { - loc:crate::Location, - ty:Option, + loc: crate::Location, + ty: Option, }, Unit { - loc:crate::Location, - ty:Option, + loc: crate::Location, + ty: Option, }, } impl ArgDeclaration { - pub(crate) fn apply_generic(&mut self, generic:&str) { + pub(crate) fn replace(&mut self, nice_name: &str, actual: &str) { match self { - Self::Discard { ty, .. } - | Self::Unit { ty, .. } - | Self::Simple { ty, .. } => if let Some(ty) = ty { - *ty = ty.clone().replace_user_with_generic(generic); - }, + Self::Discard { ty, .. } | Self::Unit { ty, .. } | Self::Simple { ty, .. } => { + *ty = ty.as_ref().map(|ty| ty.replace(nice_name, actual)) + } + Self::DestructureTuple(subs, ty, _) => { + *ty = ty.as_ref().map(|ty| ty.replace(nice_name, actual)); + for sub_arg in subs { + sub_arg.replace(nice_name, actual); + } + } + Self::DestructureStruct { struct_ident, .. } if struct_ident == nice_name => { + *struct_ident = actual.to_string(); + } + Self::DestructureStruct { .. } => (), + } + } + + pub(crate) fn apply_generic(&mut self, generic: &str) { + match self { + Self::Discard { ty, .. } | Self::Unit { ty, .. } | Self::Simple { ty, .. } => { + if let Some(ty) = ty { + *ty = ty.clone().replace_user_with_generic(generic); + } + } Self::DestructureTuple(contents, ty, _) => { if let Some(ty) = ty { *ty = ty.clone().replace_user_with_generic(generic); } contents.iter_mut().for_each(|it| it.apply_generic(generic)) } - _ => () + _ => (), } } fn get_idents(&self) -> Vec { match self { Self::Simple { ident, .. } => vec![ident.clone()], - Self::DestructureStruct { fields, renamed_fields, .. } => { - renamed_fields.values().cloned().chain(fields.iter().cloned()).collect() - }, - Self::DestructureTuple(decls, _,_) => decls.iter().flat_map(Self::get_idents).collect(), + Self::DestructureStruct { + fields, + renamed_fields, + .. + } => renamed_fields + .values() + .cloned() + .chain(fields.iter().cloned()) + .collect(), + Self::DestructureTuple(decls, _, _) => { + decls.iter().flat_map(Self::get_idents).collect() + } Self::Discard { .. } | Self::Unit { .. } => Vec::new(), } } fn get_types(&self) -> HashSet { match self { Self::DestructureTuple(idents, ty, _) => { - let mut out : HashSet = idents.iter().flat_map(Self::get_types).collect(); + let mut out: HashSet = idents.iter().flat_map(Self::get_types).collect(); if let Some(ty) = ty { out.extend(ty.get_all_types()); } out } Self::DestructureStruct { struct_ident, .. } => [struct_ident.clone()].into(), - Self::Discard { ty, .. } - | Self::Unit { ty, .. } - | Self::Simple { ty, .. } => if let Some(ty) = ty { - ty.get_all_types() - } else { - HashSet::new() - }, + Self::Discard { ty, .. } | Self::Unit { ty, .. } | Self::Simple { ty, .. } => { + if let Some(ty) = ty { + ty.get_all_types() + } else { + HashSet::new() + } + } } } } @@ -315,18 +519,22 @@ impl ValueDeclaration { } for arg in &self.args { match arg { - ArgDeclaration::Simple { ty, .. } - | ArgDeclaration::DestructureTuple(_, ty, _) - if ty.is_some() => { + ArgDeclaration::Simple { ty, .. } | ArgDeclaration::DestructureTuple(_, ty, _) + if ty.is_some() => + { let Some(ty) = ty else { unreachable!() }; let tys = ty.get_all_types(); output.extend(tys); } - _=>(), + _ => (), } } - let args = self.args.iter().flat_map(ArgDeclaration::get_idents).collect_vec(); + let args = self + .args + .iter() + .flat_map(ArgDeclaration::get_idents) + .collect_vec(); let dependencies = self.value.get_dependencies(args); output.extend(dependencies); output @@ -812,6 +1020,7 @@ pub struct MatchArm { } impl MatchArm { fn replace(&mut self, nice_name: &str, actual: &str) { + self.cond.replace(nice_name,actual); let names = self.cond.get_idents(); if names.contains(nice_name) { return; @@ -832,20 +1041,29 @@ pub enum Pattern { ConstStr(String), ConstChar(String), ConstBool(bool), //... this is one is odd but gonna support it anyway and eventaully warn with suggestion to convert to if - Read(String,crate::Location), + Read(String, crate::Location), Destructure(PatternDestructure), + EnumVariant { + ty: Option, + variant: String, + pattern: Option>, + loc: crate::Location, + }, + // maybe this one day? + // {name} @ {subpatterns} + // Binding(String /*name*/,Box/*sub_patterns*/,crate::locations) Error, - Or(Box, Box),/* - | 0 | 1 | 2 -> Combo( - ConstNumber(0), - Combo( - ConstNumber(1), - ConstNumber(2) - ) - ) - */ - // todo! conditional branch - // todo! variant patterns. + Or(Box, Box), /* + | 0 | 1 | 2 -> Combo( + ConstNumber(0), + Combo( + ConstNumber(1), + ConstNumber(2) + ) + ) + */ + // todo! conditional branch + // todo! variant patterns. } impl Pattern { @@ -853,7 +1071,7 @@ impl Pattern { match self { Self::Read(name, _) => [name.clone()].into(), Self::Destructure(d) => d.get_idents(), - Self::Or(lhs,rhs) => { + Self::Or(lhs, rhs) => { let mut idents = lhs.get_idents(); idents.extend(rhs.get_idents()); idents @@ -861,12 +1079,54 @@ impl Pattern { _ => HashSet::new(), } } + + fn replace(&mut self, nice_name: &str, actual: &str) { + match self { + + Self::Destructure(destructure) => match destructure { + PatternDestructure::Struct { base_ty, .. } => { + if let Some(ty) = base_ty { + if ty == nice_name { + *ty = actual.into(); + } + } + }, + PatternDestructure::Tuple(pats) => { + for pat in pats { + pat.replace(nice_name,actual) + } + }, + PatternDestructure::Unit => (), + }, + Self::EnumVariant { ty, variant, pattern, .. } => { + if let Some(ty) = ty { + if ty == nice_name { + *ty = actual.into(); + } + } else { + if variant == nice_name { + *variant = actual.into(); + } + } + if let Some(pat) = pattern { + pat.replace(nice_name,actual); + } + }, + + Self::Or(lhs, rhs) => { + lhs.replace(nice_name,actual); + rhs.replace(nice_name,actual); + } + _=>() + } + } } #[derive(Debug, PartialEq, Eq)] pub enum PatternDestructure { Struct { - fields : HashMap + base_ty: Option, + fields: HashMap, }, Tuple(Vec), Unit, @@ -875,8 +1135,8 @@ impl PatternDestructure { fn get_idents(&self) -> HashSet { match self { Self::Tuple(pats) => pats.iter().flat_map(Pattern::get_idents).collect(), - Self::Struct { fields } => todo!("struct destructuring"), + Self::Struct { .. } => todo!("struct destructuring"), Self::Unit => HashSet::new(), } } -} \ No newline at end of file +} diff --git a/compiler/src/inference.rs b/compiler/src/inference.rs index 64d1800..5ca9239 100644 --- a/compiler/src/inference.rs +++ b/compiler/src/inference.rs @@ -1,11 +1,13 @@ -use std::{cmp::Ordering, collections::{HashMap, HashSet}}; +use std::{ + cmp::Ordering, + collections::{HashMap, HashSet}, +}; use itertools::Itertools; use crate::{ ast as untyped_ast, types::{self, ResolvedType}, - util::ExtraUtilFunctions, }; pub(crate) mod ast; @@ -28,9 +30,10 @@ impl Context { &mut self, ast: untyped_ast::ModuleDeclaration, ) -> ast::ModuleDeclaration { + self.known_types.extend(ast.get_types()); let mut ast = self.assign_ids_module(ast); - self.try_to_infer(dbg!(&mut ast)); - self.apply_equations(dbg!(&mut ast)); + self.try_to_infer(&mut ast); + self.apply_equations(&mut ast); ast } @@ -93,23 +96,34 @@ impl Context { decl: untyped_ast::TopLevelDeclaration, ) -> ast::TopLevelDeclaration { match decl { - untyped_ast::TopLevelDeclaration::TypeDefinition(ty) => ast::TopLevelDeclaration::Type(ty), + untyped_ast::TopLevelDeclaration::TypeDefinition(ty) => { + ast::TopLevelDeclaration::Type(ty) + } untyped_ast::TopLevelDeclaration::Mod(_) => todo!(), - untyped_ast::TopLevelDeclaration::Value(untyped_ast::TopLevelValue{ loc, is_op, ident, args, ty, value, generics, abi }) => { + untyped_ast::TopLevelDeclaration::Value(untyped_ast::TopLevelValue { + loc, + is_op, + ident, + args, + ty, + value, + generics, + abi, + }) => { // ast::Declaration::Value(self.assign_ids_value_decl(v)) let ty = ty.unwrap_or_else(|| self.get_next_type_id()); let id = self.get_next_expr_id(); - self.known_values.insert(ident.clone(),ty.clone()); + self.known_values.insert(ident.clone(), ty.clone()); let args = args .into_iter() .enumerate() - .map(|(idx,arg)| { + .map(|(idx, arg)| { let expected = if !ty.is_function() { None } else { Some(ty.get_nth_arg(idx)) }; - self.assign_ids_arg(arg,expected.as_ref()) + self.assign_ids_arg(arg, expected.as_ref()) }) .collect(); let value = match value { @@ -124,59 +138,86 @@ impl Context { ), untyped_ast::ValueType::External => ast::ValueType::External, }; - ast::TopLevelDeclaration::Value(ast::TopLevelValue { - loc, - is_op, - ident, - args, - ty, - value, - generics, - abi, - id + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc, + is_op, + ident, + args, + ty, + value, + generics, + abi, + id, }) } } } - pub(crate) fn assign_ids_arg(&mut self, arg:untyped_ast::ArgDeclaration, expected_ty:Option<&ResolvedType>) -> ast::ArgDeclaration{ + pub(crate) fn assign_ids_arg( + &mut self, + arg: untyped_ast::ArgDeclaration, + expected_ty: Option<&ResolvedType>, + ) -> ast::ArgDeclaration { match arg { - untyped_ast::ArgDeclaration::Simple{ loc, ident, ty } => { - let ty = ty.or(expected_ty.cloned()).unwrap_or_else(|| self.get_next_type_id()); + untyped_ast::ArgDeclaration::Simple { loc, ident, ty } => { + let ty = ty + .or(expected_ty.cloned()) + .unwrap_or_else(|| self.get_next_type_id()); let id = self.get_next_expr_id(); self.known_locals.insert(ident.clone(), ty.clone()); ast::ArgDeclaration::Simple { loc, ident, ty, id } - }, - untyped_ast::ArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } => { + } + untyped_ast::ArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => { + ast::ArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + }; // nothing to rea todo!("not sure how to handle this as of yet."); - ast::ArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } // nothing to rea } untyped_ast::ArgDeclaration::DestructureTuple(contents, ty, loc) => { - let ty = ty.or(expected_ty.cloned()).unwrap_or_else(|| self.get_next_type_id()); + let ty = ty + .or(expected_ty.cloned()) + .unwrap_or_else(|| self.get_next_type_id()); let contents = if let ResolvedType::Tuple { underlining, .. } = &ty { if contents.len() != underlining.len() { // TODO! generate destructuring error. } - underlining.iter().zip(contents).map(|(ty, arg)| { - self.assign_ids_arg(arg, Some(ty)) - }).collect() + underlining + .iter() + .zip(contents) + .map(|(ty, arg)| self.assign_ids_arg(arg, Some(ty))) + .collect() } else { - contents.into_iter().map(|arg| { - self.assign_ids_arg(arg, None) - }).collect() + contents + .into_iter() + .map(|arg| self.assign_ids_arg(arg, None)) + .collect() }; ast::ArgDeclaration::DestructureTuple(contents, ty, loc) - }, + } untyped_ast::ArgDeclaration::Discard { loc, ty } => { //TODO! generate error of unable to deduce type. - ast::ArgDeclaration::Discard { loc, ty:ty.or(expected_ty.cloned()).unwrap_or(types::ERROR) } - }, + ast::ArgDeclaration::Discard { + loc, + ty: ty.or(expected_ty.cloned()).unwrap_or(types::ERROR), + } + } untyped_ast::ArgDeclaration::Unit { loc, ty } => { if let Some(ty) = &ty { if ty != &types::UNIT { //TODO! generate type error. } } - ast::ArgDeclaration::Unit { loc, ty:ty.unwrap_or(types::UNIT) } + ast::ArgDeclaration::Unit { + loc, + ty: ty.unwrap_or(types::UNIT), + } } } } @@ -275,7 +316,7 @@ impl Context { .into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect(); - (cond.boxed(), branch) + (cond.into(), branch) }) .collect(); let else_branch = else_branch @@ -283,7 +324,7 @@ impl Context { .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect(); ast::Statement::IfStatement(ast::IfBranching { - cond: cond.boxed(), + cond: cond.into(), true_branch, else_ifs, else_branch, @@ -316,7 +357,7 @@ impl Context { .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect(); let cond = self.assign_ids_pattern(cond, &on_t); - let ret = ret.map(|ret| self.assign_ids_expr(*ret, None).boxed()); + let ret = ret.map(|ret| self.assign_ids_expr(*ret, None).into()); ast::MatchArm { block, ret, @@ -327,61 +368,98 @@ impl Context { .collect(); ast::Match { loc, - on: on.boxed(), + on: on.into(), arms, id, } } fn assign_ids_pattern( &mut self, - pattern:untyped_ast::Pattern, - on_t : &ResolvedType + pattern: untyped_ast::Pattern, + on_t: &ResolvedType, ) -> ast::Pattern { match pattern { untyped_ast::Pattern::Default => ast::Pattern::Default, - untyped_ast::Pattern::ConstNumber(num) => { - - ast::Pattern::ConstNumber(num, on_t.clone()) - }, + untyped_ast::Pattern::ConstNumber(num) => ast::Pattern::ConstNumber(num, on_t.clone()), untyped_ast::Pattern::ConstStr(s) => ast::Pattern::ConstStr(s), untyped_ast::Pattern::ConstChar(s) => ast::Pattern::ConstChar(s), untyped_ast::Pattern::ConstBool(b) => ast::Pattern::ConstBool(b), - untyped_ast::Pattern::Read(name, loc) => { - ast::Pattern::Read { - ident:name, - loc, - ty:on_t.clone(), - id:self.get_next_expr_id() - } + untyped_ast::Pattern::Read(name, loc) => ast::Pattern::Read { + ident: name, + loc, + ty: on_t.clone(), + id: self.get_next_expr_id(), }, untyped_ast::Pattern::Destructure(destruction) => { let inner = match destruction { - untyped_ast::PatternDestructure::Struct { fields } => todo!(), - untyped_ast::PatternDestructure::Tuple(values) => { + untyped_ast::PatternDestructure::Struct { base_ty, fields } => { + let base_ty = base_ty + .map(|base_ty| ResolvedType::User { + name: base_ty, + generics: Vec::new(), + loc: (0, 0), + }) + .unwrap_or(on_t.clone()); + ast::DestructurePattern::Struct { + base_ty, + fields: fields + .into_iter() + .map(|(name, pat)| { + let on_ty = self.get_next_type_id(); + (name, self.assign_ids_pattern(pat, &on_ty)) + }) + .collect(), + } + } + untyped_ast::PatternDestructure::Tuple(values) => { let id = self.get_next_expr_id(); if let ResolvedType::Tuple { underlining, .. } = on_t { - - let values = values.into_iter().zip(underlining).map(|(value,on_t)| self.assign_ids_pattern(value, on_t)).collect(); + let values = values + .into_iter() + .zip(underlining) + .map(|(value, on_t)| self.assign_ids_pattern(value, on_t)) + .collect(); ast::DestructurePattern::Tuple(values, on_t.clone(), id) } else { - let values = values.into_iter().map(|value|{ - let on_t = self.get_next_type_id(); - self.assign_ids_pattern(value, &on_t) - }).collect(); + let values = values + .into_iter() + .map(|value| { + let on_t = self.get_next_type_id(); + self.assign_ids_pattern(value, &on_t) + }) + .collect(); ast::DestructurePattern::Tuple(values, on_t.clone(), id) } - }, + } untyped_ast::PatternDestructure::Unit => ast::DestructurePattern::Unit, }; ast::Pattern::Destructure(inner) - }, + } + untyped_ast::Pattern::EnumVariant { + ty, + variant, + pattern, + loc, + } => { + let variant = if let Some(base) = ty { + format!("{base}::{variant}") + } else { + variant + }; + let ty = self.get_next_type_id(); + let pattern = pattern.map(|pat| self.assign_ids_pattern(*pat, &ty).into()); + ast::Pattern::EnumVariant { + ty, + variant, + pattern, + loc, + } + } untyped_ast::Pattern::Error => ast::Pattern::Err, - untyped_ast::Pattern::Or(lhs, rhs) => { - ast::Pattern::Or( - self.assign_ids_pattern(*lhs, on_t).boxed(), - self.assign_ids_pattern(*rhs, on_t).boxed() - ) - }, + untyped_ast::Pattern::Or(lhs, rhs) => ast::Pattern::Or( + self.assign_ids_pattern(*lhs, on_t).into(), + self.assign_ids_pattern(*rhs, on_t).into(), + ), } } fn assign_ids_call( @@ -398,19 +476,19 @@ impl Context { unreachable!() }; let arg = self.assign_ids_expr(*arg, None); - let arg_t = arg.get_retty(self).boxed(); + let arg_t = arg.get_retty(self).into(); let value = self.assign_ids_expr( *value, Some(ResolvedType::Function { arg: arg_t, - returns: result_t.clone().boxed(), + returns: result_t.clone().into(), loc, }), ); ast::FnCall { loc, - value: value.boxed(), - arg: arg.boxed(), + value: value.into(), + arg: arg.into(), id: self.get_next_expr_id(), returns: result_t, } @@ -454,8 +532,8 @@ impl Context { let rhs = self.assign_ids_expr(*rhs, None); ast::Expr::BinaryOpCall(ast::BinaryOpCall { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, id, result: self.get_next_type_id(), @@ -486,18 +564,26 @@ impl Context { contents: _, loc: _, } => todo!(), - untyped_ast::Expr::TupleLiteral { - contents, - loc, - } => { + untyped_ast::Expr::TupleLiteral { contents, loc } => { let id = self.get_next_expr_id(); - let contents = if let Some(ResolvedType::Tuple{underlining, loc:_}) = expected { - contents.into_iter().zip(underlining).map(|(expr,ty)| self.assign_ids_expr(expr, Some(ty))).collect() + let contents = if let Some(ResolvedType::Tuple { + underlining, + loc: _, + }) = expected + { + contents + .into_iter() + .zip(underlining) + .map(|(expr, ty)| self.assign_ids_expr(expr, Some(ty))) + .collect() } else { - contents.into_iter().map(|expr| self.assign_ids_expr(expr, None)).collect() + contents + .into_iter() + .map(|expr| self.assign_ids_expr(expr, None)) + .collect() }; ast::Expr::TupleLiteral { contents, loc, id } - }, + } untyped_ast::Expr::StructConstruction(_) => todo!(), untyped_ast::Expr::BoolLiteral(value, loc) => { ast::Expr::BoolLiteral(value, loc, self.get_next_expr_id()) @@ -512,22 +598,22 @@ impl Context { else_branch, loc, } = if_; - let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).boxed(); + let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).into(); let (true_block, true_ret) = true_branch; let true_block = true_block .into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect_vec(); - let true_ret = self.assign_ids_expr(*true_ret, None).boxed(); + let true_ret = self.assign_ids_expr(*true_ret, None).into(); let else_ifs = else_ifs .into_iter() .map(|(cond, block, ret)| { - let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).boxed(); + let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).into(); let block = block .into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect_vec(); - let ret = self.assign_ids_expr(*ret, None).boxed(); + let ret = self.assign_ids_expr(*ret, None).into(); (cond, block, ret) }) .collect_vec(); @@ -536,7 +622,7 @@ impl Context { .into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect_vec(); - let else_ret = self.assign_ids_expr(*else_ret, None).boxed(); + let else_ret = self.assign_ids_expr(*else_ret, None).into(); ast::Expr::If(ast::IfExpr { cond, true_branch: (true_block, true_ret), @@ -558,7 +644,7 @@ impl Context { } = module; let items = self.dependency_tree.keys().cloned().collect(); let order = sort_on_tree(items, &self.dependency_tree); - let order = dbg!(order); + decls.sort_by_key(|decl| order.iter().position(|name| name == &decl.get_ident())); for decl in decls { self.known_locals.clear(); @@ -575,7 +661,7 @@ impl Context { let ty = value.ty.remove_args(value.args.len()); Some(ty) }; - let actual = self.get_actual_type(e,ty.clone(),&mut ty); + let actual = self.get_actual_type(e, ty.clone(), &mut ty); if value.ty.is_unknown() { value.ty = value .args @@ -583,10 +669,10 @@ impl Context { .map(|arg| arg.get_ty()) .rev() .fold(actual, |ty, arg| arg.fn_ty(&ty)); - + //not sure if this the correct way to handle this. } - }, + } ast::ValueType::Function(stmnts) => { let mut ty = if value.ty.is_unknown() { None @@ -602,41 +688,53 @@ impl Context { .iter() .map(|arg| arg.get_ty()) .reduce(|ty, arg| ty.fn_ty(&arg)); - value.ty = fun.unwrap().fn_ty(&ty.unwrap_or(types::ERROR)); //not sure if this the correct way to handle this. + value.ty = fun.unwrap().fn_ty(&ty.unwrap_or(types::ERROR)); + //not sure if this the correct way to handle this. } } ast::ValueType::External => (), } self.known_values - .insert(value.ident.clone(), value.ty.clone()); + .insert(value.ident.clone(), value.ty.clone()); } ast::TopLevelDeclaration::Type(_) => (), //don't think there is anything to be done here. } } } - fn infer_arg(&mut self, arg:&ast::ArgDeclaration) { + fn infer_arg(&mut self, arg: &ast::ArgDeclaration) { match arg { - ast::ArgDeclaration::Simple { ident, ty, ..} => { + ast::ArgDeclaration::Simple { ident, ty, .. } => { self.known_locals.insert(ident.clone(), ty.clone()); - }, + } ast::ArgDeclaration::DestructureTuple(contents, _, _) => { for arg in contents { self.infer_arg(arg); } - }, - ast::ArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } => { + } + ast::ArgDeclaration::DestructureStruct { + loc: _, + struct_ident, + fields, + renamed_fields, + } => { for field in fields { - let ty = if let Some(ty) = self.known_struct_fields.get(&(struct_ident.clone(), field.clone())) { + let ty = if let Some(ty) = self + .known_struct_fields + .get(&(struct_ident.clone(), field.clone())) + { ty.clone() } else { types::ERROR }; self.known_locals.insert(field.clone(), ty); } - for (old_name,new_name) in renamed_fields { + for (old_name, new_name) in renamed_fields { if new_name != "_" { - let ty = if let Some(ty) = self.known_struct_fields.get(&(struct_ident.clone(), old_name.clone())) { + let ty = if let Some(ty) = self + .known_struct_fields + .get(&(struct_ident.clone(), old_name.clone())) + { ty.clone() } else { types::ERROR @@ -644,14 +742,13 @@ impl Context { self.known_locals.insert(new_name.clone(), ty); } } - }, + } ast::ArgDeclaration::Discard { loc, ty } => (), - ast::ArgDeclaration::Unit {..}=> (), + ast::ArgDeclaration::Unit { .. } => (), } } fn infer_decl(&mut self, value: &mut ast::ValueDeclaration) { - for arg in &value.args { self.infer_arg(arg); } @@ -706,17 +803,30 @@ impl Context { fun_ret_ty: &mut Option, ) -> ResolvedType { match expr { - ast::Expr::TupleLiteral { contents, loc:_, id:_ } => { - let contents = if let Some(ResolvedType::Tuple { underlining, loc:_}) = expected { - contents.iter_mut().zip(underlining).map(|(expr,ty)| { - self.get_actual_type(expr,Some(ty),fun_ret_ty) - }).collect() + ast::Expr::TupleLiteral { + contents, + loc: _, + id: _, + } => { + let contents = if let Some(ResolvedType::Tuple { + underlining, + loc: _, + }) = expected + { + contents + .iter_mut() + .zip(underlining) + .map(|(expr, ty)| self.get_actual_type(expr, Some(ty), fun_ret_ty)) + .collect() } else { - contents.iter_mut().map(|expr| self.get_actual_type(expr, None, fun_ret_ty)).collect() + contents + .iter_mut() + .map(|expr| self.get_actual_type(expr, None, fun_ret_ty)) + .collect() }; ResolvedType::Tuple { - underlining:contents, - loc:(0,0), + underlining: contents, + loc: (0, 0), } } ast::Expr::Error(_) => ResolvedType::Error, @@ -893,7 +1003,7 @@ impl Context { } let out = types::ResolvedType::Array { - underlining: underlining.boxed(), + underlining: underlining.into(), size: contents.len(), }; // self.known_values.insert(*id, out.clone()); @@ -997,13 +1107,17 @@ impl Context { } = match_; let on_ty = self.get_actual_type(on, None, fun_ret_ty); let mut ety = e_ty.unwrap_or(types::ERROR); - for ast::MatchArm { - block, - ret, - cond, - loc: _, - } in arms.iter_mut() + for ( + idx, + ast::MatchArm { + block, + ret, + cond, + loc: _, + }, + ) in arms.iter_mut().enumerate() { + println!("doing equations of arm {idx}"); self.add_equation_of_pattern(cond, &on_ty); for stmnt in block { self.infer_stmnt(stmnt, fun_ret_ty); @@ -1015,6 +1129,9 @@ impl Context { self.get_actual_type(ret, Some(ety.clone()), fun_ret_ty); } } + if let ast::Pattern::EnumVariant { ty, .. } = cond { + println!("end type {ty:#?}"); + } } if !ety.is_error() { for arm in arms { @@ -1024,42 +1141,100 @@ impl Context { ety } - fn add_equation_of_pattern(&mut self, pattern:&mut ast::Pattern, on_ty:&ResolvedType) { + fn add_equation_of_pattern(&mut self, pattern: &mut ast::Pattern, on_ty: &ResolvedType) { match pattern { ast::Pattern::Read { ident, loc, ty, id } => { + //todo? check if ty is unknown first + println!("setting ty {ty:?} to {on_ty:?}"); *ty = on_ty.clone(); - self.expr_ty.insert(*id,on_ty.clone()); + self.expr_ty.insert(*id, on_ty.clone()); self.known_locals.insert(ident.clone(), on_ty.clone()); - }, - ast::Pattern::ConstNumber(num, ty) => { + } + ast::Pattern::ConstNumber(_num, ty) => { + //TODO? check for non-number types. + println!("setting ty {ty:?} to {on_ty:?}"); *ty = on_ty.clone(); - }, - + } + ast::Pattern::Destructure(d) => { + println!("destructure"); + match d { ast::DestructurePattern::Tuple(contents, ty, id) => { - if let ResolvedType::Tuple { underlining, loc:_ } = on_ty { - self.expr_ty.insert(*id,on_ty.clone()); - *ty = on_ty.clone(); - for (pat,ty) in contents.iter_mut().zip(underlining) { + if let ResolvedType::Tuple { + underlining, + loc: _, + } = on_ty + { + self.expr_ty.insert(*id, on_ty.clone()); + if let ResolvedType::Unknown(idx) = ty { + self.equations.insert(*idx, on_ty.clone()); + } else if ty != on_ty { + // TODO! error reporting + *ty = types::ERROR; + } + for (pat, ty) in contents.iter_mut().zip(underlining) { self.add_equation_of_pattern(pat, ty); } } else { + println!("Error before finding tuple"); *ty = types::ERROR // TODO! error reporting. } - }, - ast::DestructurePattern::Struct { fields } => { + } + ast::DestructurePattern::Struct { base_ty, fields } => { todo!("need to work on destructuring structures"); - }, - ast::DestructurePattern::Unit => () + } + ast::DestructurePattern::Unit => (), } } ast::Pattern::Or(lhs, rhs) => { self.add_equation_of_pattern(lhs.as_mut(), on_ty); self.add_equation_of_pattern(rhs.as_mut(), on_ty); } - _=>(), + ast::Pattern::EnumVariant { + ty: v_ty, + variant, + pattern, + loc, + } => { + + let variant = if let ResolvedType::User { name, .. } = v_ty { + format!("{}::{}", name, variant) + } else { + // TODO! handle dependent types. + // TODO! Fall back to on_ty + variant.clone() + }; + + let sub_ty = self.known_types.get(&variant).cloned(); + if let Some(ResolvedType::Dependent { base, .. }) = &sub_ty { + if let ResolvedType::Unknown(id) = on_ty { + self.equations.insert(*id, base.as_ref().clone()); + } + } + match (pattern, sub_ty) { + (Some(pat), Some(ty @ ResolvedType::Dependent { .. })) => { + + let unwrapped = if let ResolvedType::Dependent { actual, .. } = &ty { + actual + } else { + unreachable!() + }; + self.add_equation_of_pattern(pat, unwrapped.as_ref()); + if let ResolvedType::Unknown(idx) = v_ty { + self.equations.insert(*idx, ty.clone()); + } + } + (None, Some(ref ty @ ResolvedType::Dependent { ref actual, ..})) if matches!(actual.as_ref(), ResolvedType::Void) =>{ + if let ResolvedType::Unknown(idx) = v_ty { + self.equations.insert(*idx, ty.clone()); + } + } + _ => (), //TODO! handle error reporting + } + } + _ => (), } } @@ -1152,7 +1327,12 @@ impl Context { } fn apply_equations(&mut self, module: &mut ast::ModuleDeclaration) { + println!( + "equations {:#?}\nexpr_ty {:#?}", + &self.equations, &self.expr_ty + ); self.apply_substutions(module); + println!("post subs\n{module:#?}"); let ast::ModuleDeclaration { loc: _, name: _, @@ -1174,9 +1354,9 @@ impl Context { match decl { ast::TopLevelDeclaration::Value(v) => { for (id, ty) in &equations { - v.ty.replace_unknown_with(*id,ty.clone()); + v.ty.replace_unknown_with(*id, ty.clone()); for arg in &mut v.args { - arg.replace_unknown_with(*id,ty.clone()); + arg.replace_unknown_with(*id, ty.clone()); } match &mut v.value { ast::ValueType::Expr(expr) => { @@ -1184,7 +1364,9 @@ impl Context { } ast::ValueType::Function(stmnts) => { for stmnt in stmnts { - if let Some(rt) = self.apply_equation_stmnt(stmnt, *id, ty.clone()) { + if let Some(rt) = + self.apply_equation_stmnt(stmnt, *id, ty.clone()) + { if v.ty.is_unknown() || v.ty.is_error() { v.ty = rt; } @@ -1235,8 +1417,8 @@ impl Context { } fn apply_substutions(&mut self, ast: &mut ast::ModuleDeclaration) { - for (id,sub) in self.expr_ty.clone() { - let sub = (&id,&sub); + for (id, sub) in self.expr_ty.clone() { + let sub = (&id, &sub); for decl in &mut ast.decls { match decl { ast::TopLevelDeclaration::Value(v) => { @@ -1252,7 +1434,7 @@ impl Context { } ast::ValueType::External => (), } - }, + } _ => (), } } @@ -1261,14 +1443,19 @@ impl Context { fn apply_substution_arg( &mut self, - sub:(&usize,&ResolvedType), - arg:&mut ast::ArgDeclaration + sub: (&usize, &ResolvedType), + arg: &mut ast::ArgDeclaration, ) -> bool { match arg { - ast::ArgDeclaration::Simple { loc:_, ident, ty, id } if id == sub.0 => { + ast::ArgDeclaration::Simple { + loc: _, + ident, + ty, + id, + } if id == sub.0 => { *ty = sub.1.clone(); true - }, + } ast::ArgDeclaration::DestructureTuple(contents, ty, _) => { let changed = contents.iter_mut().fold(false, |accum, arg| { self.apply_substution_arg(sub, arg) || accum @@ -1276,14 +1463,20 @@ impl Context { if changed { if let ResolvedType::Unknown(ty_id) = ty { self.equations.insert( - *ty_id, - ResolvedType::Tuple { underlining: contents.iter().map(ast::ArgDeclaration::get_ty).collect(), loc: (0,0) } + *ty_id, + ResolvedType::Tuple { + underlining: contents + .iter() + .map(ast::ArgDeclaration::get_ty) + .collect(), + loc: (0, 0), + }, ); } } changed - }, - _=> false, + } + _ => false, } } @@ -1292,7 +1485,12 @@ impl Context { sub: (&usize, &ResolvedType), decl: &mut ast::ValueDeclaration, ) { - let ast::ValueDeclaration { value, args, target, .. } = decl; + let ast::ValueDeclaration { + value, + args, + target, + .. + } = decl; self.apply_substution_pattern(target, sub); for arg in args { self.apply_substution_arg(sub, arg); @@ -1309,7 +1507,11 @@ impl Context { } } - fn apply_substution_statement(&mut self, sub: (&usize, &ResolvedType), stmnt: &mut ast::Statement) { + fn apply_substution_statement( + &mut self, + sub: (&usize, &ResolvedType), + stmnt: &mut ast::Statement, + ) { match stmnt { ast::Statement::Declaration(v) => self.apply_substution_decl(sub, v), ast::Statement::FnCall(call) => self.apply_substution_fncall(sub, call), @@ -1403,8 +1605,11 @@ impl Context { let ast::Match { on, id, arms, .. } = match_; if id != sub.0 { self.apply_substution_expr(sub, on.as_mut()); - for ast::MatchArm { block, ret, cond, .. } in arms { - self.apply_substution_pattern(cond,sub); + for ast::MatchArm { + block, ret, cond, .. + } in arms + { + self.apply_substution_pattern(cond, sub); for stmnt in block { self.apply_substution_statement(sub, stmnt); } @@ -1536,37 +1741,42 @@ impl Context { if let Some(ret) = ret.as_mut() { ret_ty = self.apply_equation_expr(ret, id, ty.clone()); } else if !ret_ty.is_error() { - *ret = Some(ast::Expr::Error(0).boxed()) + *ret = Some(ast::Expr::Error(0).into()) } } ret_ty } - fn apply_equation_pattern(&self, pat:&mut ast::Pattern, id:usize, new_ty:ResolvedType) { + fn apply_equation_pattern(&self, pat: &mut ast::Pattern, id: usize, new_ty: ResolvedType) { match pat { - ast::Pattern::Read { ty, .. } - | ast::Pattern::ConstNumber(_, ty) => ty.replace_unknown_with(id, new_ty), - ast::Pattern::Destructure(d) => { - match d { - ast::DestructurePattern::Struct { fields } => { - for field in fields.values_mut() { - self.apply_equation_pattern(field, id, new_ty.clone()); - } - }, - ast::DestructurePattern::Tuple(patterns, ty, _) => { - ty.replace_unknown_with(id, new_ty.clone()); - for pat in patterns { - self.apply_equation_pattern(pat, id, new_ty.clone()); - } - }, - ast::DestructurePattern::Unit => (), + ast::Pattern::Read { ty, .. } | ast::Pattern::ConstNumber(_, ty) => { + ty.replace_unknown_with(id, new_ty) + } + ast::Pattern::Destructure(d) => match d { + ast::DestructurePattern::Struct { base_ty, fields } => { + for field in fields.values_mut() { + self.apply_equation_pattern(field, id, new_ty.clone()); + } + } + ast::DestructurePattern::Tuple(patterns, ty, _) => { + ty.replace_unknown_with(id, new_ty.clone()); + for pat in patterns { + self.apply_equation_pattern(pat, id, new_ty.clone()); + } } + ast::DestructurePattern::Unit => (), }, ast::Pattern::Or(lhs, rhs) => { self.apply_equation_pattern(lhs.as_mut(), id, new_ty.clone()); self.apply_equation_pattern(rhs.as_mut(), id, new_ty); - }, - _ => () + } + ast::Pattern::EnumVariant { ty, pattern, .. } => { + ty.replace_unknown_with(id, new_ty.clone()); + if let Some(pat) = pattern { + self.apply_equation_pattern(pat.as_mut(), id, new_ty); + } + } + _ => (), } } @@ -1596,18 +1806,28 @@ impl Context { ty: ResolvedType, ) -> ResolvedType { match expr { - ast::Expr::TupleLiteral { contents, loc:_, id:eid }=> { + ast::Expr::TupleLiteral { + contents, + loc: _, + id: eid, + } => { if id == *eid { - let ResolvedType::Tuple { underlining, loc:_ } = &ty else { return types::ERROR; }; + let ResolvedType::Tuple { + underlining, + loc: _, + } = &ty + else { + return types::ERROR; + }; //TODO? do I need to do something here? ty } else { - ResolvedType::Tuple { + ResolvedType::Tuple { underlining: contents .iter_mut() .map(|expr| self.apply_equation_expr(expr, id, ty.clone())) - .collect(), - loc: (0,0) + .collect(), + loc: (0, 0), } } } @@ -1688,7 +1908,7 @@ impl Context { }; ResolvedType::Array { - underlining: underlining.boxed(), + underlining: underlining.into(), size: contents.len(), } } @@ -1758,53 +1978,67 @@ impl Context { ast::Expr::Error(_) => types::ERROR, //nothing to do } } - - fn apply_substution_pattern(&self, cond: &mut ast::Pattern, (eid,new_ty):(&usize,&ResolvedType)) { + + fn apply_substution_pattern( + &self, + cond: &mut ast::Pattern, + (eid, new_ty): (&usize, &ResolvedType), + ) { match cond { - ast::Pattern::Read { id, ty, .. } if id ==eid =>*ty = new_ty.clone(), - ast::Pattern::Destructure(d ) => { - match d { - ast::DestructurePattern::Tuple(patterns, ty, id) => { - for pat in patterns { - self.apply_substution_pattern(pat, (eid,new_ty)); - if id == eid { - *ty = new_ty.clone() - } + ast::Pattern::Read { id, ty, .. } if id == eid => *ty = new_ty.clone(), + ast::Pattern::Destructure(d) => match d { + ast::DestructurePattern::Tuple(patterns, ty, id) => { + for pat in patterns { + self.apply_substution_pattern(pat, (eid, new_ty)); + if id == eid { + *ty = new_ty.clone() } - }, - ast::DestructurePattern::Struct { fields } => { - for field in fields.values_mut() { - self.apply_substution_pattern(field, (eid,new_ty)) - } - }, - ast::DestructurePattern::Unit => () + } } - } - ast::Pattern::Err => (), - ast::Pattern::Or(lhs, rhs) =>{ - self.apply_substution_pattern(lhs.as_mut(), (eid,new_ty)); - self.apply_substution_pattern(rhs.as_mut(), (eid,new_ty)); + ast::DestructurePattern::Struct { base_ty, fields } => { + for field in fields.values_mut() { + self.apply_substution_pattern(field, (eid, new_ty)) + } + } + ast::DestructurePattern::Unit => (), }, + ast::Pattern::Err => (), + ast::Pattern::Or(lhs, rhs) => { + self.apply_substution_pattern(lhs.as_mut(), (eid, new_ty)); + self.apply_substution_pattern(rhs.as_mut(), (eid, new_ty)); + } + ast::Pattern::EnumVariant { + ty, pattern, loc, .. + } => { + if let Some(pat) = pattern { + self.apply_substution_pattern(pat.as_mut(), (eid, new_ty)); + } + } _ => (), } } } -fn sort_on_tree(src : Vec, dependencies : &HashMap>) -> Vec { +fn sort_on_tree(src: Vec, dependencies: &HashMap>) -> Vec { let mut sorted = Vec::with_capacity(src.len()); let mut visited = HashSet::with_capacity(src.len()); for item in src { - visit(item,&mut visited, &mut sorted,dependencies); + visit(item, &mut visited, &mut sorted, dependencies); } sorted } -fn visit(item:String, visited:&mut HashSet, sorted:&mut Vec, dependencies : &HashMap>) { +fn visit( + item: String, + visited: &mut HashSet, + sorted: &mut Vec, + dependencies: &HashMap>, +) { if !visited.contains(&item) { visited.insert(item.clone()); if let Some(deps) = dependencies.get(&item) { for dep in deps { - visit(dep.clone(),visited,sorted,dependencies) + visit(dep.clone(), visited, sorted, dependencies) } } sorted.push(item) @@ -1825,11 +2059,13 @@ impl Context { #[cfg(test)] mod tests { - use std::collections::HashMap; - use crate::{ - inference::ast::TopLevelValue, parser::Parser, types::{self, ResolvedType}, util::ExtraUtilFunctions + inference::ast::TopLevelValue, + parser::Parser, + types::{self, ResolvedType}, }; + use pretty_assertions::assert_eq; + use std::collections::HashMap; #[test] fn phase1() { @@ -1841,7 +2077,7 @@ mod tests { super::untyped_ast::TopLevelValue { loc: (0, 0), is_op: false, - ident:"foo".to_owned(), + ident: "foo".to_owned(), args: vec![super::untyped_ast::ArgDeclaration::Simple { loc: (0, 0), ident: "a".to_string(), @@ -1872,7 +2108,7 @@ mod tests { super::ast::TopLevelValue { loc: (0, 0), is_op: false, - ident:"foo".to_string(), + ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (0, 0), ident: "a".to_string(), @@ -1904,7 +2140,7 @@ mod tests { super::ast::TopLevelValue { loc: (0, 4), is_op: false, - ident:"foo".to_string(), + ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (0, 8), ident: "a".to_string(), @@ -1915,7 +2151,7 @@ mod tests { value: super::ast::ValueType::Expr(super::ast::Expr::If( super::ast::IfExpr { cond: super::ast::Expr::ValueRead("a".to_string(), (0, 15), 3) - .boxed(), + .into(), true_branch: ( Vec::new(), super::ast::Expr::NumericLiteral { @@ -1923,7 +2159,7 @@ mod tests { id: 4, ty: types::NUMBER, } - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( @@ -1933,7 +2169,7 @@ mod tests { id: 5, ty: types::NUMBER, } - .boxed() + .into() ), loc: (0, 12), id: 2, @@ -1968,7 +2204,7 @@ let foo a = match a where super::ast::TopLevelValue { loc: (1, 4), is_op: false, - ident:"foo".to_string(), + ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (1, 8), ident: "a".to_string(), @@ -1979,51 +2215,45 @@ let foo a = match a where value: super::ast::ValueType::Expr(super::ast::Expr::Match( super::ast::Match { loc: (1, 12), - on: super::ast::Expr::ValueRead("a".to_string(), (1, 18), 3) - .boxed(), + on: super::ast::Expr::ValueRead("a".to_string(), (1, 18), 3).into(), arms: vec![ super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::CharLiteral("a".to_string()).boxed() + super::ast::Expr::CharLiteral("a".to_string()).into() + ), + cond: super::ast::Pattern::ConstNumber( + "0".to_string(), + ResolvedType::Unknown(2), ), - cond: - super::ast::Pattern::ConstNumber( - "0".to_string(), - ResolvedType::Unknown(2), - ), loc: (2, 6) }, super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::CharLiteral("b".to_string()).boxed() + super::ast::Expr::CharLiteral("b".to_string()).into() + ), + cond: super::ast::Pattern::ConstNumber( + "1".to_string(), + ResolvedType::Unknown(2), ), - cond: - super::ast::Pattern::ConstNumber( - "1".to_string(), - ResolvedType::Unknown(2), - ), loc: (3, 6) }, super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::CharLiteral("c".to_string()).boxed() + super::ast::Expr::CharLiteral("c".to_string()).into() + ), + cond: super::ast::Pattern::ConstNumber( + "2".to_string(), + ResolvedType::Unknown(2), ), - cond: - super::ast::Pattern::ConstNumber( - "2".to_string(), - ResolvedType::Unknown(2), - ) - - , loc: (4, 6) }, super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::CharLiteral("d".to_string()).boxed() + super::ast::Expr::CharLiteral("d".to_string()).into() ), cond: super::ast::Pattern::Default, loc: (5, 6) @@ -2050,7 +2280,7 @@ let foo a = match a where super::ast::TopLevelValue { loc: (0, 4), is_op: false, - ident:"foo".to_string(), + ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (0, 8), ident: "a".to_string(), @@ -2062,13 +2292,13 @@ let foo a = match a where super::ast::BinaryOpCall { loc: (0, 14), lhs: super::ast::Expr::ValueRead("a".to_string(), (0, 12), 3) - .boxed(), + .into(), rhs: super::ast::Expr::NumericLiteral { value: "3".to_string(), id: 4, ty: types::NUMBER, } - .boxed(), + .into(), operator: "==".to_string(), id: 2, result: types::ResolvedType::Unknown(2), @@ -2107,7 +2337,7 @@ for let foo x y : T -> T -> () = () super::ast::TopLevelValue { loc: (1, 11), is_op: false, - ident:"foo".to_string(), + ident: "foo".to_string(), args: vec![ super::ast::ArgDeclaration::Simple { loc: (1, 15), @@ -2133,17 +2363,17 @@ for let foo x y : T -> T -> () = () name: "T".to_string(), loc: (1, 21) } - .boxed(), + .into(), returns: ResolvedType::Function { arg: ResolvedType::Generic { name: "T".to_string(), loc: (1, 26) } - .boxed(), - returns: types::UNIT.boxed(), + .into(), + returns: types::UNIT.into(), loc: (1, 28) } - .boxed(), + .into(), loc: (1, 23) }, value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), @@ -2217,7 +2447,7 @@ let complex x = super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { loc: (3, 4), is_op: false, - ident:"annotated_arg".to_string(), + ident: "annotated_arg".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (3, 19), ident: "x".to_string(), @@ -2225,12 +2455,12 @@ let complex x = id: 1 },], ty: ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 4 } - .boxed(), + .into(), loc: (0, 0) }, value: super::ast::ValueType::Expr(super::ast::Expr::ArrayLiteral { @@ -2262,7 +2492,7 @@ let complex x = super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { loc: (5, 4), is_op: false, - ident:"complex".to_string(), + ident: "complex".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (5, 12), ident: "x".to_string(), @@ -2270,7 +2500,7 @@ let complex x = id: 8 },], ty: types::INT32.fn_ty(&ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 4 }), value: super::ast::ValueType::Function(vec![ @@ -2281,9 +2511,9 @@ let complex x = (6, 4), 10 ) - .boxed(), + .into(), arg: super::ast::Expr::ValueRead("x".to_string(), (6, 16), 9) - .boxed(), + .into(), id: 11, returns: types::UNIT }), @@ -2297,19 +2527,19 @@ let complex x = (7, 14), 14 ) - .boxed(), + .into(), rhs: super::ast::Expr::NumericLiteral { value: "0".to_string(), id: 15, ty: types::INT32 } - .boxed(), + .into(), operator: "==".to_string(), id: 13, result: types::BOOL } ) - .boxed(), + .into(), true_branch: ( Vec::new(), super::ast::Expr::ArrayLiteral { @@ -2338,7 +2568,7 @@ let complex x = loc: (7, 26), id: 16 } - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( @@ -2350,25 +2580,25 @@ let complex x = (7, 41), 22 ) - .boxed(), + .into(), arg: super::ast::Expr::ValueRead( "x".to_string(), (7, 55), 21 ) - .boxed(), + .into(), id: 23, returns: ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 4 } }) - .boxed() + .into() ), loc: (7, 11), id: 12, result: ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 4 } }), @@ -2417,7 +2647,9 @@ let unit_unit _ : () -> () = () let mut module = ctx.inference(module.ast); - module.decls.sort_by_key(super::ast::TopLevelDeclaration::get_ident); + module + .decls + .sort_by_key(super::ast::TopLevelDeclaration::get_ident); let [int_int, int_unit, unit_int, unit_unit] = &module.decls[..] else { unreachable!() }; @@ -2425,7 +2657,7 @@ let unit_unit _ : () -> () = () &super::ast::TopLevelDeclaration::Value(TopLevelValue { loc: (5, 4), is_op: false, - ident:"int_int".to_string(), + ident: "int_int".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (5, 12), ident: "x".to_string(), @@ -2433,8 +2665,8 @@ let unit_unit _ : () -> () = () id: 4 }], ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (5, 22) }, value: super::ast::ValueType::Expr(super::ast::Expr::ValueRead( @@ -2453,14 +2685,14 @@ let unit_unit _ : () -> () = () &super::ast::TopLevelDeclaration::Value(TopLevelValue { loc: (1, 4), is_op: false, - ident:"int_unit".to_string(), + ident: "int_unit".to_string(), args: vec![super::ast::ArgDeclaration::Discard { loc: (1, 13), ty: types::INT32, }], ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::UNIT.boxed(), + arg: types::INT32.into(), + returns: types::UNIT.into(), loc: (1, 23), }, value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), @@ -2475,14 +2707,14 @@ let unit_unit _ : () -> () = () &super::ast::TopLevelDeclaration::Value(TopLevelValue { loc: (3, 4), is_op: false, - ident:"unit_int".to_string(), + ident: "unit_int".to_string(), args: vec![super::ast::ArgDeclaration::Discard { loc: (3, 13), ty: types::UNIT, }], ty: ResolvedType::Function { - arg: types::UNIT.boxed(), - returns: types::INT16.boxed(), + arg: types::UNIT.into(), + returns: types::INT16.into(), loc: (3, 20) }, value: super::ast::ValueType::Expr(super::ast::Expr::NumericLiteral { @@ -2501,20 +2733,20 @@ let unit_unit _ : () -> () = () &super::ast::TopLevelDeclaration::Value(TopLevelValue { loc: (7, 4), is_op: false, - ident:"unit_unit".to_string(), + ident: "unit_unit".to_string(), args: vec![super::ast::ArgDeclaration::Discard { loc: (7, 14), ty: types::UNIT, }], ty: ResolvedType::Function { - arg: types::UNIT.boxed(), - returns: types::UNIT.boxed(), + arg: types::UNIT.into(), + returns: types::UNIT.into(), loc: (7, 21) }, value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), generics: None, abi: None, - id: 6 + id: 6 }), unit_unit, "unit_unit" @@ -2544,7 +2776,7 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { loc: (1, 4), is_op: false, - ident:"if_expr".to_string(), + ident: "if_expr".to_string(), args: vec![ super::ast::ArgDeclaration::Simple { loc: (1, 12), @@ -2560,20 +2792,20 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 }, ], ty: ResolvedType::Function { - arg: types::BOOL.boxed(), + arg: types::BOOL.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (1, 32) } - .boxed(), + .into(), loc: (1, 23) }, value: super::ast::ValueType::Expr(super::ast::Expr::If(super::ast::IfExpr { - cond: super::ast::Expr::ValueRead("a".to_string(), (1, 46), 4).boxed(), + cond: super::ast::Expr::ValueRead("a".to_string(), (1, 46), 4).into(), true_branch: ( Vec::new(), - super::ast::Expr::ValueRead("b".to_string(), (1, 53), 5).boxed() + super::ast::Expr::ValueRead("b".to_string(), (1, 53), 5).into() ), else_ifs: Vec::new(), else_branch: ( @@ -2583,7 +2815,7 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 id: 6, ty: types::INT32 } - .boxed() + .into() ), loc: (1, 43), id: 3, @@ -2623,7 +2855,7 @@ let returns a : bool -> int32 = &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { loc: (1, 4), is_op: false, - ident:"returns".to_string(), + ident: "returns".to_string(), args: vec![super::ast::ArgDeclaration::Simple { loc: (1, 12), ident: "a".to_string(), @@ -2631,13 +2863,13 @@ let returns a : bool -> int32 = id: 1, },], ty: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (1, 21) }, value: super::ast::ValueType::Function(vec![ super::ast::Statement::IfStatement(super::ast::IfBranching { - cond: super::ast::Expr::ValueRead("a".to_string(), (2, 7), 2).boxed(), + cond: super::ast::Expr::ValueRead("a".to_string(), (2, 7), 2).into(), true_branch: vec![super::ast::Statement::Return( super::ast::Expr::NumericLiteral { value: "0".to_string(), @@ -2698,42 +2930,36 @@ let consume a = fst a; ); let mut ast = ctx.inference(ast); - ast.decls.sort_by_key(super::ast::TopLevelDeclaration::get_ident); + ast.decls + .sort_by_key(super::ast::TopLevelDeclaration::get_ident); let [consume, produce] = &ast.decls[..] else { unreachable!("more than the declared functions?") }; - assert_eq!(&super::ast::TopLevelDeclaration::Value( - super::ast::TopLevelValue { - loc: (3,4), + assert_eq!( + &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { + loc: (3, 4), is_op: false, - ident:"consume".to_string(), - args: vec![ - super::ast::ArgDeclaration::Simple { - loc: (3,12), - ident: "a".to_string(), - ty: ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }, - id: 6 - } - ], - ty: ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }.fn_ty(&types::INT32), - value: super::ast::ValueType::Expr(super::ast::Expr::FnCall(super::ast::FnCall{ - loc: (3,16), - value : super::ast::Expr::ValueRead("fst".to_string(), (3,16), 8).boxed(), - arg:super::ast::Expr::ValueRead("a".to_string(), (3,20), 7).boxed(), - id:9, - returns : types::INT32, + ident: "consume".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (3, 12), + ident: "a".to_string(), + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + }, + id: 6 + }], + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + } + .fn_ty(&types::INT32), + value: super::ast::ValueType::Expr(super::ast::Expr::FnCall(super::ast::FnCall { + loc: (3, 16), + value: super::ast::Expr::ValueRead("fst".to_string(), (3, 16), 8).into(), + arg: super::ast::Expr::ValueRead("a".to_string(), (3, 20), 7).into(), + id: 9, + returns: types::INT32, })), generics: None, abi: None, @@ -2745,30 +2971,30 @@ let consume a = fst a; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc:(1,4), - is_op:false, - ident:"produce".to_string(), - args : vec![ - super::ast::ArgDeclaration::Simple{ - loc:(1,13), - ident : "a".to_string(), - ty:types::INT32, - id:1 - } - ], - ty: types::INT32.fn_ty(&ResolvedType::Tuple { underlining: vec![types::INT32,types::INT32,], loc: (0,0) }), - id:0, - generics:None, - abi:None, - value: super::ast::ValueType::Expr(super::ast::Expr::TupleLiteral{ - contents:vec![ - super::ast::Expr::ValueRead("a".to_string(), (1,25), 3), - super::ast::Expr::ValueRead("a".to_string(), (1,27), 4), + loc: (1, 4), + is_op: false, + ident: "produce".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (1, 13), + ident: "a".to_string(), + ty: types::INT32, + id: 1 + }], + ty: types::INT32.fn_ty(&ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + }), + id: 0, + generics: None, + abi: None, + value: super::ast::ValueType::Expr(super::ast::Expr::TupleLiteral { + contents: vec![ + super::ast::Expr::ValueRead("a".to_string(), (1, 25), 3), + super::ast::Expr::ValueRead("a".to_string(), (1, 27), 4), ], - id:2, - loc:(1,24), + id: 2, + loc: (1, 24), }) - }), produce, "produces" @@ -2776,8 +3002,8 @@ let consume a = fst a; } #[test] - fn array() { - const SRC : &'static str = " + fn array() { + const SRC: &'static str = " let f (a:[int32;5]) = (); let main _ : () -> () = @@ -2787,74 +3013,103 @@ let main _ : () -> () = let ast = crate::Parser::from_source(SRC).module(String::new()).ast; let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut inference_ctx = super::Context::new( - dtree, + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); let mut ast = inference_ctx.inference(ast); ast.decls.sort_by_key(|decl| decl.get_ident()); - let [f,main]=&ast.decls[..] else { unreachable!() }; + let [f, main] = &ast.decls[..] else { + unreachable!() + }; assert_eq!( - &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue{ - loc : (1,4), - is_op:false, - ident:"f".to_string(), - args:vec![ - super::ast::ArgDeclaration::Simple { - loc:(1,7), - ident:"a".to_string(), - ty : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, - id:1, + &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { + loc: (1, 4), + is_op: false, + ident: "f".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (1, 7), + ident: "a".to_string(), + ty: ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 }, - ], - ty:ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT), - value:super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), - generics:None, - abi:None, - id:0 + id: 1, + },], + ty: ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 + } + .fn_ty(&types::UNIT), + value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), + generics: None, + abi: None, + id: 0 }), f, "the function" ); assert_eq!( - &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue{ - loc : (3,4), - is_op:false, - ident:"main".to_string(), - args:vec![ - super::ast::ArgDeclaration::Discard { - loc:(3,9), - ty : types::UNIT, - }, - ], - ty:types::UNIT.fn_ty(&types::UNIT), - value:super::ast::ValueType::Function(vec![ + &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { + loc: (3, 4), + is_op: false, + ident: "main".to_string(), + args: vec![super::ast::ArgDeclaration::Discard { + loc: (3, 9), + ty: types::UNIT, + },], + ty: types::UNIT.fn_ty(&types::UNIT), + value: super::ast::ValueType::Function(vec![ super::ast::Statement::FnCall(super::ast::FnCall { - loc:(4,4), - value:super::ast::Expr::ValueRead("f".to_string(), (4,4), 9).boxed(), - arg:super::ast::Expr::ArrayLiteral { + loc: (4, 4), + value: super::ast::Expr::ValueRead("f".to_string(), (4, 4), 9).into(), + arg: super::ast::Expr::ArrayLiteral { contents: vec![ - super::ast::Expr::NumericLiteral { value: "1".to_string(), id: 4, ty: types::INT32 }, - super::ast::Expr::NumericLiteral { value: "2".to_string(), id: 5, ty: types::INT32 }, - super::ast::Expr::NumericLiteral { value: "3".to_string(), id: 6, ty: types::INT32 }, - super::ast::Expr::NumericLiteral { value: "4".to_string(), id: 7, ty: types::INT32 }, - super::ast::Expr::NumericLiteral { value: "5".to_string(), id: 8, ty: types::INT32 }, - ], - loc: (4,6), - id: 3 - }.boxed(), - id:10, - returns:types::UNIT + super::ast::Expr::NumericLiteral { + value: "1".to_string(), + id: 4, + ty: types::INT32 + }, + super::ast::Expr::NumericLiteral { + value: "2".to_string(), + id: 5, + ty: types::INT32 + }, + super::ast::Expr::NumericLiteral { + value: "3".to_string(), + id: 6, + ty: types::INT32 + }, + super::ast::Expr::NumericLiteral { + value: "4".to_string(), + id: 7, + ty: types::INT32 + }, + super::ast::Expr::NumericLiteral { + value: "5".to_string(), + id: 8, + ty: types::INT32 + }, + ], + loc: (4, 6), + id: 3 + } + .into(), + id: 10, + returns: types::UNIT }), - super::ast::Statement::Return(super::ast::Expr::UnitLiteral, (5,4)) + super::ast::Statement::Return(super::ast::Expr::UnitLiteral, (5, 4)) ]), - generics:None, - abi:None, - id:2 + generics: None, + abi: None, + id: 2 }), main, "main" @@ -2863,7 +3118,7 @@ let main _ : () -> () = #[test] fn patterns() { - const SRC : &'static str = " + const SRC: &'static str = " let ors (a:int32) = match a where | 1 | 2 | 3 -> 0, | a -> a, @@ -2874,138 +3129,182 @@ let tuples (v:(int32,int32)) = match v where "; let ast = crate::Parser::from_source(SRC).module(String::new()).ast; let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut inference_ctx = super::Context::new( - dtree, + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); let mut ast = inference_ctx.inference(ast); ast.decls.sort_by_key(|decl| decl.get_ident()); - let [ors,tuples] = &ast.decls[..] else { unreachable!() }; + let [ors, tuples] = &ast.decls[..] else { + unreachable!() + }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc:(1,4), - is_op:false, - ident:"ors".to_string(), - args: vec![ - super::ast::ArgDeclaration::Simple { loc: (1,9), ident: "a".to_string(), ty: types::INT32, id: 1 } - ], - ty:types::INT32.fn_ty(&types::INT32), - value:super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match{ - loc:(1,20), - on:super::ast::Expr::ValueRead("a".to_string(), (1,26), 3).boxed(), - arms:vec![ - super::ast::MatchArm{ - block:Vec::new(), - ret:Some(super::ast::Expr::NumericLiteral { value: "0".to_string(), id: 4, ty: types::INT32 }.boxed()), - cond:super::ast::Pattern::Or( - super::ast::Pattern::ConstNumber("1".to_string(), types::INT32).boxed(), + loc: (1, 4), + is_op: false, + ident: "ors".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (1, 9), + ident: "a".to_string(), + ty: types::INT32, + id: 1 + }], + ty: types::INT32.fn_ty(&types::INT32), + value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { + loc: (1, 20), + on: super::ast::Expr::ValueRead("a".to_string(), (1, 26), 3).into(), + arms: vec![ + super::ast::MatchArm { + block: Vec::new(), + ret: Some( + super::ast::Expr::NumericLiteral { + value: "0".to_string(), + id: 4, + ty: types::INT32 + } + .into() + ), + cond: super::ast::Pattern::Or( + super::ast::Pattern::ConstNumber("1".to_string(), types::INT32) + .into(), super::ast::Pattern::Or( - super::ast::Pattern::ConstNumber("2".to_string(), types::INT32).boxed(), - super::ast::Pattern::ConstNumber("3".to_string(), types::INT32).boxed(), - ).boxed() + super::ast::Pattern::ConstNumber("2".to_string(), types::INT32) + .into(), + super::ast::Pattern::ConstNumber("3".to_string(), types::INT32) + .into(), + ) + .into() ), - loc:(2,6), + loc: (2, 6), }, super::ast::MatchArm { - block:Vec::new(), - ret:Some(super::ast::Expr::ValueRead("a".to_string(), (3,11), 6).boxed()), - cond:super::ast::Pattern::Read { ident: "a".to_string(), loc: (3,6), ty: types::INT32, id: 5 }, - loc:(3,6), + block: Vec::new(), + ret: Some( + super::ast::Expr::ValueRead("a".to_string(), (3, 11), 6).into() + ), + cond: super::ast::Pattern::Read { + ident: "a".to_string(), + loc: (3, 6), + ty: types::INT32, + id: 5 + }, + loc: (3, 6), } ], - id:2 + id: 2 })), - generics:None, - abi:None, - id:0 + generics: None, + abi: None, + id: 0 }), ors ); assert_eq!( - &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue{ - loc:(4,4), - is_op:false, - ident:"tuples".to_string(), - args:vec![ - super::ast::ArgDeclaration::Simple { - loc: (4,12), - ident: "v".to_string(), - ty: ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }, - id: 8 - } - ], - ty:ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }.fn_ty(&types::INT32), - value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match{ - loc:(4,31), - on:super::ast::Expr::ValueRead("v".to_string(), (4,37), 10).boxed(), - arms:vec![ + &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { + loc: (4, 4), + is_op: false, + ident: "tuples".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (4, 12), + ident: "v".to_string(), + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + }, + id: 8 + }], + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + } + .fn_ty(&types::INT32), + value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { + loc: (4, 31), + on: super::ast::Expr::ValueRead("v".to_string(), (4, 37), 10).into(), + arms: vec![ super::ast::MatchArm { - block:Vec::new(), - ret:Some(super::ast::Expr::ValueRead("a".to_string(), (5,15), 13).boxed()), - cond:super::ast::Pattern::Destructure(super::ast::DestructurePattern::Tuple( - vec![ - super::ast::Pattern::Read { ident: "a".to_string(), loc: (5,7), ty: types::INT32, id: 12 }, - super::ast::Pattern::ConstNumber("0".to_string(),types::INT32), - ], - ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }, - 11 - )), - loc:(5,6) + block: Vec::new(), + ret: Some( + super::ast::Expr::ValueRead("a".to_string(), (5, 15), 13).into() + ), + cond: super::ast::Pattern::Destructure( + super::ast::DestructurePattern::Tuple( + vec![ + super::ast::Pattern::Read { + ident: "a".to_string(), + loc: (5, 7), + ty: types::INT32, + id: 12 + }, + super::ast::Pattern::ConstNumber( + "0".to_string(), + types::INT32 + ), + ], + ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + }, + 11 + ) + ), + loc: (5, 6) }, super::ast::MatchArm { - block:Vec::new(), - ret:Some(super::ast::Expr::ValueRead("b".to_string(), (6,15), 16).boxed()), - cond:super::ast::Pattern::Destructure(super::ast::DestructurePattern::Tuple( - vec![ - super::ast::Pattern::ConstNumber("1".to_string(),types::INT32), - super::ast::Pattern::Read { ident: "b".to_string(), loc: (6,9), ty: types::INT32, id: 15 }, - ], - ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (0,0) - }, - 14 - )), - loc:(6,6) + block: Vec::new(), + ret: Some( + super::ast::Expr::ValueRead("b".to_string(), (6, 15), 16).into() + ), + cond: super::ast::Pattern::Destructure( + super::ast::DestructurePattern::Tuple( + vec![ + super::ast::Pattern::ConstNumber( + "1".to_string(), + types::INT32 + ), + super::ast::Pattern::Read { + ident: "b".to_string(), + loc: (6, 9), + ty: types::INT32, + id: 15 + }, + ], + ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + }, + 14 + ) + ), + loc: (6, 6) }, super::ast::MatchArm { - block:Vec::new(), - ret:Some(super::ast::Expr::NumericLiteral { value: "0".to_string(), id: 17, ty: types::INT32 }.boxed()), - cond:super::ast::Pattern::Default, - loc:(7,6) + block: Vec::new(), + ret: Some( + super::ast::Expr::NumericLiteral { + value: "0".to_string(), + id: 17, + ty: types::INT32 + } + .into() + ), + cond: super::ast::Pattern::Default, + loc: (7, 6) } ], - id:9, + id: 9, })), - generics:None, - abi:None, - id:7 + generics: None, + abi: None, + id: 7 }), tuples, "tuples" @@ -3013,113 +3312,643 @@ let tuples (v:(int32,int32)) = match v where } #[test] fn destructureing_statement() { - let ast = Parser::from_source(" + let ast = Parser::from_source( + " let a (v:(int32,int32)) = let (x,y) = v; return (); -").module("".to_string()).ast; +", + ) + .module("".to_string()) + .ast; let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut inference_ctx = crate::inference::Context::new( - dtree, + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); let ast = inference_ctx.inference(ast); - let [a]=&ast.decls[..] else { unreachable!() }; + let [a] = &ast.decls[..] else { unreachable!() }; use super::ast; assert_eq!( &ast::TopLevelDeclaration::Value(ast::TopLevelValue { - loc:(1,4), - is_op:false, - ident:"a".to_string(), - args:vec![ast::ArgDeclaration::Simple{ - ident:"v".to_string(), - ty:ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + loc: (1, 4), + is_op: false, + ident: "a".to_string(), + args: vec![ast::ArgDeclaration::Simple { + ident: "v".to_string(), + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, - loc:(1,7), - id:1, + loc: (1, 7), + id: 1, }], ty: ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) - }.fn_ty(&types::UNIT), + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + } + .fn_ty(&types::UNIT), value: ast::ValueType::Function(vec![ ast::Statement::Declaration(ast::ValueDeclaration { - loc:(2,8), - is_op:false, - target:ast::Pattern::Destructure(ast::DestructurePattern::Tuple( + loc: (2, 8), + is_op: false, + target: ast::Pattern::Destructure(ast::DestructurePattern::Tuple( vec![ - ast::Pattern::Read{ ident:"x".to_string(), ty:types::INT32, loc:(2,9), id:3}, - ast::Pattern::Read{ ident:"y".to_string(), ty:types::INT32, loc:(2,11), id:4 }, + ast::Pattern::Read { + ident: "x".to_string(), + ty: types::INT32, + loc: (2, 9), + id: 3 + }, + ast::Pattern::Read { + ident: "y".to_string(), + ty: types::INT32, + loc: (2, 11), + id: 4 + }, ], ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, 2 )), - args:Vec::new(), - value:ast::ValueType::Expr( - ast::Expr::ValueRead("v".to_string(), - (2,16), + args: Vec::new(), + value: ast::ValueType::Expr(ast::Expr::ValueRead( + "v".to_string(), + (2, 16), 6 )), - ty:ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, - generics:None, - abi:None, - id:5 + generics: None, + abi: None, + id: 5 }), - ast::Statement::Return(ast::Expr::UnitLiteral,(3,4)) - ]), - generics: None, + ast::Statement::Return(ast::Expr::UnitLiteral, (3, 4)) + ]), + generics: None, abi: None, - id:0 + id: 0 }), a ); } + #[test] + fn enum_patterns() { + let parser = Parser::from_source( + " +enum IP = | V4 (int8,int8,int8,int8) | V6 (int8,int8,int8,int8,int8,int8) + +let do_something a = match a where +| IP::V4 (127,0,0,1) -> (), +| IP::V4 a -> (), +| IP::V6 _ -> (), +", + ); + let ast = parser.module("".to_string()); + assert_eq!(ast.errors.len(), 0, "no errors"); + + let mut ctx = super::Context::new( + [].into(), + HashMap::new(), + [].into(), + [].into(), + [].into(), + ); + let ast = ctx.inference(ast.ast); + let [_enum_, func] = &ast.decls[..] else { + panic!("too much? too little?") + }; + assert_eq!( + func, + &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { + loc: (3, 4), + is_op: false, + ident: "do_something".to_string(), + args: vec![super::ast::ArgDeclaration::Simple { + loc: (3, 17), + ident: "a".to_string(), + ty: ResolvedType::User { + name: "IP".to_string(), + generics: Vec::new(), + loc: (0, 0), + }, + id: 1 + },], + ty: ResolvedType::User { + name: "IP".to_string(), + generics: Vec::new(), + loc: (0, 0), + } + .fn_ty(&types::UNIT), + value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { + loc: (3, 21), + on: super::ast::Expr::ValueRead("a".to_string(), (3, 27), 3).into(), + arms: vec![ + super::ast::MatchArm { + block: Vec::new(), + ret: Some(super::ast::Expr::UnitLiteral.into()), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "IP".into(), + generics: Vec::new(), + loc: (0, 0) + } + .into(), + ident: "IP::V4".into(), + generics: Vec::new(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8;4 + ], + loc: (0, 0) + } + .into(), + loc: (0, 0) + }, + variant: "IP::V4".to_string(), + // (127, 0, 0, 1) + pattern: Some( + super::ast::Pattern::Destructure( + super::ast::DestructurePattern::Tuple( + vec![ + super::ast::Pattern::ConstNumber( + "127".to_string(), + types::INT8 + ), + super::ast::Pattern::ConstNumber( + "0".to_string(), + types::INT8 + ), + super::ast::Pattern::ConstNumber( + "0".to_string(), + types::INT8 + ), + super::ast::Pattern::ConstNumber( + "1".to_string(), + types::INT8 + ), + ], ResolvedType::Tuple { + underlining: vec![ + types::INT8;4 + ], + loc: (0, 0) + }, + 4 + ) + ) + .into() + ), + loc: (4, 2) + }, + loc: (4, 2) + }, + super::ast::MatchArm { + block: Vec::new(), + ret: Some(super::ast::Expr::UnitLiteral.into()), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "IP".into(), + generics: Vec::new(), + loc: (0, 0) + } + .into(), + ident: "IP::V4".into(), + generics: Vec::new(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8, + types::INT8, + types::INT8, + types::INT8, + ], + loc: (0, 0) + } + .into(), + loc: (0, 0) + }, + variant: "IP::V4".into(), + pattern: Some( + super::ast::Pattern::Read { + ident: "a".into(), + loc: (5, 9), + ty: ResolvedType::Tuple { + underlining: vec![ + types::INT8;4 + ], + loc: (0, 0) + }, + id: 5 + } + .into() + ), + loc: (5, 2) + }, + loc: (5, 2), + }, + super::ast::MatchArm { + block: Vec::new(), + ret: Some(super::ast::Expr::UnitLiteral.into()), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "IP".into(), + generics: Vec::new(), + loc: (0, 0) + } + .into(), + ident: "IP::V6".into(), + generics: Vec::new(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8, + types::INT8, + types::INT8, + types::INT8, + types::INT8, + types::INT8, + ], + loc: (0, 0) + } + .into(), + loc: (0, 0) + }, + variant: "IP::V6".into(), + pattern: Some(super::ast::Pattern::Default.into()), + loc: (6, 2) + }, + loc: (6, 2) + } + ], + id: 2 + })), + generics: None, + abi: None, + id: 0, + }), + ); + + } + #[test] #[ignore = "for debugging only"] fn debug() { - let parser = Parser::from_source(" -let b value : (int32,(int32,int32)) -> int32 = match value where - | (0, (0,b) | (b,0) ) | (b,_) -> b, - | _ -> 0, -"); - let ast = parser.module("".to_string()).ast; + + const SRC: &'static str = r#" +enum Testing = | One (int8,int8) | Two; +let fun test = match test where +| Testing::One (0,1) -> 0, +| Testing::One (1|0,a) -> a, +| Testing::One _ -> 1, +| Testing::Two -> 2, +"#; + let mut ast = Parser::from_source(SRC).module("".to_string()).ast; + ast.canonialize(vec!["v".into()]); let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); - let mut inference_ctx = super::Context::new( - dtree, + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); + let mut inference_ctx = crate::inference::Context::new( + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); - let mut ast = inference_ctx.inference(ast); - ast.decls.sort_by_key(|decl| decl.get_ident()); - let [a] = &ast.decls[..] else { unreachable!() }; - println!("{a:#?}"); + let ast = inference_ctx.inference(ast); + let [_ty, fun] = &ast.decls[..] else { + unreachable!() + }; + let expected = super::ast::TopLevelDeclaration::Value( + super::ast::TopLevelValue { + loc: ( + 2, + 4, + ), + is_op: false, + ident: "fun".into(), + args: vec![ + super::ast::ArgDeclaration::Simple { + loc: ( + 2, + 8, + ), + ident: "test".into(), + ty: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }, + id: 1, + }, + ], + ty: ResolvedType::Function { + arg: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }.into(), + returns: types::INT8.into(), + loc: ( + 0, + 0, + ), + }, + value: super::ast::ValueType::Expr( + super::ast::Expr::Match( + super::ast::Match { + loc: ( + 2, + 15, + ), + on: super::ast::Expr::ValueRead( + "test".into(), + ( + 2, + 21, + ), + 3, + ).into(), + arms: vec![ + super::ast::MatchArm { + block: Vec::new(), + ret: Some( + super::ast::Expr::NumericLiteral { + value: "0".into(), + id: 5, + ty: types::INT8, + }.into(), + ), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }.into(), + ident: "Testing::One".into(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8;2 + ], + loc: ( + 1, + 21, + ), + }.into(), + generics: Vec::new(), + loc: ( + 1, + 17, + ), + }, + variant: "Testing::One".into(), + pattern: Some( + super::ast::Pattern::Destructure( + super::ast::DestructurePattern::Tuple( + vec![ + super::ast::Pattern::ConstNumber( + "0".into(), + types::INT8, + ), + super::ast::Pattern::ConstNumber( + "1".into(), + types::INT8, + ), + ], + ResolvedType::Tuple { + underlining: vec![ + types::INT8;2 + ], + loc: ( + 1, + 21, + ), + }, + 4, + ), + ).into(), + ), + loc: ( + 3, + 2, + ), + }, + loc: ( + 3, + 2, + ), + }, + super::ast::MatchArm { + block: Vec::new(), + ret: Some( + super::ast::Expr::ValueRead( + "a".into(), + ( + 4, + 26, + ), + 8, + ).into(), + ), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }.into(), + ident: "Testing::One".into(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8;2 + ], + loc: ( + 1, + 21, + ), + }.into(), + generics: Vec::new(), + loc: ( + 1, + 17, + ), + }, + variant: "Testing::One".into(), + pattern: Some( + super::ast::Pattern::Destructure( + super::ast::DestructurePattern::Tuple( + vec![ + super::ast::Pattern::Or( + super::ast::Pattern::ConstNumber( + "1".into(), + types::INT8, + ).into(), + super::ast::Pattern::ConstNumber( + "0".into(), + types::INT8, + ).into(), + ), + super::ast::Pattern::Read { + ident: "a".into(), + loc: ( + 4, + 20, + ), + ty: types::INT8, + id: 7, + }, + ], + ResolvedType::Tuple { + underlining: vec![ + types::INT8;2 + ], + loc: ( + 1, + 21, + ), + }, + 6, + ), + ).into(), + ), + loc: ( + 4, + 2, + ), + }, + loc: ( + 4, + 2, + ), + }, + super::ast::MatchArm { + block: Vec::new(), + ret: Some( + super::ast::Expr::NumericLiteral { + value: "1".into(), + id: 9, + ty: types::INT8, + }.into(), + ), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }.into(), + ident: "Testing::One".into(), + actual: ResolvedType::Tuple { + underlining: vec![ + types::INT8;2 + ], + loc: ( + 1, + 21, + ), + }.into(), + generics: Vec::new(), + loc: ( + 1, + 17, + ), + }, + variant: "Testing::One".into(), + pattern: Some( + super::ast::Pattern::Default.into(), + ), + loc: ( + 5, + 2, + ), + }, + loc: ( + 5, + 2, + ), + }, + super::ast::MatchArm { + block: Vec::new(), + ret: Some( + super::ast::Expr::NumericLiteral { + value: "2".into(), + id: 10, + ty: types::INT8, + }.into(), + ), + cond: super::ast::Pattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Testing".into(), + generics: Vec::new(), + loc: ( + 1, + 5, + ), + }.into(), + ident: "Testing::Two".into(), + actual: ResolvedType::Void.into(), + generics: Vec::new(), + loc: ( + 1, + 35, + ), + }, + variant: "Testing::Two".into(), + pattern: None, + loc: ( + 6, + 2, + ), + }, + loc: ( + 6, + 2, + ), + }, + ], + id: 2, + }, + ), + ), + generics: None, + abi: None, + id: 0, + }, + ); + assert_eq!( + fun, + &expected + ); } } diff --git a/compiler/src/inference/ast.rs b/compiler/src/inference/ast.rs index 7df2248..ae918ab 100644 --- a/compiler/src/inference/ast.rs +++ b/compiler/src/inference/ast.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use crate::{ // ast::{EnumDeclation, StructDefinition}, types::{self, ResolvedType}, - util::ExtraUtilFunctions, }; pub use crate::ast::GenericsDecl; @@ -25,9 +24,7 @@ impl TopLevelDeclaration { pub(crate) fn get_ident(&self) -> String { match self { Self::Type(ty) => ty.get_ident(), - Self::Value(v)=> { - v.ident.clone() - }, + Self::Value(v) => v.ident.clone(), } } @@ -41,15 +38,15 @@ impl TopLevelDeclaration { #[derive(PartialEq, Debug)] pub(crate) struct TopLevelValue { - pub(crate) loc : crate::Location, + pub(crate) loc: crate::Location, pub(crate) is_op: bool, - pub(crate) ident : String, - pub(crate) args : Vec, - pub(crate) ty:ResolvedType, - pub(crate) value : ValueType, - pub(crate) generics : Option, - pub(crate) abi : Option, - pub(crate) id : usize + pub(crate) ident: String, + pub(crate) args: Vec, + pub(crate) ty: ResolvedType, + pub(crate) value: ValueType, + pub(crate) generics: Option, + pub(crate) abi: Option, + pub(crate) id: usize, } #[derive(PartialEq, Debug)] @@ -68,50 +65,60 @@ pub(crate) struct ValueDeclaration { #[derive(PartialEq, Debug, Clone)] pub(crate) enum ArgDeclaration { Simple { - loc : crate::Location, + loc: crate::Location, ident: String, - ty:ResolvedType, - id : usize, + ty: ResolvedType, + id: usize, }, - DestructureTuple(Vec,ResolvedType, crate::Location), + DestructureTuple(Vec, ResolvedType, crate::Location), DestructureStruct { - loc:crate::Location, - struct_ident : String, - fields : Vec, - renamed_fields : HashMap + loc: crate::Location, + struct_ident: String, + fields: Vec, + renamed_fields: HashMap, }, Discard { - loc:crate::Location, - ty:ResolvedType, + loc: crate::Location, + ty: ResolvedType, + }, + Unit { + loc: crate::Location, + ty: ResolvedType, }, - Unit { loc:crate::Location, ty:ResolvedType }, } impl ArgDeclaration { pub(crate) fn get_ty(&self) -> ResolvedType { match self { - Self::Unit { .. }=> types::UNIT, - Self::DestructureStruct { struct_ident, .. } => ResolvedType::User { name: struct_ident.clone(), generics: Vec::new(), loc: (0,0) }, + Self::Unit { .. } => types::UNIT, + Self::DestructureStruct { struct_ident, .. } => ResolvedType::User { + name: struct_ident.clone(), + generics: Vec::new(), + loc: (0, 0), + }, Self::Simple { ty, .. } | Self::Discard { ty, .. } - | Self::DestructureTuple(_, ty,_) => ty.clone() + | Self::DestructureTuple(_, ty, _) => ty.clone(), } } - + pub(crate) fn replace_unknown_with(&mut self, id: usize, new_ty: ResolvedType) { match self { - Self::Unit { .. }| Self::DestructureStruct { .. } => (), - Self::Simple { ty, .. } - | Self::Discard { ty, .. } => ty.replace_unknown_with(id, new_ty), + Self::Unit { .. } | Self::DestructureStruct { .. } => (), + Self::Simple { ty, .. } | Self::Discard { ty, .. } => { + println!("chaging {id} to {new_ty:#?}"); + ty.replace_unknown_with(id, new_ty) + } Self::DestructureTuple(contents, ty, _) => { - contents.iter_mut().for_each(|it| it.replace_unknown_with(id, new_ty.clone())); + contents + .iter_mut() + .for_each(|it| it.replace_unknown_with(id, new_ty.clone())); ty.replace_unknown_with(id, new_ty); } } } } - #[derive(PartialEq, Debug)] pub(crate) enum ValueType { Expr(Expr), @@ -157,29 +164,35 @@ pub(crate) struct MatchArm { #[derive(PartialEq, Debug)] pub(crate) enum Pattern { Default, - ConstNumber(String,ResolvedType), + ConstNumber(String, ResolvedType), ConstStr(String), ConstChar(String), - ConstBool(bool),//again why? - Read{ - ident:String, - loc:crate::Location, - ty:ResolvedType, - id:usize, + ConstBool(bool), //again why? + Read { + ident: String, + loc: crate::Location, + ty: ResolvedType, + id: usize, }, Destructure(DestructurePattern), Err, - Or(Box,Box) + EnumVariant { + ty: ResolvedType, + variant: String, + pattern: Option>, + loc: crate::Location, + }, + Or(Box, Box), } impl Pattern { - pub(crate) fn get_idents_with_types(&self) -> HashMap { + pub(crate) fn get_idents_with_types(&self) -> HashMap { match self { - Self::Read { ident, ty, .. } => [(ident.clone(),ty.clone())].into(), + Self::Read { ident, ty, .. } => [(ident.clone(), ty.clone())].into(), Self::Destructure(d) => d.get_idents_with_types(), Self::Or(lhs, rhs) => { let mut lhs = lhs.get_idents_with_types(); let rhs = rhs.get_idents_with_types(); - if lhs!=rhs { + if lhs != rhs { lhs.insert("".to_string(), types::ERROR); } lhs @@ -189,13 +202,13 @@ impl Pattern { } } - #[derive(PartialEq, Debug)] pub(crate) enum DestructurePattern { Struct { - fields:HashMap, + base_ty: ResolvedType, + fields: HashMap, }, - Tuple(Vec,ResolvedType,usize), // (patterns, ty, id) + Tuple(Vec, ResolvedType, usize), // (patterns, ty, id) Unit, } impl DestructurePattern { @@ -203,7 +216,10 @@ impl DestructurePattern { match self { Self::Struct { .. } => todo!(), //TODO? checking for conflicting names? - Self::Tuple(patterns, _, _) => patterns.iter().flat_map(Pattern::get_idents_with_types).collect(), + Self::Tuple(patterns, _, _) => patterns + .iter() + .flat_map(Pattern::get_idents_with_types) + .collect(), Self::Unit => HashMap::new(), } } @@ -239,8 +255,8 @@ pub(crate) enum Expr { }, TupleLiteral { contents: Vec, - loc:crate::Location, - id:usize + loc: crate::Location, + id: usize, }, #[allow(unused)] ListLiteral { @@ -273,14 +289,18 @@ impl Expr { } pub(crate) fn get_retty(&self, ctx: &mut crate::inference::Context) -> ResolvedType { match self { - Expr::TupleLiteral { contents, loc, id } => { + Expr::TupleLiteral { + contents, + loc: _, + id: _, + } => { if contents.is_empty() { // in theory shouldn't need this but gonna be safe. types::UNIT } else { ResolvedType::Tuple { - underlining:contents.iter().map(|expr|expr.get_retty(ctx)).collect(), - loc:(0,0) + underlining: contents.iter().map(|expr| expr.get_retty(ctx)).collect(), + loc: (0, 0), } } } @@ -298,12 +318,12 @@ impl Expr { Expr::ArrayLiteral { contents, .. } => { if contents.is_empty() { ResolvedType::Array { - underlining: ctx.get_next_type_id().boxed(), + underlining: ctx.get_next_type_id().into(), size: 0, } } else { ResolvedType::Array { - underlining: contents.first().unwrap().get_retty(ctx).boxed(), + underlining: contents.first().unwrap().get_retty(ctx).into(), size: contents.len(), } } diff --git a/compiler/src/lexer.rs b/compiler/src/lexer.rs index 0bccb46..5f40ec9 100644 --- a/compiler/src/lexer.rs +++ b/compiler/src/lexer.rs @@ -11,7 +11,7 @@ struct Lexer { macro_rules! operators { () => { - '|' | '>' | '<' | '!' | '@' | '$' | '=' | '&' | '+' | '-' | '\\' | '/' | '*' | '^' | '.' + '|' | '>' | '<' | '!' | '@' | '=' | '&' | '+' | '-' | '\\' | '/' | '*' | '^' | '.' }; } @@ -387,6 +387,11 @@ impl + Clone> Lexer> { self.curr_col += 3; (Token::Enum, (self.curr_line, start_col)) } + ':' if self.source_stream.clone().next() == Some(':') => { + let _ = self.source_stream.next(); + self.curr_col += 1; + (Token::Scope, (self.curr_line, start_col)) + } ':' => (Token::Colon, (self.curr_line, start_col)), c => { let inner: String = self @@ -411,10 +416,7 @@ impl + Clone> Lexer> { } } } else { - ( - Token::EoF, - (self.curr_line, self.curr_col), - ) + (Token::EoF, (self.curr_line, self.curr_col)) } } } @@ -470,6 +472,7 @@ mod tests { use super::TokenStream; use itertools::Itertools; + use pretty_assertions::assert_eq; #[test] #[ignore = "for debugging only"] @@ -710,8 +713,13 @@ let match_expr_with_block x : int32 -> int32 = match x where assert_eq!( TokenStream::from_source("extern").map(fst).collect_vec(), [Token::Extern, Token::EoF], - "" - ) + "extern" + ); + assert_eq!( + TokenStream::from_source("::").map(fst).collect_vec(), + [Token::Scope, Token::EoF], + ":: (scope)" + ); } #[test] @@ -937,8 +945,8 @@ match x where [ Match,Ident("x".to_string()),Where, - Op("|".to_string()),Ident("Foo".to_string()),Colon,Colon,Ident("Y".to_string()),Ident("bar".to_string()),Arrow,GroupOpen,GroupClose, - Op("|".to_string()),Ident("Foo".to_string()),Colon,Colon,Ident("Z".to_string()),CurlOpen,Ident("a".to_string()),Comma,Ident("b".to_string()),CurlClose,Arrow,GroupOpen,GroupClose, + Op("|".to_string()),Ident("Foo".to_string()),Scope,Ident("Y".to_string()),Ident("bar".to_string()),Arrow,GroupOpen,GroupClose, + Op("|".to_string()),Ident("Foo".to_string()),Scope,Ident("Z".to_string()),CurlOpen,Ident("a".to_string()),Comma,Ident("b".to_string()),CurlClose,Arrow,GroupOpen,GroupClose, EoF ], "Match" diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index b6bfaea..bbbb953 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -1,5 +1,5 @@ -use std::{cmp::Ordering, collections::HashMap}; use std::path::PathBuf; +use std::{cmp::Ordering, collections::HashMap}; pub mod ast; // mod langstd; @@ -12,10 +12,12 @@ pub mod types; mod util; use itertools::Itertools; -use regex::CaptureNames; use thiserror::Error; -use typed_ast::{TypedDeclaration, TypedExpr, TypedFnCall, TypedModuleDeclaration, TypedTopLevelValue, TypedValueType}; +use typed_ast::{ + TypedDeclaration, TypedExpr, TypedFnCall, TypedModuleDeclaration, TypedTopLevelValue, + TypedValueType, +}; #[derive(Error, Debug)] #[error(transparent)] @@ -91,62 +93,92 @@ pub fn get_ast(input: &str, file_name: &str) -> typed_ast::TypedModuleDeclaratio let ast = infer_context.inference(module); TypedModuleDeclaration::from(ast, &HashMap::new(), &ops) } -fn unfold_global_curries(mut ast:TypedModuleDeclaration, external_globals : HashMap, dtree : HashMap>) -> TypedModuleDeclaration { +fn unfold_global_curries( + mut ast: TypedModuleDeclaration, + external_globals: HashMap, + dtree: HashMap>, +) -> TypedModuleDeclaration { let decls = &mut ast.declarations; - let order = dtree.into_iter().sorted_by(|(lhs_name,lhs_depends), (rhs_name,rhs_depends)| { - match (lhs_depends.contains(rhs_name), rhs_depends.contains(lhs_name)) { - (true,true) => { - todo!("remove this case. both lhs and rhs. means they depend on each other.") + let order = dtree + .into_iter() + .sorted_by(|(lhs_name, lhs_depends), (rhs_name, rhs_depends)| { + match ( + lhs_depends.contains(rhs_name), + rhs_depends.contains(lhs_name), + ) { + (true, true) => { + todo!("remove this case. both lhs and rhs. means they depend on each other.") + } + (false, true) => Ordering::Less, //right depends on left thus should appear after. + (true, false) => Ordering::Greater, //left depends on right thus should appear after. + (false, false) => Ordering::Equal, //neither depend on each other. } - (false, true) => Ordering::Less,//right depends on left thus should appear after. - (true, false) => Ordering::Greater,//left depends on right thus should appear after. - (false,false) => Ordering::Equal,//neither depend on each other. - } - }) - .map(|(a,_)|a) - .collect_vec(); + }) + .map(|(a, _)| a) + .collect_vec(); let mut values = external_globals; - values.extend(decls.iter().filter(|decl|if let TypedDeclaration::Value(TypedTopLevelValue{args, ..}) = decl { - args.is_empty() - } else { - false - }).map(|decl| { - let TypedDeclaration::Value(decl) = decl else { unreachable!() }; - let TypedValueType::Expr(expr) = &decl.value else { unreachable!() }; - (decl.ident.clone(), expr.clone()) - })); - for decl in decls.iter_mut() - .filter(|decl| - if let TypedDeclaration::Value(TypedTopLevelValue{args, ..}) =decl { - args.is_empty() + values.extend( + decls + .iter() + .filter(|decl| { + if let TypedDeclaration::Value(TypedTopLevelValue { args, .. }) = decl { + args.is_empty() + } else { + false + } + }) + .map(|decl| { + let TypedDeclaration::Value(decl) = decl else { + unreachable!() + }; + let TypedValueType::Expr(expr) = &decl.value else { + unreachable!() + }; + (decl.ident.clone(), expr.clone()) + }), + ); + for decl in decls + .iter_mut() + .filter(|decl| { + if let TypedDeclaration::Value(TypedTopLevelValue { args, .. }) = decl { + args.is_empty() } else { false } - ) - .sorted_by_cached_key(|decl| order.iter().position(|name| name == &decl.get_ident())) { - let TypedDeclaration::Value(decl) = decl else {unreachable!() }; - let TypedValueType::Expr(expr) = &mut decl.value else { unreachable!() }; + }) + .sorted_by_cached_key(|decl| order.iter().position(|name| name == &decl.get_ident())) + { + let TypedDeclaration::Value(decl) = decl else { + unreachable!() + }; + let TypedValueType::Expr(expr) = &mut decl.value else { + unreachable!() + }; replace_values(expr, &values); values.insert(decl.ident.clone(), expr.clone()); } ast } -fn replace_values(expr:&mut TypedExpr, values : &HashMap) { +fn replace_values(expr: &mut TypedExpr, values: &HashMap) { match expr { TypedExpr::FnCall(call) if call.is_extern => { - call.arg.as_mut().map(|arg| replace_values(arg.as_mut(), values)); - }, + call.arg + .as_mut() + .map(|arg| replace_values(arg.as_mut(), values)); + } TypedExpr::FnCall(call) => { replace_values(call.value.as_mut(), values); - call.arg.as_mut().map(|expr| replace_values(expr.as_mut(), values)); - }, + call.arg + .as_mut() + .map(|expr| replace_values(expr.as_mut(), values)); + } TypedExpr::ValueRead(name, _, _) => { if let Some(new_expr) = values.get(name) { *expr = new_expr.clone(); } } - TypedExpr::TupleLiteral { contents,.. } + TypedExpr::TupleLiteral { contents, .. } | TypedExpr::ListLiteral { contents } | TypedExpr::ArrayLiteral { contents, .. } => { for expr in contents { @@ -157,14 +189,14 @@ fn replace_values(expr:&mut TypedExpr, values : &HashMap) { replace_values(&mut biop.lhs, values); replace_values(&mut biop.rhs, values); } - _ => () + _ => (), } } pub fn from_file<'ctx>( file: &PathBuf, fwd_declarations: HashMap, - fwd_ops : HashMap>, + fwd_ops: HashMap>, project_name: String, ) -> (Result>, Vec) { // TODO: I would like to make this work for now I will read the whole file to a string then @@ -204,13 +236,16 @@ pub fn from_file<'ctx>( let errors = errors.into_iter().map(Error::from).collect_vec(); ast.canonialize(vec![project_name]); let dependency_graph = ast.get_dependencies(); - let dependency_tree : HashMap<_,_> = dependency_graph + let dependency_tree: HashMap<_, _> = dependency_graph .into_iter() .map(|(key, value)| (key, value.into_iter().collect())) .collect(); + let mut known_types = fwd_declarations.clone(); + + known_types.extend(ast.get_types()); let mut inference_context = inference::Context::new( - dbg!(dependency_tree.clone()), - fwd_declarations.clone(), + dependency_tree.clone(), + known_types, HashMap::new(), fwd_ops.clone(), HashMap::new(), @@ -218,7 +253,7 @@ pub fn from_file<'ctx>( let ast = inference_context.inference(ast); let mut ast = TypedModuleDeclaration::from(ast, &fwd_declarations, &fwd_ops); //TODO: foward declare std lib ast.lower_generics(&HashMap::new()); - let ast = unfold_global_curries(ast,HashMap::new(),dependency_tree); + let ast = unfold_global_curries(ast, HashMap::new(), dependency_tree); ( if errors.is_empty() { Ok(ast) diff --git a/compiler/src/parser.rs b/compiler/src/parser.rs index ffc360d..584214e 100644 --- a/compiler/src/parser.rs +++ b/compiler/src/parser.rs @@ -1,18 +1,22 @@ use std::{ - collections::{HashMap, HashSet}, fmt::Error, iter::Peekable, str::Chars + collections::{HashMap, HashSet}, + fmt::Error, + iter::Peekable, + str::Chars, }; -use ast::TypeDefinition; +use ast::{GenericsDecl, TypeDefinition}; use itertools::Itertools; use crate::{ ast::{ - self, ArgDeclaration, BinaryOpCall, Expr, FieldDecl, FnCall, Match, Pattern, PatternDestructure, Statement, StructConstruction, StructDefinition, TopLevelDeclaration, TopLevelValue, ValueDeclaration, ValueType + self, ArgDeclaration, BinaryOpCall, Expr, FieldDecl, FnCall, Match, Pattern, + PatternDestructure, Statement, StructConstruction, StructDefinition, TopLevelDeclaration, + TopLevelValue, ValueDeclaration, ValueType, }, lexer::TokenStream, tokens::Token, types::{self, ResolvedType}, - util::ExtraUtilFunctions, }; use thiserror::Error; @@ -46,7 +50,7 @@ enum ParseErrorReason { } #[derive(Debug)] -pub struct ParserReturns { +pub struct ParserReturns { pub ast: T, pub loc: crate::Location, pub warnings: Vec, //TODO! add warnings and a way next_toplevel treat warnings as errors @@ -80,12 +84,13 @@ where } pub fn has_next(&mut self) -> bool { - let _ = self.stream.peeking_take_while(|(token,_)| { - match token { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { Token::Seq | Token::EndBlock => true, _ => false, - } - }).collect_vec(); + }) + .collect_vec(); self.stream .peek() .map_or(false, |(token, _)| !token.is_eof()) @@ -176,7 +181,7 @@ where errors, } } - Some((Token::Let,_)) => { + Some((Token::Let, _)) => { let _ = self.stream.next(); let (token, ident_span) = self.stream.next().unwrap(); let (ident, is_op) = match token { @@ -187,7 +192,7 @@ where ast: TopLevelDeclaration::Value(TopLevelValue { loc: ident_span, is_op: false, - ident:"".to_string(), + ident: "".to_string(), args: vec![ArgDeclaration::Simple { loc: (0, 0), ident: "".to_string(), @@ -212,9 +217,12 @@ where errors.extend(args.errors); let mut args = args.ast; if is_op && (args.len() > 2 || args.len() == 0) { - errors.push(ParseError { span: ident_span, reason:ParseErrorReason::ArgumentError }); + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::ArgumentError, + }); } - let mut ty = if let Some((Token::Colon, _)) =self.stream.peek() { + let mut ty = if let Some((Token::Colon, _)) = self.stream.peek() { let _ = self.stream.next(); let ty = self.collect_type(); warnings.extend(ty.warnings); @@ -222,15 +230,18 @@ where Some(ty.ast) } else { if is_op { - errors.push(ParseError { span: ident_span, reason: ParseErrorReason::DeclarationError }); + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); } None }; let value = match self.stream.peek() { - Some((Token::Op(op),_)) if op == "=" => { + Some((Token::Op(op), _)) if op == "=" => { let _ = self.stream.next(); match self.stream.peek() { - Some((Token::BeginBlock,_)) => { + Some((Token::BeginBlock, _)) => { let block = self.collect_block(); warnings.extend(block.warnings); errors.extend(block.errors); @@ -243,29 +254,29 @@ where ValueType::Expr(expr.ast) } None => { - errors.push(ParseError{ - span:(0,0), - reason:ParseErrorReason::UnexpectedEndOfFile, + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, }); ValueType::Expr(Expr::Error) } } - }, - Some((Token::Seq,_)) if abi.is_some() => { + } + Some((Token::Seq, _)) if abi.is_some() => { let _ = self.stream.next(); ValueType::External - }, - Some((_,loc)) => { - errors.push(ParseError{ - span:*loc, - reason:ParseErrorReason::UnexpectedToken, + } + Some((_, loc)) => { + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnexpectedToken, }); ValueType::Expr(Expr::Error) - }, + } None => { - errors.push(ParseError{ - span:(0,0), - reason:ParseErrorReason::UnexpectedEndOfFile, + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, }); ValueType::Expr(Expr::Error) } @@ -275,7 +286,7 @@ where generics .decls .iter() - .map(|(_,it)| it) + .map(|(_, it)| it) .for_each(|name| arg.apply_generic(name)); } if let Some(ty) = &mut ty { @@ -287,8 +298,8 @@ where } } ParserReturns { - ast:TopLevelDeclaration::Value(TopLevelValue { - loc:ident_span, + ast: TopLevelDeclaration::Value(TopLevelValue { + loc: ident_span, is_op, ident, args, @@ -297,15 +308,15 @@ where generics, abi, }), - loc:ident_span, + loc: ident_span, warnings, errors, } - }, - Some((Token::EoF,loc)) => { + } + Some((Token::EoF, loc)) => { errors.push(ParseError { - span:loc, - reason:ParseErrorReason::UnexpectedEndOfFile, + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, }); ParserReturns { ast: ast::TopLevelDeclaration::Value(TopLevelValue { @@ -326,11 +337,11 @@ where warnings, errors, } - }, - Some((_,loc)) => { + } + Some((_, loc)) => { errors.push(ParseError { - span:(0,0), - reason:ParseErrorReason::UnexpectedToken, + span: (0, 0), + reason: ParseErrorReason::UnexpectedToken, }); ParserReturns { ast: ast::TopLevelDeclaration::Value(TopLevelValue { @@ -354,16 +365,16 @@ where } None => { errors.push(ParseError { - span:(0,0), - reason:ParseErrorReason::UnexpectedEndOfFile, + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, }); ParserReturns { ast: ast::TopLevelDeclaration::Value(TopLevelValue { - loc:(0,0), + loc: (0, 0), is_op: false, ident: "".to_string(), args: vec![ArgDeclaration::Simple { - loc:(0,0), + loc: (0, 0), ident: "".to_string(), ty: Some(types::ERROR), }], @@ -372,12 +383,11 @@ where generics: generics, abi: None, }), - loc:(0,0), + loc: (0, 0), warnings, errors, } } - } } pub fn next_statement(&mut self) -> ParserReturns { @@ -407,8 +417,12 @@ where } Some((Token::Let, _)) => { let inner = match self.stream.clone().nth(1) { - Some((Token::GroupOpen,_)) => self.destructuring_declaration(), - Some((Token::Ident(_),_)) if self.stream.clone().nth(2).map(|(a,_)|a) == Some(Token::CurlOpen) => self.destructuring_declaration(), + Some((Token::GroupOpen, _)) => self.destructuring_declaration(), + Some((Token::Ident(_), _)) + if self.stream.clone().nth(2).map(|(a, _)| a) == Some(Token::CurlOpen) => + { + self.destructuring_declaration() + } _ => self.fn_declaration(None, None), }; if let Some((Token::Seq, _)) = self.stream.clone().next() { @@ -417,12 +431,12 @@ where // TODO generated error here. println!("expected ; on line {}", inner.loc.0); } - + ParserReturns { ast: Statement::Declaration(inner.ast), - loc:inner.loc, - warnings:inner.warnings, - errors:inner.errors, + loc: inner.loc, + warnings: inner.warnings, + errors: inner.errors, } } Some((Token::Return, _)) => { @@ -821,7 +835,7 @@ where let cond = self.next_expr(); warnings.extend(cond.warnings); errors.extend(cond.errors); - let cond = cond.ast.boxed(); + let cond = cond.ast.into(); if let Some((Token::Then, _)) = self.stream.peek() { let _ = self.stream.next(); @@ -863,7 +877,7 @@ where (Vec::new(), ret.ast) } }; - else_ifs.push((cond, body, ret.boxed())); + else_ifs.push((cond, body, ret.into())); if let Some((Token::Else, _loc)) = self.stream.clone().next() { let _else_token = self.stream.next(); @@ -875,11 +889,11 @@ where }); return ParserReturns { ast: ast::IfExpr { - cond: root_cond.boxed(), + cond: root_cond.into(), loc: if_loc, - true_branch: (true_body.0, true_body.1.boxed()), + true_branch: (true_body.0, true_body.1.into()), else_ifs, - else_branch: (Vec::new(), ast::Expr::Error.boxed()), + else_branch: (Vec::new(), ast::Expr::Error.into()), }, loc: if_loc, warnings, @@ -911,20 +925,20 @@ where errors.extend(ret.errors); let _ = self.stream.next(); - (body, ret.ast.boxed()) + (body, ret.ast.into()) } _ => { let ret = self.next_expr(); warnings.extend(ret.warnings); errors.extend(ret.errors); - (Vec::new(), ret.ast.boxed()) + (Vec::new(), ret.ast.into()) } }; ParserReturns { ast: ast::IfExpr { - cond: root_cond.boxed(), - true_branch: (true_body.0, true_body.1.boxed()), + cond: root_cond.into(), + true_branch: (true_body.0, true_body.1.into()), else_ifs, else_branch, loc: if_loc, @@ -943,10 +957,10 @@ where // TODO! recover ParserReturns { ast: ast::IfExpr { - cond: root_cond.boxed(), - true_branch: (true_body.0, true_body.1.boxed()), + cond: root_cond.into(), + true_branch: (true_body.0, true_body.1.into()), else_ifs: Vec::new(), - else_branch: (Vec::new(), Expr::Error.boxed()), + else_branch: (Vec::new(), Expr::Error.into()), loc: if_loc, }, loc: if_loc, @@ -1070,7 +1084,7 @@ where ( FnCall { loc: value_loc, - value: ast::Expr::ValueRead(ident, value_loc).boxed(), + value: ast::Expr::ValueRead(ident, value_loc).into(), arg: None, }, value_loc, @@ -1084,7 +1098,7 @@ where FnCall { loc, value, - arg: Some(next.boxed()), + arg: Some(next.into()), }, next_loc, ) @@ -1092,8 +1106,8 @@ where ( FnCall { loc, - value: Expr::FnCall(inner).boxed(), - arg: Some(next.boxed()), + value: Expr::FnCall(inner).into(), + arg: Some(next.into()), }, next_loc, ) @@ -1113,8 +1127,8 @@ where }); ParserReturns { ast: FnCall { - value: Expr::Error.boxed(), - arg: Some(Expr::Error.boxed()), + value: Expr::Error.into(), + arg: Some(Expr::Error.into()), loc: (0, 0), }, loc: (0, 0), @@ -1276,7 +1290,7 @@ where mut errors, loc: _, } = self.next_expr(); - let cond = cond.boxed(); + let cond = cond.into(); if let Some((Token::Then, _)) = self.stream.peek() { let _ = self.stream.next(); } else { @@ -1337,7 +1351,7 @@ where } = self.next_expr(); warnings.extend(new_warnings); errors.extend(new_errors); - let cond = cond.boxed(); + let cond = cond.into(); if let Some((Token::Then, _)) = self.stream.peek() { let _ = self.stream.next(); } else { @@ -1473,8 +1487,8 @@ where errors.extend(result.errors); ParserReturns { ast: ResolvedType::Function { - arg: ty.boxed(), - returns: result.ast.boxed(), + arg: ty.into(), + returns: result.ast.into(), loc: fn_loc, }, loc: fn_loc, @@ -1501,8 +1515,8 @@ where errors.extend(returns.errors); ParserReturns { ast: ResolvedType::Function { - arg: types::UNIT.boxed(), - returns: returns.ast.boxed(), + arg: types::UNIT.into(), + returns: returns.ast.into(), loc: arr_loc, }, loc: span, @@ -1534,9 +1548,7 @@ where Some((Token::GroupClose, _)) => { break; } - Some((Token::Comma, _)) => { - continue - } + Some((Token::Comma, _)) => continue, _ => { errors.push(ParseError { span: span, @@ -1578,8 +1590,8 @@ where errors.extend(result.errors); ParserReturns { ast: ResolvedType::Function { - arg: ty.boxed(), - returns: result.ast.boxed(), + arg: ty.into(), + returns: result.ast.into(), loc: arr_loc, }, loc: arr_loc, @@ -1613,7 +1625,7 @@ where let _ = self.stream.next(); ParserReturns { ast: ResolvedType::Array { - underlining: ty.boxed(), + underlining: ty.into(), size: value.parse().unwrap(), }, loc, @@ -1666,7 +1678,7 @@ where let _ = self.stream.next(); ParserReturns { ast: ResolvedType::Slice { - underlining: ty.boxed(), + underlining: ty.into(), }, loc, warnings, @@ -1786,9 +1798,7 @@ where } let next = self.stream.clone().next(); match next { - Some((Token::Let, _)) => { - self.fn_declaration(abi, generics) - } + Some((Token::Let, _)) => self.fn_declaration(abi, generics), Some((Token::Seq, _)) => { let _ = self.stream.next(); self.declaration() @@ -1891,7 +1901,13 @@ where } } Token::Enum => { - todo!() + let enum_ = self.enum_declaration(generics); + ParserReturns { + ast: ast::TypeDefinition::Enum(enum_.ast), + loc, + warnings: enum_.warnings, + errors: enum_.errors, + } } _ => unreachable!(), } @@ -1900,9 +1916,242 @@ where #[allow(unused)] fn enum_declaration( &mut self, - _generics: HashSet, - ) -> Result, ParseError> { - todo!() + generics: Option, + ) -> ParserReturns { + let mut errors = Vec::new(); + let mut warnings = Vec::new(); + let (ident, loc) = match self.stream.clone().next() { + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + (ident, loc) + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident: "".to_string(), + generics, + values: Vec::new(), + loc: (0, 0), + }, + loc: (0, 0), + warnings, + errors, + }; + } + Some((_, loc)) => { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { + Token::Op(op) if op == "=" || op == "|" => false, + _ => true, + }) + .collect_vec(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ("".to_string(), loc) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident: "".to_string(), + generics, + values: Vec::new(), + loc: (0, 0), + }, + loc: (0, 0), + warnings, + errors, + }; + } + }; + let op = match self.stream.next() { + Some((Token::Op(op), _)) => op, + _ => { + //TODO! progress next_toplevel valid point. + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + }; + + if op != "=" { + //TODO! progress next_toplevel until valid point. + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + let mut values = Vec::new(); + while let Some((Token::Op(op), _)) = self.stream.peek() { + if op == "|" { + let _ = self.stream.next(); + let (ident, variant_loc) = match self.stream.clone().next() { + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + (ident, loc) + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + Some((_, loc)) => { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { + Token::Op(op) if op == "=" || op == "|" => false, + _ => true, + }) + .collect_vec(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ("".to_string(), loc) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + }; + match self.stream.peek() { + Some((Token::CurlOpen, _)) => { + let fields = self.struct_declaration("".to_string(), generics.clone(), loc); + warnings.extend(fields.warnings); + errors.extend(fields.errors); + values.push(ast::EnumVariant::Struct { + ident, + fields: fields.ast.values, + loc: variant_loc, + }); + } + Some((Token::Op(op), _)) if op == "|" => { + values.push(ast::EnumVariant::Unit { + ident, + loc: variant_loc, + }); + } + Some((Token::Ident(_) | Token::BracketOpen | Token::GroupOpen, _)) => { + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + let ty = if let Some(generics) = &generics { + generics + .decls + .iter() + .map(|(_, name)| name) + .fold(ty, |accum, name| accum.replace_user_with_generic(name)) + } else { + ty + }; + values.push(ast::EnumVariant::Tuple { + ident, + ty, + loc: variant_loc, + }); + } + _ => { + values.push(ast::EnumVariant::Unit { + ident, + loc: variant_loc, + }); + break; + } + } + } else { + break; + } + } + ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values, + loc, + }, + loc, + warnings, + errors, + } } fn struct_declaration( @@ -2106,15 +2355,19 @@ where #[allow(unused_mut)] let mut warnings = Vec::new(); let mut errors = Vec::new(); - match dbg!(self.stream.clone().next()) { - Some((Token::GroupOpen,_)) => {//( - let Some((Token::GroupOpen,open_loc)) = self.stream.next() else { unreachable!() }; + match self.stream.clone().next() { + Some((Token::GroupOpen, _)) => { + //( + let Some((Token::GroupOpen, open_loc)) = self.stream.next() else { + unreachable!() + }; match self.stream.clone().next() { - Some((Token::GroupClose,_)) => { //() + Some((Token::GroupClose, _)) => { + //() let _ = self.stream.next(); // ) - let ty = if let Some((Token::Colon,_)) = self.stream.clone().next() { - let _ = self.stream.next();// : - let ty = self.collect_type(); + let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() { + let _ = self.stream.next(); // : + let ty = self.collect_type(); warnings.extend(ty.warnings); errors.extend(ty.errors); // will error at type checking/inference phase if not a unit type. @@ -2122,68 +2375,80 @@ where } else { None }; - ParserReturns { - ast: ArgDeclaration::Unit { loc:open_loc, ty }, - loc:open_loc, + ParserReturns { + ast: ArgDeclaration::Unit { loc: open_loc, ty }, + loc: open_loc, warnings, errors, } - }, - Some((Token::Ident(_),_)) => {// ( - let Some((Token::Ident(name),loc))=self.stream.next() else { unreachable!() }; + } + Some((Token::Ident(_), _)) => { + // ( + let Some((Token::Ident(name), loc)) = self.stream.next() else { + unreachable!() + }; match self.stream.clone().next() { - Some((Token::Colon,_)) => {//(: - let _ = self.stream.next();// : - let ty = self.collect_type(); + Some((Token::Colon, _)) => { + //(: + let _ = self.stream.next(); // : + let ty = self.collect_type(); warnings.extend(ty.warnings); errors.extend(ty.errors); let ty = ty.ast; match self.stream.clone().next() { - Some((Token::GroupClose,_))=> { + Some((Token::GroupClose, _)) => { let _ = self.stream.next(); - }, - Some((_,loc)) => { - errors.push(ParseError { span: loc, reason: ParseErrorReason::UnbalancedBraces }); - }, - None=> { - errors.push(ParseError { span: (0,0), reason: ParseErrorReason::UnbalancedBraces }); - }, + } + Some((_, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnbalancedBraces, + }); + } } ParserReturns { - ast:if name=="_" { - ArgDeclaration::Discard { loc, ty : Some(ty) } + ast: if name == "_" { + ArgDeclaration::Discard { loc, ty: Some(ty) } } else { ArgDeclaration::Simple { loc, - ident:name, - ty:Some(ty), + ident: name, + ty: Some(ty), } }, loc, warnings, errors, } - }, - Some((Token::Comma,_)) => {//(, - let mut contents = vec![ - if name == "_" { - ArgDeclaration::Discard { loc, ty:None } - } else { - ArgDeclaration::Simple { - loc, - ident:name, - ty : None, - } + } + Some((Token::Comma, _)) => { + //(, + let mut contents = vec![if name == "_" { + ArgDeclaration::Discard { loc, ty: None } + } else { + ArgDeclaration::Simple { + loc, + ident: name, + ty: None, } - ]; - let _ = dbg!(self.stream.next()); //, - while let Some((Token::Ident(_)|Token::GroupOpen,_)) = self.stream.clone().next() { + }]; + let _ = self.stream.next(); //, + while let Some((Token::Ident(_) | Token::GroupOpen, _)) = + self.stream.clone().next() + { let arg = self.parse_arg(); warnings.extend(arg.warnings); errors.extend(arg.errors); contents.push(arg.ast); } - let ty = if let Some((Token::Colon,_)) =self.stream.clone().next() { + let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() + { let _ = self.stream.next(); let ty = self.collect_type(); warnings.extend(ty.warnings); @@ -2192,126 +2457,144 @@ where } else { None }; - if let Some((Token::GroupClose,_)) = self.stream.clone().next() { + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { let _ = self.stream.next(); } else { - errors.push(ParseError{ - span:loc, - reason:ParseErrorReason::UnbalancedBraces, + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, }); } ParserReturns { - ast:ArgDeclaration::DestructureTuple(contents,ty,open_loc), - loc:open_loc, + ast: ArgDeclaration::DestructureTuple(contents, ty, open_loc), + loc: open_loc, warnings, errors, } } - Some((Token::GroupClose,_)) => {//() + Some((Token::GroupClose, _)) => { + //() let _ = self.stream.next(); ParserReturns { - ast:if name == "_" { - ArgDeclaration::Discard { loc, ty:None } + ast: if name == "_" { + ArgDeclaration::Discard { loc, ty: None } } else { ArgDeclaration::Simple { loc, - ident:name, - ty : None, + ident: name, + ty: None, } }, - loc:open_loc, + loc: open_loc, warnings, errors, } } - Some((_,loc)) => { - errors.push(ParseError { span: loc, reason: ParseErrorReason::UnbalancedBraces }); + Some((_, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); ParserReturns { - ast:ArgDeclaration::Simple{ + ast: ArgDeclaration::Simple { loc, - ident:"".to_string(), - ty:Some(types::ERROR), + ident: "".to_string(), + ty: Some(types::ERROR), }, loc, warnings, errors, } - }, + } None => { - errors.push(ParseError { span: (0,0), reason: ParseErrorReason::UnbalancedBraces }); + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnbalancedBraces, + }); ParserReturns { - ast:ArgDeclaration::Simple{ - loc:(0,0), - ident:"".to_string(), - ty:Some(types::ERROR), + ast: ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), }, - loc:(0,0), + loc: (0, 0), warnings, errors, } - }, + } } } - _ => {//( + _ => { + //( let inner = self.parse_arg(); warnings.extend(inner.warnings); errors.extend(inner.errors); let mut inner = inner.ast; - if let Some((Token::Colon,_)) = self.stream.clone().next() { + if let Some((Token::Colon, _)) = self.stream.clone().next() { let _ = self.stream.next(); let ty = self.collect_type(); warnings.extend(ty.warnings); errors.extend(ty.errors); let new_ty = ty.ast; match &mut inner { - ArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } => (),//generate warning. + ArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => (), //generate warning. ArgDeclaration::Discard { ty, .. } | ArgDeclaration::DestructureTuple(_, ty, _) | ArgDeclaration::Unit { ty, .. } - | ArgDeclaration::Simple { ty, .. } => *ty = Some(new_ty), + | ArgDeclaration::Simple { ty, .. } => *ty = Some(new_ty), } } - if let Some((Token::GroupClose,_)) = self.stream.clone().next() { + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { let _ = self.stream.next(); } else { errors.push(ParseError { - span:open_loc, - reason:ParseErrorReason::UnbalancedBraces + span: open_loc, + reason: ParseErrorReason::UnbalancedBraces, }); } ParserReturns { - ast:inner, - loc:open_loc, + ast: inner, + loc: open_loc, warnings, errors, } - }, + } } } - Some((Token::Ident(_),_)) => { - let Some((Token::Ident(ident),loc)) = self.stream.next() else { unreachable!() }; + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; ParserReturns { loc, - ast: if ident=="_" { + ast: if ident == "_" { ArgDeclaration::Discard { loc, ty: None } } else { ArgDeclaration::Simple { loc, ident, - ty:None, + ty: None, } }, warnings, errors, } - }, - Some((Token::EoF,loc)) => { - errors.push(ParseError { span : loc, reason: ParseErrorReason::UnexpectedEndOfFile }); + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); ParserReturns { - ast:ArgDeclaration::Simple{ + ast: ArgDeclaration::Simple { loc, - ident:"".to_string(), - ty:Some(types::ERROR), + ident: "".to_string(), + ty: Some(types::ERROR), }, loc, warnings, @@ -2319,27 +2602,33 @@ where } } Some((_token, loc)) => { - errors.push(ParseError { span:loc, reason: ParseErrorReason::UnexpectedToken }); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); ParserReturns { loc, ast: ArgDeclaration::Simple { loc, - ident : "".to_string(), - ty:Some(types::ERROR), + ident: "".to_string(), + ty: Some(types::ERROR), }, warnings, errors, } } None => { - errors.push(ParseError { span :(0,0), reason: ParseErrorReason::UnexpectedEndOfFile }); + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); ParserReturns { - ast:ArgDeclaration::Simple{ - loc:(0,0), - ident:"".to_string(), - ty:Some(types::ERROR), + ast: ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), }, - loc:(0,0), + loc: (0, 0), warnings, errors, } @@ -2351,13 +2640,13 @@ where let mut out = Vec::new(); let mut warnings = Vec::new(); let mut errors = Vec::new(); - while let Some((t,_)) = self.stream.clone().next() { + while let Some((t, _)) = self.stream.clone().next() { if let Token::Op(eq) = &t { if eq == "=" { break; } } - if t==Token::Colon { + if t == Token::Colon { break; } let arg = self.parse_arg(); @@ -2373,17 +2662,17 @@ where } } - fn destructuring_declaration( - &mut self, - ) -> ParserReturns { - let Some((Token::Let,_)) = self.stream.next() else { unreachable!() }; - let ParserReturns { - ast:kind, - loc, - mut warnings, - mut errors + fn destructuring_declaration(&mut self) -> ParserReturns { + let Some((Token::Let, _)) = self.stream.next() else { + unreachable!() + }; + let ParserReturns { + ast: kind, + loc, + mut warnings, + mut errors, } = self.collect_pattern(); - let ty = if let Some((Token::Colon,_)) = self.stream.peek() { + let ty = if let Some((Token::Colon, _)) = self.stream.peek() { let _ = self.stream.next(); let ty = self.collect_type(); warnings.extend(ty.warnings); @@ -2392,32 +2681,32 @@ where } else { None }; - if let Some((Token::Op(eq),loc)) = self.stream.peek() { + if let Some((Token::Op(eq), loc)) = self.stream.peek() { if eq != "=" { - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::UnexpectedToken + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnexpectedToken, }); } else { let _ = self.stream.next(); } } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, }); } let expr = match self.stream.peek() { - Some((Token::BeginBlock,loc)) => { - errors.push(ParseError{ - span:*loc, - reason:ParseErrorReason::UnsupportedFeature, + Some((Token::BeginBlock, loc)) => { + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnsupportedFeature, }); let result = self.collect_block(); warnings.extend(result.warnings); errors.extend(result.errors); ast::Expr::Error - }, + } Some(_) => { let result = self.next_expr(); warnings.extend(result.warnings); @@ -2425,12 +2714,15 @@ where result.ast } _ => { - errors.push(ParseError { span: (0,0), reason:ParseErrorReason::UnexpectedEndOfFile }); + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); ast::Expr::Error } }; ParserReturns { - ast:ValueDeclaration { + ast: ValueDeclaration { loc, is_op: false, target: kind, @@ -2550,7 +2842,7 @@ where ast: ValueDeclaration { loc: ident_span, is_op, - target: ast::Pattern::Read(ident,ident_span), + target: ast::Pattern::Read(ident, ident_span), args, ty, value: ValueType::Expr(Expr::Error), @@ -2688,11 +2980,11 @@ where }; if let Some(generics) = &generics { for arg in &mut args { - generics - .decls - .iter() - .map(|(_, it)| it) - .for_each(|name| arg.apply_generic(name)); + generics + .decls + .iter() + .map(|(_, it)| it) + .for_each(|name| arg.apply_generic(name)); } if let Some(ty) = &mut ty { @@ -2724,7 +3016,7 @@ where ast: ValueDeclaration { loc: (0, 0), is_op: false, - target: ast::Pattern::Read("".to_string(), (0,0)), + target: ast::Pattern::Read("".to_string(), (0, 0)), args: vec![ArgDeclaration::Simple { loc: (0, 0), ident: "".to_string(), @@ -3002,8 +3294,8 @@ where ast::Expr::BinaryOpCall(BinaryOpCall { loc, operator: op, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), }), loc, )) @@ -3074,7 +3366,7 @@ where warnings.extend(pattern.warnings); errors.extend(pattern.errors); let loc = pattern.loc; - let cond = dbg!(pattern.ast); + let cond = pattern.ast; if let Some((Token::Arrow, _)) = self.stream.peek() { self.stream.next(); } else { @@ -3122,7 +3414,7 @@ where } else { println!("did you mean next_toplevel move back a block?"); } - (body, Some(ret.boxed())) + (body, Some(ret.into())) } } } @@ -3147,7 +3439,7 @@ where peeked, loc.0, loc.1 ) } - (Vec::new(), Some(dbg!(expr).boxed())) + (Vec::new(), Some(expr.into())) } }; arms.push(ast::MatchArm { @@ -3162,14 +3454,16 @@ where if let Some((Token::EndBlock, _)) = self.stream.peek() { let _ = self.stream.next(); } else { - println!("did you mean next_toplevel go back next_toplevel the containing block level?"); + println!( + "did you mean next_toplevel go back next_toplevel the containing block level?" + ); } } ParserReturns { ast: Match { loc: match_loc, - on: on.boxed(), + on: on.into(), arms, }, loc: match_loc, @@ -3182,26 +3476,146 @@ where let mut warnings = Vec::new(); let mut errors = Vec::new(); // op should poped beffore this. - let (pattern,loc) = match self.stream.clone().next() { - Some((Token::Ident(_),_)) => { - let Some((Token::Ident(name),loc)) = self.stream.next() else { unreachable!() }; - if name == "_" { - (Pattern::Default,loc) + let (pattern, loc) = match self.stream.clone().next() { + Some((Token::CurlOpen, loc)) => { + let _curl = self.stream.next(); + let mut fields = HashMap::new(); + while let Some((Token::Ident(_), _)) = self.stream.clone().next() { + let Some((Token::Ident(field_name), loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::Colon, _)) = self.stream.clone().next() { + let Some((Token::Colon, _)) = self.stream.next() else { + unreachable!() + }; + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + fields.insert(field_name, sub_pattern.ast); + } else { + fields.insert(field_name.clone(), Pattern::Read(field_name, loc)); + } + if let Some((Token::Comma, _)) = self.stream.clone().next() { + let _comma = self.stream.next(); + } else { + break; + } + } + if let Some((Token::CurlClose, _)) = self.stream.clone().next() { + let _curl = self.stream.next(); } else { - // TODO! pattern detection of enum varaints. - (Pattern::Read(name, loc),loc) + //todo! recovery. } - }, - Some((Token::Integer(_, _),_)) => { - let Some((Token::Integer(signed,value),loc)) = self.stream.next() else { unreachable!() }; + ( + Pattern::Destructure(PatternDestructure::Struct { + base_ty: None, + fields, + }), + loc, + ) + } + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(name), loc)) = self.stream.next() else { + unreachable!() + }; + match self.stream.clone().next() { + Some((Token::Scope, _)) => { + let enum_name = name; + let Some((_scope, scope_loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::Ident(_), _)) = self.stream.clone().next() { + let Some((Token::Ident(variant), _)) = self.stream.next() else { + unreachable!() + }; + let pattern = match self.stream.clone().next() { + Some(( + Token::CurlOpen + | Token::GroupOpen + | Token::Ident(_) + | Token::BracketOpen + | Token::Integer(_, _) + | Token::FloatingPoint(_, _), + _, + )) => { + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + Some(sub_pattern.ast.into()) + } + _ => None, + }; + ( + Pattern::EnumVariant { + ty: Some(enum_name), + variant, + pattern, + loc, + }, + loc, + ) + } else { + errors.push(ParseError { + span: scope_loc, + reason: ParseErrorReason::UnexpectedToken, + }); + (Pattern::Error, loc) + } + } + Some((Token::CurlOpen, _)) => { + let mut sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + let Pattern::Destructure(PatternDestructure::Struct { base_ty, .. }) = + &mut sub_pattern.ast + else { + unreachable!() + }; + *base_ty = Some(name); + (sub_pattern.ast, loc) + } + Some(( + Token::GroupOpen + | Token::Ident(_) + | Token::BracketOpen + | Token::Integer(_, _) + | Token::FloatingPoint(_, _), + _, + )) => { + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + ( + Pattern::EnumVariant { + ty: None, + variant: name, + pattern: Some(sub_pattern.ast.into()), + loc, + }, + loc, + ) + } + _ => { + if name == "_" { + (Pattern::Default, loc) + } else { + // TODO! pattern detection of enum varaints. + (Pattern::Read(name, loc), loc) + } + } + } + } + Some((Token::Integer(_, _), _)) => { + let Some((Token::Integer(signed, value), loc)) = self.stream.next() else { + unreachable!() + }; ( Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), loc, ) - }, + } Some((Token::FloatingPoint(_, _), _)) => { - let Some((Token::FloatingPoint(signed, value), loc)) = self.stream.next() - else { + let Some((Token::FloatingPoint(signed, value), loc)) = self.stream.next() else { unreachable!() }; @@ -3209,37 +3623,39 @@ where Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), loc, ) - }, + } Some((Token::CharLiteral(_), _)) => { let Some((Token::CharLiteral(c), loc)) = self.stream.next() else { unreachable!() }; (Pattern::ConstChar(c), loc) - }, + } Some((Token::StringLiteral(_), _)) => { let Some((Token::StringLiteral(c), loc)) = self.stream.next() else { unreachable!() }; (Pattern::ConstStr(c), loc) - }, + } Some((Token::True, _)) => { let Some((_, loc)) = self.stream.next() else { unreachable!() }; (Pattern::ConstBool(true), loc) - }, + } Some((Token::False, _)) => { let Some((_, loc)) = self.stream.next() else { unreachable!() }; (Pattern::ConstBool(false), loc) - }, + } - Some((Token::GroupOpen,_)) => { - let Some((Token::GroupOpen,loc)) = self.stream.next() else { unreachable!() }; - if let Some((Token::GroupClose,_)) = self.stream.clone().next() { + Some((Token::GroupOpen, _)) => { + let Some((Token::GroupOpen, loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { let _ = self.stream.next(); - (Pattern::Destructure(PatternDestructure::Unit),loc) + (Pattern::Destructure(PatternDestructure::Unit), loc) } else { let first = self.collect_pattern(); warnings.extend(first.warnings); @@ -3248,113 +3664,123 @@ where let mut patterns = vec![first.ast]; loop { match self.stream.clone().next() { - Some((Token::Comma,_)) => { + Some((Token::Comma, _)) => { let _ = self.stream.next(); let next = self.collect_pattern(); warnings.extend(next.warnings); errors.extend(next.errors); patterns.push(next.ast); - }, - Some((Token::GroupClose,_)) => { + } + Some((Token::GroupClose, _)) => { break; - }, - Some((Token::EoF,_))|None => - { + } + Some((Token::EoF, _)) | None => { let _ = self.stream.next(); errors.push(ParseError { - span:loc, - reason:ParseErrorReason::UnexpectedEndOfFile + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, }); break; } - Some((t,loc)) => { + Some((t, loc)) => { let _ = self.stream.next(); errors.push(ParseError { - span:loc, - reason:ParseErrorReason::UnexpectedToken + span: loc, + reason: ParseErrorReason::UnexpectedToken, }); break; } } } match self.stream.clone().next() { - Some((Token::GroupClose,_)) => { + Some((Token::GroupClose, _)) => { let _ = self.stream.next(); - }, - Some((Token::EoF,_))|None => - { - + } + Some((Token::EoF, _)) | None => { let _ = self.stream.next(); errors.push(ParseError { - span:loc, - reason:ParseErrorReason::UnexpectedEndOfFile + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, }); } - Some((t,loc)) => { - let n = - self.stream.clone() - .peeking_take_while(|(t,_)| match t { - Token::Comma | Token::EndBlock =>false, - Token::Op(op) => op != "|", - _ => true, - }) - .collect_vec() - .len() - ; + Some((t, loc)) => { + let n = self + .stream + .clone() + .peeking_take_while(|(t, _)| match t { + Token::Comma | Token::EndBlock => false, + Token::Op(op) => op != "|", + _ => true, + }) + .collect_vec() + .len(); for _ in 0..n { let _ = self.stream.next(); } - errors.push(ParseError { span: loc, reason: ParseErrorReason::UnexpectedToken }); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); } } if patterns.len() == 1 { - (patterns.pop().unwrap(),first_loc) + (patterns.pop().unwrap(), first_loc) } else { - (Pattern::Destructure(PatternDestructure::Tuple(patterns)),loc) + ( + Pattern::Destructure(PatternDestructure::Tuple(patterns)), + loc, + ) } } } - Some((Token::EoF,_))|None => - { + Some((Token::EoF, _)) | None => { let _ = self.stream.next(); errors.push(ParseError { - span:(0,0), - reason:ParseErrorReason::UnexpectedEndOfFile + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, }); - (Pattern::Error,(0,0)) + (Pattern::Error, (0, 0)) } - Some((t,loc)) => { - errors.push(ParseError { span:loc, reason: ParseErrorReason::UnexpectedToken }); - let n = - self.stream.clone() - .peeking_take_while(|(t,_)| match t { - Token::Comma | Token::EndBlock =>false, + Some((t, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + let n = self + .stream + .clone() + .peeking_take_while(|(t, _)| match t { + Token::Comma | Token::EndBlock => false, Token::Op(op) => op != "|", _ => true, }) .collect_vec() - .len() - ; + .len(); for _ in 0..n { let _ = self.stream.next(); } - (Pattern::Error,loc) + (Pattern::Error, loc) } }; - let pattern = if let Some((Token::Op(op),_)) = self.stream.peek() { + let pattern = if let Some((Token::Op(op), _)) = self.stream.peek() { if op == "|" { let _ = self.stream.next(); - let next=self.collect_pattern(); + let next = self.collect_pattern(); warnings.extend(next.warnings); errors.extend(next.errors); - Pattern::Or(pattern.boxed(), next.ast.boxed()) + Pattern::Or(pattern.into(), next.ast.into()) } else { pattern } } else { pattern }; - ParserReturns { ast: pattern, loc, warnings, errors } + ParserReturns { + ast: pattern, + loc, + warnings, + errors, + } } fn array_literal(&mut self) -> ParserReturns { @@ -3527,11 +3953,14 @@ impl std::fmt::Debug for ShuntingYardOptions { #[cfg(test)] mod tests { - use crate::{ - ast::{ArgDeclaration, TopLevelDeclaration, IfBranching, IfExpr, MatchArm, StructDefinition}, + ast::{ + ArgDeclaration, EnumDeclaration, EnumVariant, IfBranching, IfExpr, MatchArm, + StructDefinition, TopLevelDeclaration, + }, types::ResolvedType, }; + use pretty_assertions::assert_eq; #[test] fn types() { @@ -3563,7 +3992,7 @@ mod tests { assert_eq!( Parser::from_source("[int32;5]").collect_type().ast, ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 5 } ); @@ -3572,8 +4001,8 @@ mod tests { assert_eq!( Parser::from_source("int32->int32").collect_type().ast, ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0), } ); @@ -3582,13 +4011,13 @@ mod tests { .collect_type() .ast, ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0), } - .boxed(), + .into(), loc: (0, 0), } ); @@ -3597,13 +4026,13 @@ mod tests { .collect_type() .ast, ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0), } - .boxed(), + .into(), loc: (0, 0), } ); @@ -3613,12 +4042,12 @@ mod tests { .ast, ResolvedType::Function { arg: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0), } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (0, 0), } ); @@ -3628,13 +4057,16 @@ mod tests { #[test] #[ignore = "This is for singled out tests"] fn for_debugging_only() { - let mut parser = Parser::from_source(" -let a (v:(int32,int32)) = - let (x,y) = v; - return (); - -let b ((x,y):(int32,int32)) = (); "); - dbg!(parser.module("".to_string())); + let mut parser = Parser::from_source( + "enum Testing = | One (int8,int8) | Two +let fun test = match test where +| Testing::One (0,1) -> 0, +| Testing::One ((1|0),a) -> a, +| Testing::One _ -> -1, +| Testing::Two -> -2, ", + ); + let module = parser.module("".to_string()); + println!("{module:#?}") } #[test] fn individual_simple_expressions() { @@ -3644,7 +4076,7 @@ let b ((x,y):(int32,int32)) = (); "); Statement::Declaration(ValueDeclaration { loc: (0, 4), is_op: false, - target:ast::Pattern::Read("foo".to_owned(),(0,4)), + target: ast::Pattern::Read("foo".to_owned(), (0, 4)), ty: Some(types::INT32), args: Vec::new(), value: ValueType::Expr(Expr::NumericLiteral { @@ -3666,11 +4098,14 @@ let b ((x,y):(int32,int32)) = (); "); is_op: false, ident: "foo".to_owned(), ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 18) }), - args: vec![ArgDeclaration::Discard{ty:None,loc:(0,8)}], + args: vec![ArgDeclaration::Discard { + ty: None, + loc: (0, 8) + }], value: ValueType::Function(vec![Statement::Return( Expr::NumericLiteral { value: "5".to_string(), @@ -3695,18 +4130,21 @@ let foo _ : ( int32 -> int32 ) -> int32 = Statement::Declaration(ValueDeclaration { loc: (1, 4), is_op: false, - target: ast::Pattern::Read("foo".to_owned(), (1,4)), + target: ast::Pattern::Read("foo".to_owned(), (1, 4)), ty: Some(ResolvedType::Function { arg: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (1, 20) } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (1, 31) }), - args: vec![ast::ArgDeclaration::Discard{ty:None, loc:(1,8)}], + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 8) + }], value: ValueType::Function(vec![Statement::Return( Expr::NumericLiteral { value: "0".to_string(), @@ -3728,18 +4166,21 @@ let foo _ : int32 -> ( int32 -> int32 ) = Statement::Declaration(ValueDeclaration { loc: (1, 4), is_op: false, - target:ast::Pattern::Read("foo".to_owned(), (1,4)), + target: ast::Pattern::Read("foo".to_owned(), (1, 4)), ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (1, 29) } - .boxed(), + .into(), loc: (1, 18) }), - args: vec![ast::ArgDeclaration::Discard{ty:None,loc:(1,8)}], + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 8) + }], value: ValueType::Function(vec![Statement::Return( Expr::NumericLiteral { value: "0".to_owned(), @@ -3762,7 +4203,7 @@ let foo _ : int32 -> ( int32 -> int32 ) = ast::TopLevelDeclaration::Value(TopLevelValue { loc: (0, 4), is_op: false, - ident:"foo".to_owned(), + ident: "foo".to_owned(), ty: Some(types::INT32), args: Vec::new(), value: ValueType::Expr(Expr::NumericLiteral { @@ -3778,10 +4219,10 @@ let foo _ : int32 -> ( int32 -> int32 ) = ast::TopLevelDeclaration::Value(TopLevelValue { loc: (2, 4), is_op: false, - ident:"bar".to_owned(), + ident: "bar".to_owned(), ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (2, 20) }), args: vec![ast::ArgDeclaration::Simple { @@ -3793,7 +4234,7 @@ let foo _ : int32 -> ( int32 -> int32 ) = Statement::Declaration(ValueDeclaration { loc: (3, 8), is_op: false, - target:Pattern::Read("baz".to_owned(), (3,8)), + target: Pattern::Read("baz".to_owned(), (3, 8)), ty: Some(types::STR), args: Vec::new(), value: ValueType::Expr(Expr::StringLiteral(r#"merp " yes"#.to_string())), @@ -3817,16 +4258,16 @@ let foo _ : int32 -> ( int32 -> int32 ) = ast::TopLevelDeclaration::Value(TopLevelValue { loc: (6, 4), is_op: true, - - ident:"^^".to_owned(), + + ident: "^^".to_owned(), ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (6, 32) } - .boxed(), + .into(), loc: (6, 23) }), args: vec![ @@ -3844,8 +4285,8 @@ let foo _ : int32 -> ( int32 -> int32 ) = value: ValueType::Function(vec![ Statement::FnCall(FnCall { loc: (7, 4), - value: Expr::ValueRead("bar".to_string(), (7, 4)).boxed(), - arg: Some(Expr::ValueRead("foo".to_string(), (7, 8)).boxed()), + value: Expr::ValueRead("bar".to_string(), (7, 4)).into(), + arg: Some(Expr::ValueRead("foo".to_string(), (7, 8)).into()), }), Statement::Return( Expr::NumericLiteral { @@ -3875,29 +4316,32 @@ let main _ : int32 -> int32 = Statement::Declaration(ValueDeclaration { loc: (1, 4), is_op: false, - - target:Pattern::Read("main".to_owned(), (1,4)), + + target: Pattern::Read("main".to_owned(), (1, 4)), ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (1, 19) }), - args: vec![ast::ArgDeclaration::Discard{ty:None,loc:(1,9)}], + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 9) + }], value: ValueType::Function(vec![ Statement::FnCall(FnCall { loc: (2, 4), - value: Expr::ValueRead("put_int32".to_string(), (2, 4)).boxed(), + value: Expr::ValueRead("put_int32".to_string(), (2, 4)).into(), arg: Some( Expr::NumericLiteral { value: "100".to_owned(), } - .boxed() + .into() ) }), Statement::FnCall(FnCall { loc: (3, 4), - value: Expr::ValueRead("print_str".to_string(), (3, 4)).boxed(), - arg: Some(Expr::StringLiteral("v".to_string()).boxed()) + value: Expr::ValueRead("print_str".to_string(), (3, 4)).into(), + arg: Some(Expr::StringLiteral("v".to_string()).into()) }), Statement::Return( Expr::NumericLiteral { @@ -3924,7 +4368,7 @@ let main _ : int32 -> int32 = lhs: Expr::NumericLiteral { value: "100".to_string(), } - .boxed(), + .into(), rhs: Expr::BinaryOpCall(BinaryOpCall { loc: (0, 16), lhs: Expr::BinaryOpCall(BinaryOpCall { @@ -3932,27 +4376,27 @@ let main _ : int32 -> int32 = lhs: Expr::NumericLiteral { value: "100".to_string(), } - .boxed(), - rhs: Expr::ValueRead("foo".to_string(), (0, 12)).boxed(), + .into(), + rhs: Expr::ValueRead("foo".to_string(), (0, 12)).into(), operator: "*".to_string() }) - .boxed(), + .into(), rhs: Expr::BinaryOpCall(BinaryOpCall { loc: (0, 23), lhs: Expr::NumericLiteral { value: "10".to_string(), } - .boxed(), + .into(), rhs: Expr::NumericLiteral { value: "1".to_string(), } - .boxed(), + .into(), operator: "-".to_string() }) - .boxed(), + .into(), operator: "*".to_string() }) - .boxed(), + .into(), operator: "+".to_string() }), parser.next_expr().ast @@ -3965,13 +4409,16 @@ let main _ : int32 -> int32 = Statement::Declaration(ValueDeclaration { loc: (0, 4), is_op: false, - target:Pattern::Read("main".to_owned(), (0,4)), + target: Pattern::Read("main".to_owned(), (0, 4)), ty: None, - args: vec![ast::ArgDeclaration::Discard{ty:None,loc:(0,9)}], + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (0, 9) + }], value: ValueType::Function(vec![ Statement::FnCall(FnCall { loc: (1, 4), - value: Expr::ValueRead("print_int32".to_owned(), (1, 4)).boxed(), + value: Expr::ValueRead("print_int32".to_owned(), (1, 4)).into(), arg: Some( Expr::BinaryOpCall(BinaryOpCall { loc: (1, 20), @@ -3979,13 +4426,13 @@ let main _ : int32 -> int32 = lhs: Expr::NumericLiteral { value: "100".to_owned(), } - .boxed(), + .into(), rhs: Expr::NumericLiteral { value: "100".to_owned(), } - .boxed() + .into() }) - .boxed() + .into() ) }), Statement::Return( @@ -4010,25 +4457,25 @@ let main _ : int32 -> int32 = loc: (0, 4), lhs: ast::Expr::BinaryOpCall(BinaryOpCall { loc: (0, 1), - lhs: ast::Expr::ValueRead("a".to_string(), (0, 0)).boxed(), - rhs: ast::Expr::ValueRead("b".to_string(), (0, 2)).boxed(), + lhs: ast::Expr::ValueRead("a".to_string(), (0, 0)).into(), + rhs: ast::Expr::ValueRead("b".to_string(), (0, 2)).into(), operator: ".".to_string() }) - .boxed(), + .into(), rhs: ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed(), + .into(), operator: "+".to_string() }) - .boxed(), + .into(), rhs: ast::Expr::BinaryOpCall(BinaryOpCall { loc: (0, 11), - lhs: ast::Expr::ValueRead("c".to_string(), (0, 10)).boxed(), - rhs: ast::Expr::ValueRead("d".to_string(), (0, 12)).boxed(), + lhs: ast::Expr::ValueRead("c".to_string(), (0, 10)).into(), + rhs: ast::Expr::ValueRead("d".to_string(), (0, 12)).into(), operator: ".".to_string() }) - .boxed(), + .into(), operator: "-".to_string() }), parser.next_expr().ast, @@ -4040,16 +4487,16 @@ let main _ : int32 -> int32 = loc: (0, 10), lhs: ast::Expr::FnCall(FnCall { loc: (0, 1), - value: ast::Expr::ValueRead("foo".to_string(), (0, 1)).boxed(), - arg: Some(ast::Expr::ValueRead("bar".to_string(), (0, 5)).boxed()) + value: ast::Expr::ValueRead("foo".to_string(), (0, 1)).into(), + arg: Some(ast::Expr::ValueRead("bar".to_string(), (0, 5)).into()) }) - .boxed(), + .into(), rhs: ast::Expr::FnCall(FnCall { loc: (0, 14), - value: ast::Expr::ValueRead("baz".to_string(), (0, 14)).boxed(), - arg: Some(ast::Expr::ValueRead("quz".to_string(), (0, 18)).boxed()) + value: ast::Expr::ValueRead("baz".to_string(), (0, 14)).into(), + arg: Some(ast::Expr::ValueRead("quz".to_string(), (0, 18)).into()) }) - .boxed(), + .into(), operator: "&&".to_string() }), parser.next_expr().ast, @@ -4064,7 +4511,7 @@ let main _ : int32 -> int32 = ast::TopLevelDeclaration::Value(TopLevelValue { loc: (0, 11), is_op: false, - ident:"test".to_owned(), + ident: "test".to_owned(), args: vec![ast::ArgDeclaration::Simple { loc: (0, 16), ident: "a".to_string(), @@ -4075,12 +4522,12 @@ let main _ : int32 -> int32 = name: "T".to_string(), loc: (0, 20) } - .boxed(), + .into(), returns: ResolvedType::Generic { name: "T".to_string(), loc: (0, 25) } - .boxed(), + .into(), loc: (0, 22) }), value: ast::ValueType::Expr(ast::Expr::ValueRead("a".to_string(), (0, 29))), @@ -4105,46 +4552,50 @@ for type Tuple = { }"#; let mut parser = Parser::from_source(SRC); assert_eq!( - ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct(StructDefinition { - ident: "Foo".to_string(), - generics: None, - values: vec![ast::FieldDecl { - name: "a".to_string(), - ty: types::INT32, - loc: (1, 4), - }], - loc: (0, 5) - },)), + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( + StructDefinition { + ident: "Foo".to_string(), + generics: None, + values: vec![ast::FieldDecl { + name: "a".to_string(), + ty: types::INT32, + loc: (1, 4), + }], + loc: (0, 5) + }, + )), parser.next_toplevel().ast, "basic" ); assert_eq!( - ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct(StructDefinition { - ident: "Tuple".to_string(), - generics: Some(ast::GenericsDecl { - for_loc: (3, 0), - decls: vec![((3, 4), "T".to_string()), ((3, 6), "U".to_string())], - }), - values: vec![ - ast::FieldDecl { - name: "first".to_string(), - ty: ResolvedType::Generic { - name: "T".to_string(), - loc: (4, 12), + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( + StructDefinition { + ident: "Tuple".to_string(), + generics: Some(ast::GenericsDecl { + for_loc: (3, 0), + decls: vec![((3, 4), "T".to_string()), ((3, 6), "U".to_string())], + }), + values: vec![ + ast::FieldDecl { + name: "first".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (4, 12), + }, + loc: (4, 4) }, - loc: (4, 4) - }, - ast::FieldDecl { - name: "second".to_string(), - ty: ResolvedType::Generic { - name: "U".to_string(), - loc: (5, 13) + ast::FieldDecl { + name: "second".to_string(), + ty: ResolvedType::Generic { + name: "U".to_string(), + loc: (5, 13) + }, + loc: (5, 4) }, - loc: (5, 4) - }, - ], - loc: (3, 14) - })), + ], + loc: (3, 14) + } + )), parser.next_toplevel().ast, "generic" ) @@ -4160,7 +4611,7 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (0, 4), is_op: false, - ident:"foo".to_owned(), + ident: "foo".to_owned(), args: vec![ ArgDeclaration::Simple { loc: (0, 8), @@ -4179,18 +4630,18 @@ for type Tuple = { generics: vec![types::INT32], loc: (0, 14) } - .boxed(), + .into(), returns: ResolvedType::Function { arg: ResolvedType::User { name: "Baz".to_string(), generics: vec![types::INT32, types::FLOAT64], loc: (0, 28) } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (0, 47) } - .boxed(), + .into(), loc: (0, 25) }), value: ValueType::Function(vec![Statement::Return( @@ -4253,25 +4704,25 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (0, 4), is_op: false, - ident:"inline_expr".to_owned(), + ident: "inline_expr".to_owned(), args: vec![ast::ArgDeclaration::Simple { ident: "a".to_string(), loc: (0, 16), ty: None, }], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (0, 25) }), value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (0, 39)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (0, 39)).into(), true_branch: ( Vec::new(), ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( @@ -4279,7 +4730,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ), loc: (0, 36) })), @@ -4294,32 +4745,32 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (2, 4), is_op: false, - ident:"out_of_line_expr".to_owned(), + ident: "out_of_line_expr".to_owned(), args: vec![ast::ArgDeclaration::Simple { ident: "a".to_string(), loc: (2, 21), ty: None, }], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (2, 30) }), value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (2, 44)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (2, 44)).into(), true_branch: ( Vec::new(), ast::Expr::FnCall(ast::FnCall { loc: (3, 8), - value: ast::Expr::ValueRead("fun".to_string(), (3, 8)).boxed(), + value: ast::Expr::ValueRead("fun".to_string(), (3, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed() + .into() ), }) - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( @@ -4327,7 +4778,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ), loc: (2, 41) })), @@ -4342,51 +4793,51 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (7, 4), is_op: false, - ident:"expr_with_statement".to_owned(), + ident: "expr_with_statement".to_owned(), args: vec![ast::ArgDeclaration::Simple { loc: (7, 24), ident: "a".to_string(), ty: None, }], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (7, 33) }), value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (7, 47)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (7, 47)).into(), true_branch: ( vec![ast::Statement::FnCall(FnCall { loc: (8, 8), - value: ast::Expr::ValueRead("bar".to_string(), (8, 8)).boxed(), + value: ast::Expr::ValueRead("bar".to_string(), (8, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "3".to_string(), } - .boxed() + .into() ), })], ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( vec![ast::Statement::FnCall(FnCall { loc: (11, 8), - value: ast::Expr::ValueRead("baz".to_string(), (11, 8)).boxed(), + value: ast::Expr::ValueRead("baz".to_string(), (11, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "4".to_string(), } - .boxed() + .into() ), })], ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ), loc: (7, 44) })), @@ -4401,7 +4852,7 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (14, 4), is_op: false, - ident:"expr_with_else_if".to_owned(), + ident: "expr_with_else_if".to_owned(), args: vec![ ast::ArgDeclaration::Simple { loc: (14, 22), @@ -4415,38 +4866,38 @@ for type Tuple = { }, ], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), + arg: types::BOOL.into(), returns: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (14, 41) } - .boxed(), + .into(), loc: (14, 33) }), value: ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (14, 55)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (14, 55)).into(), true_branch: ( Vec::new(), ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed() + .into() ), else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (14, 72)).boxed(), + ast::Expr::ValueRead("b".to_string(), (14, 72)).into(), Vec::new(), ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ),], else_branch: ( Vec::new(), ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed() + .into() ), loc: (14, 52) })), @@ -4461,28 +4912,28 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (16, 4), is_op: false, - ident:"statement".to_owned(), + ident: "statement".to_owned(), args: vec![ast::ArgDeclaration::Simple { loc: (16, 14), ident: "a".to_string(), ty: None, }], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (16, 23) }), value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { - cond: ast::Expr::ValueRead("a".to_string(), (17, 7)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (17, 7)).into(), true_branch: vec![ ast::Statement::FnCall(FnCall { loc: (18, 8), - value: ast::Expr::ValueRead("foo".to_string(), (18, 8)).boxed(), + value: ast::Expr::ValueRead("foo".to_string(), (18, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "3".to_string(), } - .boxed() + .into() ) }), ast::Statement::Return( @@ -4496,12 +4947,12 @@ for type Tuple = { else_branch: vec![ ast::Statement::FnCall(FnCall { loc: (21, 8), - value: ast::Expr::ValueRead("bar".to_string(), (21, 8)).boxed(), + value: ast::Expr::ValueRead("bar".to_string(), (21, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "4".to_string(), } - .boxed() + .into() ) }), ast::Statement::Return( @@ -4524,7 +4975,7 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (24, 4), is_op: false, - ident:"statement_with_else_if".to_owned(), + ident: "statement_with_else_if".to_owned(), args: vec![ ast::ArgDeclaration::Simple { loc: (24, 27), @@ -4538,17 +4989,17 @@ for type Tuple = { }, ], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), + arg: types::BOOL.into(), returns: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (24, 46) } - .boxed(), + .into(), loc: (24, 38) }), value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { - cond: ast::Expr::ValueRead("a".to_string(), (25, 7)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (25, 7)).into(), true_branch: vec![ast::Statement::Return( ast::Expr::NumericLiteral { value: "0".to_string(), @@ -4556,7 +5007,7 @@ for type Tuple = { (26, 8) )], else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (27, 12)).boxed(), + ast::Expr::ValueRead("b".to_string(), (27, 12)).into(), vec![ast::Statement::Return( ast::Expr::NumericLiteral { value: "1".to_string(), @@ -4583,7 +5034,7 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (32, 4), is_op: false, - ident:"expr_multi_with_elseif".to_owned(), + ident: "expr_multi_with_elseif".to_owned(), args: vec![ ast::ArgDeclaration::Simple { loc: (32, 27), @@ -4597,38 +5048,38 @@ for type Tuple = { }, ], ty: Some(ResolvedType::Function { - arg: types::BOOL.boxed(), + arg: types::BOOL.into(), returns: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (32, 46) } - .boxed(), + .into(), loc: (32, 38) }), value: ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (32, 60)).boxed(), + cond: ast::Expr::ValueRead("a".to_string(), (32, 60)).into(), true_branch: ( Vec::new(), ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed(), + .into(), ), else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (34, 12)).boxed(), + ast::Expr::ValueRead("b".to_string(), (34, 12)).into(), Vec::new(), ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed(), + .into(), )], else_branch: ( Vec::new(), ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed(), + .into(), ), loc: (32, 57) })), @@ -4647,20 +5098,20 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (0, 4), is_op: false, - ident:"match_expr_ints".to_owned(), + ident: "match_expr_ints".to_owned(), args: vec![ast::ArgDeclaration::Simple { loc: (0, 20), ident: "x".to_string(), ty: None, }], ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 30) }), value: ast::ValueType::Expr(ast::Expr::Match(Match { loc: (0, 41), - on: ast::Expr::ValueRead("x".to_string(), (0, 47)).boxed(), + on: ast::Expr::ValueRead("x".to_string(), (0, 47)).into(), arms: vec![ MatchArm { block: Vec::new(), @@ -4668,7 +5119,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ), cond: Pattern::ConstNumber("1".to_string()), loc: (1, 6) @@ -4679,7 +5130,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "3".to_string(), } - .boxed() + .into() ), cond: Pattern::ConstNumber("2".to_string()), loc: (2, 6) @@ -4690,7 +5141,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "4".to_string(), } - .boxed() + .into() ), cond: Pattern::Default, loc: (3, 6) @@ -4708,27 +5159,27 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (5, 4), is_op: false, - ident:"match_expr_with_block".to_owned(), + ident: "match_expr_with_block".to_owned(), args: vec![ArgDeclaration::Simple { loc: (5, 26), ident: "x".to_string(), ty: None, },], ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (5, 36) }), value: ValueType::Expr(ast::Expr::Match(Match { loc: (5, 47), - on: ast::Expr::ValueRead("x".to_string(), (5, 53)).boxed(), + on: ast::Expr::ValueRead("x".to_string(), (5, 53)).into(), arms: vec![ MatchArm { loc: (6, 6), block: vec![ast::Statement::Declaration(ValueDeclaration { loc: (7, 12), is_op: false, - target:Pattern::Read("a".to_owned(), (7,12)), + target: Pattern::Read("a".to_owned(), (7, 12)), args: Vec::new(), ty: Some(types::INT32), value: ValueType::Expr(ast::Expr::NumericLiteral { @@ -4740,14 +5191,14 @@ for type Tuple = { ret: Some( ast::Expr::BinaryOpCall(BinaryOpCall { loc: (8, 9), - lhs: ast::Expr::ValueRead("a".to_string(), (8, 8)).boxed(), + lhs: ast::Expr::ValueRead("a".to_string(), (8, 8)).into(), rhs: ast::Expr::NumericLiteral { value: "3".to_string(), } - .boxed(), + .into(), operator: "*".to_string() }) - .boxed() + .into() ), cond: Pattern::ConstNumber("1".to_string()), }, @@ -4757,7 +5208,7 @@ for type Tuple = { ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed() + .into() ), cond: Pattern::ConstNumber("2".to_string()), loc: (9, 6) @@ -4768,16 +5219,16 @@ for type Tuple = { ret: Some( ast::Expr::BinaryOpCall(BinaryOpCall { loc: (10, 12), - lhs: ast::Expr::ValueRead("a".to_string(), (10, 11)).boxed(), + lhs: ast::Expr::ValueRead("a".to_string(), (10, 11)).into(), rhs: ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed(), + .into(), operator: "/".to_string() }) - .boxed() + .into() ), - cond: Pattern::Read("a".to_string(),(10,6)), + cond: Pattern::Read("a".to_string(), (10, 6)), }, ] })), @@ -4791,30 +5242,30 @@ for type Tuple = { ast::TopLevelDeclaration::Value(TopLevelValue { loc: (12, 4), is_op: false, - ident:"match_statement".to_owned(), + ident: "match_statement".to_owned(), args: vec![ArgDeclaration::Simple { loc: (12, 20), ident: "x".to_string(), ty: None, },], ty: Some(ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::UNIT.boxed(), + arg: types::INT32.into(), + returns: types::UNIT.into(), loc: (12, 30) }), value: ValueType::Function(vec![ast::Statement::Match(Match { loc: (13, 4), - on: ast::Expr::ValueRead("x".to_string(), (13, 10)).boxed(), + on: ast::Expr::ValueRead("x".to_string(), (13, 10)).into(), arms: vec![ MatchArm { block: vec![ast::Statement::FnCall(FnCall { loc: (15, 8), - value: ast::Expr::ValueRead("foo".to_string(), (15, 8)).boxed(), + value: ast::Expr::ValueRead("foo".to_string(), (15, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "0".to_string(), } - .boxed() + .into() ) })], ret: None, @@ -4824,12 +5275,12 @@ for type Tuple = { MatchArm { block: vec![ast::Statement::FnCall(FnCall { loc: (17, 8), - value: ast::Expr::ValueRead("bar".to_string(), (17, 8)).boxed(), + value: ast::Expr::ValueRead("bar".to_string(), (17, 8)).into(), arg: Some( ast::Expr::NumericLiteral { value: "1".to_string(), } - .boxed() + .into() ) })], ret: None, @@ -4841,16 +5292,15 @@ for type Tuple = { ret: Some( ast::Expr::FnCall(FnCall { loc: (18, 11), - value: ast::Expr::ValueRead("baz".to_string(), (18, 11)) - .boxed(), + value: ast::Expr::ValueRead("baz".to_string(), (18, 11)).into(), arg: Some( ast::Expr::NumericLiteral { value: "2".to_string(), } - .boxed() + .into() ) }) - .boxed() + .into() ), cond: Pattern::ConstNumber("3".to_string()), loc: (18, 6), @@ -4874,7 +5324,7 @@ let arr = [0,0,0,0]; ast::TopLevelDeclaration::Value(TopLevelValue { loc: (1, 4), is_op: false, - ident:"arr".to_owned(), + ident: "arr".to_owned(), args: Vec::new(), ty: None, value: ast::ValueType::Expr(ast::Expr::ArrayLiteral { @@ -4915,7 +5365,7 @@ extern "C" let ex (a:int32) b = a + b; ast::TopLevelDeclaration::Value(TopLevelValue { loc: (1, 15), is_op: false, - ident:"putchar".to_owned(), + ident: "putchar".to_owned(), args: Vec::new(), ty: Some(types::INT32.fn_ty(&types::INT32)), value: ValueType::External, @@ -4932,7 +5382,7 @@ extern "C" let ex (a:int32) b = a + b; ast::TopLevelDeclaration::Value(TopLevelValue { loc: (2, 15), is_op: false, - ident:"ex".to_owned(), + ident: "ex".to_owned(), args: vec![ ast::ArgDeclaration::Simple { loc: (2, 19), @@ -4948,8 +5398,8 @@ extern "C" let ex (a:int32) b = a + b; ty: None, value: ValueType::Expr(Expr::BinaryOpCall(BinaryOpCall { loc: (2, 34), - lhs: Expr::ValueRead("a".to_string(), (2, 32)).boxed(), - rhs: Expr::ValueRead("b".to_string(), (2, 36)).boxed(), + lhs: Expr::ValueRead("a".to_string(), (2, 32)).into(), + rhs: Expr::ValueRead("b".to_string(), (2, 36)).into(), operator: "+".to_string() })), generics: None, @@ -4979,8 +5429,11 @@ let cons a : int32 -> (int32,int32) = (a,0) &ast::TopLevelDeclaration::Value(TopLevelValue { loc: (1, 4), is_op: false, - ident:"ty".to_owned(), - args: vec![ArgDeclaration::Discard {ty:None,loc:(1,7)}], + ident: "ty".to_owned(), + args: vec![ArgDeclaration::Discard { + ty: None, + loc: (1, 7) + }], ty: Some( ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32], @@ -5001,7 +5454,7 @@ let cons a : int32 -> (int32,int32) = (a,0) &ast::TopLevelDeclaration::Value(TopLevelValue { loc: (3, 4), is_op: false, - ident:"cons".to_owned(), + ident: "cons".to_owned(), args: vec![ArgDeclaration::Simple { loc: (3, 9), ident: "a".to_string(), @@ -5030,22 +5483,14 @@ let cons a : int32 -> (int32,int32) = (a,0) #[test] fn match_patterns() { let pattern = Parser::from_source("a").collect_pattern().ast; - assert_eq!( - Pattern::Read("a".to_string(), (0,0)), - pattern, - "a" - ); + assert_eq!(Pattern::Read("a".to_string(), (0, 0)), pattern, "a"); let pattern = Parser::from_source("_").collect_pattern().ast; - assert_eq!( - Pattern::Default, - pattern, - "_" - ); + assert_eq!(Pattern::Default, pattern, "_"); let pattern = Parser::from_source("(a,b)").collect_pattern().ast; assert_eq!( Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("a".to_string(),(0,1)), - Pattern::Read("b".to_string(),(0,3)), + Pattern::Read("a".to_string(), (0, 1)), + Pattern::Read("b".to_string(), (0, 3)), ])), pattern, "destruct tuple" @@ -5053,8 +5498,8 @@ let cons a : int32 -> (int32,int32) = (a,0) let pattern = Parser::from_source("0 | 1").collect_pattern().ast; assert_eq!( Pattern::Or( - Pattern::ConstNumber("0".to_string()).boxed(), - Pattern::ConstNumber("1".to_string()).boxed(), + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), ), pattern, "or (0 or 1)" @@ -5062,11 +5507,12 @@ let cons a : int32 -> (int32,int32) = (a,0) let pattern = Parser::from_source("0 | 1 | 2").collect_pattern().ast; assert_eq!( Pattern::Or( - Pattern::ConstNumber("0".to_string()).boxed(), + Pattern::ConstNumber("0".to_string()).into(), Pattern::Or( - Pattern::ConstNumber("1".to_string()).boxed(), - Pattern::ConstNumber("2".to_string()).boxed(), - ).boxed() + Pattern::ConstNumber("1".to_string()).into(), + Pattern::ConstNumber("2".to_string()).into(), + ) + .into() ), pattern, "or (0 or 1 or 2)" @@ -5075,10 +5521,10 @@ let cons a : int32 -> (int32,int32) = (a,0) assert_eq!( Pattern::Destructure(PatternDestructure::Tuple(vec![ Pattern::Or( - Pattern::ConstNumber("0".to_string()).boxed(), - Pattern::ConstNumber("1".to_string()).boxed(), + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), ), - Pattern::Read("b".to_string(),(0,7)), + Pattern::Read("b".to_string(), (0, 7)), ])), pattern, "destruct tuple" @@ -5087,8 +5533,7 @@ let cons a : int32 -> (int32,int32) = (a,0) #[test] fn arg_types() { - const SRC : &'static str = -" + const SRC: &'static str = " let simple a = (); let decon_arg (a,b) = (); let discard _ = (); @@ -5097,123 +5542,118 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "; let ast = Parser::from_source(SRC).module("".to_string()).ast; - let [simple,decon,discard, unit, annotated_decon] = &ast.declarations[..] else {unreachable!()}; + let [simple, decon, discard, unit, annotated_decon] = &ast.declarations[..] else { + unreachable!() + }; assert_eq!( &TopLevelDeclaration::Value(TopLevelValue { - loc:(1,4), - is_op:false, - ident:"simple".to_owned(), - args:vec![ - ArgDeclaration::Simple { - loc: (1,11), - ident: "a".to_string(), - ty: None, - }, - ], - ty:None, - value:ValueType::Expr(Expr::UnitLiteral), - generics:None, - abi:None, + loc: (1, 4), + is_op: false, + ident: "simple".to_owned(), + args: vec![ArgDeclaration::Simple { + loc: (1, 11), + ident: "a".to_string(), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, }), simple, "let simple a = ();" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue{ - loc:(2,4), - is_op:false, - ident:"decon_arg".to_owned(), - args:vec![ - ArgDeclaration::DestructureTuple(vec![ + &TopLevelDeclaration::Value(TopLevelValue { + loc: (2, 4), + is_op: false, + ident: "decon_arg".to_owned(), + args: vec![ArgDeclaration::DestructureTuple( + vec![ ArgDeclaration::Simple { - loc: (2,15), + loc: (2, 15), ident: "a".to_string(), - ty: None, + ty: None, }, ArgDeclaration::Simple { - loc: (2,17), + loc: (2, 17), ident: "b".to_string(), - ty: None, + ty: None, }, - - ], None, (2,14)), - ], - ty:None, - value:ValueType::Expr(Expr::UnitLiteral), - generics:None, - abi:None, + ], + None, + (2, 14) + ),], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, }), decon, "let decon_arg (a,b) = ()" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue{ - loc:(3,4), - is_op:false, - ident:"discard".to_owned(), - args:vec![ - ArgDeclaration::Discard{ - loc: (3,12), - ty: None, - }, - ], - ty:None, - value:ValueType::Expr(Expr::UnitLiteral), - generics:None, - abi:None, + &TopLevelDeclaration::Value(TopLevelValue { + loc: (3, 4), + is_op: false, + ident: "discard".to_owned(), + args: vec![ArgDeclaration::Discard { + loc: (3, 12), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, }), discard, "let discard _ = ();" ); assert_eq!( &TopLevelDeclaration::Value(TopLevelValue { - loc:(4,4), - is_op:false, - ident:"unit".to_owned(), - args:vec![ - ArgDeclaration::Unit { - loc:(4,9), - ty: None, - }, - ], - ty:None, - value:ValueType::Expr(Expr::UnitLiteral), - generics:None, - abi:None, + loc: (4, 4), + is_op: false, + ident: "unit".to_owned(), + args: vec![ArgDeclaration::Unit { + loc: (4, 9), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, }), unit, "let unit () = ();" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue{ - loc:(5,4), - is_op:false, - ident:"annotated_arg_tuple".to_owned(), - args:vec![ - ArgDeclaration::DestructureTuple(vec![ + &TopLevelDeclaration::Value(TopLevelValue { + loc: (5, 4), + is_op: false, + ident: "annotated_arg_tuple".to_owned(), + args: vec![ArgDeclaration::DestructureTuple( + vec![ ArgDeclaration::Simple { - loc: (5,26), + loc: (5, 26), ident: "x".to_string(), - ty: None, + ty: None, }, ArgDeclaration::Simple { - loc: (5,28), + loc: (5, 28), ident: "y".to_string(), - ty: None, + ty: None, }, - ], - Some(ResolvedType::Tuple { - underlining: vec![ - types::INT32, - types::INT32, - ], - loc: (5,31) - }), (5,25)), - ], - ty:None, - value:ValueType::Expr(Expr::UnitLiteral), - generics:None, - abi:None, + ], + Some(ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (5, 31) + }), + (5, 25) + ),], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, }), annotated_decon, "let annotated_arg_tuple ((x,y):(int32,int32)) = ();" @@ -5221,84 +5661,264 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); } #[test] fn destructuring_statement() { - let mut parser = super::Parser::from_source(" + let mut parser = super::Parser::from_source( + " let (x,y) = v; let ((x,y),z) = v; let (x,y,z) = v; let (x,y):(int32,int32) = v; //yes this will all fail typecheking. -"); +", + ); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (1,4), - is_op: false, - target:Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (1,5)), - Pattern::Read("y".to_string(), (1,7)), - ])), - args:Vec::new(), - ty:None, - value:ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (1,12))), - generictypes: None, + Statement::Declaration(ValueDeclaration { + loc: (1, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (1, 5)), + Pattern::Read("y".to_string(), (1, 7)), + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (1, 12))), + generictypes: None, abi: None, }), parser.next_statement().ast ); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (2,4), - is_op: false, - target:Pattern::Destructure(PatternDestructure::Tuple(vec![ + Statement::Declaration(ValueDeclaration { + loc: (2, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (2,6)), - Pattern::Read("y".to_string(), (2,8)), + Pattern::Read("x".to_string(), (2, 6)), + Pattern::Read("y".to_string(), (2, 8)), ])), - Pattern::Read("z".to_string(), (2,11)) - ])), - args:Vec::new(), - ty:None, - value:ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (2,16))), - generictypes: None, + Pattern::Read("z".to_string(), (2, 11)) + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (2, 16))), + generictypes: None, abi: None, }), parser.next_statement().ast ); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (3,4), - is_op: false, - target:Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (3,5)), - Pattern::Read("y".to_string(), (3,7)), - Pattern::Read("z".to_string(), (3,9)), - ])), - args:Vec::new(), - ty:None, - value:ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (3,14))), - generictypes: None, + Statement::Declaration(ValueDeclaration { + loc: (3, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (3, 5)), + Pattern::Read("y".to_string(), (3, 7)), + Pattern::Read("z".to_string(), (3, 9)), + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (3, 14))), + generictypes: None, abi: None, }), parser.next_statement().ast ); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (4,4), - is_op: false, - target:Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (4,5)), - Pattern::Read("y".to_string(), (4,7)), - ])), - args:Vec::new(), - ty:Some(ResolvedType::Tuple{ - underlining:vec![types::INT32,types::INT32], - loc:(4,10), - }), - value:ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (4,26))), - generictypes: None, + Statement::Declaration(ValueDeclaration { + loc: (4, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (4, 5)), + Pattern::Read("y".to_string(), (4, 7)), + ])), + args: Vec::new(), + ty: Some(ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32], + loc: (4, 10), + }), + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (4, 26))), + generictypes: None, abi: None, }), parser.next_statement().ast ); } + + #[test] + fn enums() { + const SRC: &'static str = " +enum Basic = | None | AnInt int32 | Struct { a: int32 } +for enum Option = | Some T | None +for enum Result = | Ok T | Err E +"; + let mut parser = Parser::from_source(SRC); + let basic = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Basic".to_string(), + generics: None, + values: vec![ + EnumVariant::Unit { + ident: "None".to_string(), + loc: (1, 15) + }, + EnumVariant::Tuple { + ident: "AnInt".to_string(), + loc: (1, 22), + ty: types::INT32 + }, + EnumVariant::Struct { + ident: "Struct".to_string(), + fields: vec![FieldDecl { + name: "a".to_string(), + ty: types::INT32, + loc: (1, 45) + }], + loc: (1, 36) + } + ], + loc: (1, 5), + })), + basic, + "basic: enum Basic = | None | AnInt int32 | Struct {{ a: int32 }}" + ); + let option = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Option".to_string(), + generics: Some(GenericsDecl { + for_loc: (2, 0), + decls: vec![((2, 4), "T".to_string())] + }), + values: vec![ + EnumVariant::Tuple { + ident: "Some".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (2, 28) + }, + loc: (2, 23) + }, + EnumVariant::Unit { + ident: "None".to_string(), + loc: (2, 32) + } + ], + loc: (2, 12) + })), + option, + "option: for enum Option = | Some T | None" + ); + + let result = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Result".to_string(), + generics: Some(GenericsDecl { + for_loc: (3, 0), + decls: vec![((3, 4), "T".to_string()), ((3, 6), "E".to_string()),] + }), + values: vec![ + EnumVariant::Tuple { + ident: "Ok".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (3, 28) + }, + loc: (3, 25) + }, + EnumVariant::Tuple { + ident: "Err".to_string(), + ty: ResolvedType::Generic { + name: "E".to_string(), + loc: (3, 35) + }, + loc: (3, 32) + }, + ], + loc: (3, 14) + })), + result, + "result: for enum Result = | Ok T | Err E" + ); + + assert!(!parser.has_next()); + } + + #[test] + fn enum_patterns() { + const SRC: &'static str = r#" +match a where +| Enum::Complex { a: 0, b } -> b, // TODO! struct patterns +// | Enum::Complex c -> c.a // TODO! struct access. +| Enum::Simple (0 | 1) -> 0, +| Simple a -> a, +"#; + let ast = Parser::from_source(SRC).match_().ast; + + assert_eq!( + ast::Match { + loc: (1, 0), + on: ast::Expr::ValueRead("a".to_string(), (1, 6)).into(), + arms: vec![ + MatchArm { + block: Vec::new(), + ret: Some(ast::Expr::ValueRead("b".to_string(), (2, 31)).into()), + cond: Pattern::EnumVariant { + ty: Some("Enum".to_string()), + variant: "Complex".to_string(), + pattern: Some( + Pattern::Destructure(PatternDestructure::Struct { + base_ty: None, + fields: [ + ("a".to_string(), Pattern::ConstNumber("0".to_string())), + ("b".to_string(), Pattern::Read("b".to_string(), (2, 24))), + ] + .into(), + }) + .into() + ), + loc: (2, 2) + }, + loc: (2, 2), + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "0".to_string() + } + .into() + ), + cond: Pattern::EnumVariant { + ty: Some("Enum".to_string()), + variant: "Simple".to_string(), + pattern: Some( + Pattern::Or( + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), + ) + .into() + ), + loc: (4, 2) + }, + loc: (4, 2), + }, + MatchArm { + block: Vec::new(), + ret: Some(ast::Expr::ValueRead("a".to_string(), (5, 14)).into()), + cond: Pattern::EnumVariant { + ty: None, + variant: "Simple".to_string(), + pattern: Some(Pattern::Read("a".to_string(), (5, 9)).into()), + loc: (5, 2) + }, + loc: (5, 2), + }, + ], + }, + ast, + "match" + ); + } } diff --git a/compiler/src/tokens.rs b/compiler/src/tokens.rs index f797da4..ee483db 100644 --- a/compiler/src/tokens.rs +++ b/compiler/src/tokens.rs @@ -45,6 +45,7 @@ pub enum Token { BeginBlock, EndBlock, EoF, + Scope, Error(&'static str /*reason*/), } diff --git a/compiler/src/typed_ast.rs b/compiler/src/typed_ast.rs index 3ca950f..e18dddc 100644 --- a/compiler/src/typed_ast.rs +++ b/compiler/src/typed_ast.rs @@ -1,15 +1,15 @@ use itertools::Itertools; -use std::{collections::{HashMap, HashSet}, num::NonZeroU8}; +use std::{ + collections::{HashMap, HashSet}, + num::NonZeroU8, +}; use thiserror::Error; use crate::{ - inference::ast::{self, TopLevelDeclaration, Expr}, + inference::ast::{self, Expr, TopLevelDeclaration}, types::{self, FloatWidth, IntWidth, ResolvedType}, - util::ExtraUtilFunctions, }; - - pub type FileTyped = TypedModuleDeclaration; pub type ProgramTyped = Vec; #[derive(Debug, PartialEq, Clone)] @@ -31,7 +31,19 @@ impl TypedModuleDeclaration { match it { TopLevelDeclaration::Type(decl) => match decl { ast::TypeDefinition::Alias(name, value) => Some((name.clone(), value.clone())), - ast::TypeDefinition::Enum(_) => todo!(), + ast::TypeDefinition::Enum(enum_) => Some(( + name.clone(), + ResolvedType::User { + name: enum_.ident.clone(), + generics: enum_ + .generics + .clone() + .map(ResolvedGenericsDecl::from) + .map(|g| g.decls.into_iter().map(|(_, ty)| ty).collect()) + .unwrap_or_else(Vec::new), + loc: enum_.loc, + }, + )), ast::TypeDefinition::Struct(strct) => Some(( strct.ident.clone(), ResolvedType::User { @@ -61,14 +73,87 @@ impl TypedModuleDeclaration { _ => None, }) .collect(); - let types: HashMap = decls + let mut types: HashMap = HashMap::new(); + // decls + // .iter() + // .filter_map::<(String, ast::TypeDefinition), _>(|it| match it { + + // ast::TopLevelDeclaration::Type(def) => Some((def.get_ident(), def.clone())), + // _ => None, + // }) + // .collect(); + for def in decls .iter() - .filter_map::<(String, ast::TypeDefinition), _>(|it| match it { - ast::TopLevelDeclaration::Type(def) => Some((def.get_ident(), def.clone())), - _ => None, - }) - .collect(); - + .filter(|it| matches!(it, ast::TopLevelDeclaration::Type(_))) + { + let ast::TopLevelDeclaration::Type(def) = def else { + unreachable!() + }; + match def { + ast::TypeDefinition::Alias(_, _resolved_type) => unreachable!(), //should be resolved at cannonizing + ast::TypeDefinition::Enum(enum_declaration) => { + let base = + ResolvedTypeDeclaration::try_from(def.clone(), &fwd_declares).unwrap(); + let generics = if let ResolvedTypeDeclaration::Enum(e) = &base { + e.generics.clone() + } else { + unreachable!() + }; + for variant in &enum_declaration.values { + match variant { + crate::ast::EnumVariant::Unit { ident, loc } => { + types.insert( + format!("{}::{}", &enum_declaration.ident, &ident), + ResolvedTypeDeclaration::Dependent { + base: base.clone().into(), + actual: ResolvedTypeDeclaration::Alias( + ident.clone(), + ResolvedType::Void, + ) + .into(), + }, + ); + } + crate::ast::EnumVariant::Tuple { ident, ty, loc } => { + types.insert( + format!("{}::{}", &enum_declaration.ident, &ident), + ResolvedTypeDeclaration::Dependent { + base: base.clone().into(), + actual: ResolvedTypeDeclaration::Alias( + ident.clone(), + ty.clone(), + ) + .into(), + }, + ); + } + crate::ast::EnumVariant::Struct { ident, fields, loc } => { + types.insert( + format!("{}::{}", &enum_declaration.ident, &ident), + ResolvedTypeDeclaration::Dependent { + base: base.clone().into(), + actual: ResolvedTypeDeclaration::Struct(StructDefinition { + ident: ident.clone(), + generics: generics.clone(), + fields: fields.clone(), + loc: *loc, + }) + .into(), + }, + ); + } + } + } + types.insert(enum_declaration.ident.clone(), base); + } + ast::TypeDefinition::Struct(struct_definition) => { + types.insert( + struct_definition.ident.clone(), + ResolvedTypeDeclaration::try_from(def.clone(), &fwd_declares).unwrap(), + ); + } + } + } Self { loc, name, @@ -77,7 +162,7 @@ impl TypedModuleDeclaration { .map(|decl| { TypedDeclaration::try_from(decl, &externs, &fwd_declares, operators, &types) }) - .filter_map(|decl| match decl { + .filter_map(|decl: Result| match decl { Ok(decl) => Some(decl), Err(e) => { println!("{:?}", e); @@ -103,11 +188,12 @@ impl TypedModuleDeclaration { args: Vec::new(), }; self.declarations - .iter_mut() - .filter(|it| it.get_generics().is_empty()) + .iter_mut() + .filter(|it| it.get_generics().is_empty()) .for_each(|it| it.lower_generics(&mut context)); self.declarations .extend(context.generated_generics.into_iter().map(|(_, it)| it)); + // println!("{:?}", self.declarations) } } @@ -143,7 +229,7 @@ impl TypedDeclaration { Self::TypeDefinition(decl) => decl.get_ident(), } } - + pub fn is_generic(&self) -> bool { match self { Self::Value(v) => v.ty.is_generic(), @@ -156,7 +242,7 @@ impl TypedDeclaration { known_externs: &HashMap, known_values: &HashMap, known_ops: &HashMap>, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { match data { TopLevelDeclaration::Value(decl) => Ok(Self::Value(TypedTopLevelValue::try_from( @@ -166,7 +252,6 @@ impl TypedDeclaration { known_ops, known_types, )?)), - TopLevelDeclaration::Value(_)=>todo!(), TopLevelDeclaration::Type(define) => Ok(Self::TypeDefinition( ResolvedTypeDeclaration::try_from(define, known_values)?, )), @@ -183,13 +268,13 @@ impl TypedDeclaration { TypedDeclaration::TypeDefinition(strct) => strct.replace_types(types, context), }; } - + pub(crate) fn get_generics(&self) -> Vec { match self { TypedDeclaration::Value(v) => v - .generics - .as_ref() - .map(|g| { + .generics + .as_ref() + .map(|g| { g.decls .iter() .map(|(_, it)| { @@ -213,26 +298,25 @@ impl TypedDeclaration { } } - #[derive(Debug, PartialEq, Clone)] pub struct TypedTopLevelValue { - pub loc : crate::Location, + pub loc: crate::Location, pub is_op: bool, - pub ident : String, - pub args : Vec, + pub ident: String, + pub args: Vec, pub ty: ResolvedType, - pub value : TypedValueType, - pub generics : Option, - pub abi : Option, + pub value: TypedValueType, + pub generics: Option, + pub abi: Option, } impl TypedTopLevelValue { fn try_from( - value : ast::TopLevelValue, + value: ast::TopLevelValue, known_externs: &HashMap, known_values: &HashMap, _known_ops: &HashMap>, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { let ast::TopLevelValue { loc, @@ -243,21 +327,20 @@ impl TypedTopLevelValue { value, generics, abi, - id, + id: _, } = value; let mut known_values = known_values.clone(); - let args = args.into_iter().map(TypedArgDeclaration::from).collect_vec(); + let args = args + .into_iter() + .map(TypedArgDeclaration::from) + .collect_vec(); known_values.extend( args.iter() - .flat_map(|arg| arg.get_idents_with_types(known_types)) + .flat_map(|arg| arg.get_idents_with_types(known_types)), ); - let value = match TypedValueType::try_from( - value, - known_externs, - &known_values, - known_types - ) { - Ok(value)=>value, + let value = match TypedValueType::try_from(value, known_externs, &known_values, known_types) + { + Ok(value) => value, Err(e) => { println!("{:?}", e); TypedValueType::Err @@ -275,23 +358,25 @@ impl TypedTopLevelValue { } } } - Ok(Self{ + Ok(Self { loc, is_op, ident, args, ty, value, - generics:generics.map(ResolvedGenericsDecl::from), - abi + generics: generics.map(ResolvedGenericsDecl::from), + abi, }) } - pub(crate) fn replace_types(&mut self,types:&[(String,ResolvedType)]) { + pub(crate) fn replace_types(&mut self, types: &[(String, ResolvedType)]) { for arg in &mut self.args { arg.replace_types(types); } - self.ty = types.iter().fold(self.ty.clone(), |ty,(name,new_ty)| ty.replace_generic(name,new_ty.clone())); + self.ty = types.iter().fold(self.ty.clone(), |ty, (name, new_ty)| { + ty.replace_generic(name, new_ty.clone()) + }); match &mut self.value { TypedValueType::Function(stmnts) => stmnts .into_iter() @@ -300,10 +385,10 @@ impl TypedTopLevelValue { TypedValueType::External | TypedValueType::Err => (), } } - pub(crate) fn lower_generics(&mut self, context:&mut LoweringContext) { + pub(crate) fn lower_generics(&mut self, context: &mut LoweringContext) { self.ty.lower_generics(context); match &mut self.value { - TypedValueType::Expr(expr)=> expr.lower_generics(context), + TypedValueType::Expr(expr) => expr.lower_generics(context), TypedValueType::Function(stmnts) => { for stmnt in stmnts { context.args.clear(); @@ -319,10 +404,40 @@ impl TypedTopLevelValue { #[derive(Debug, PartialEq, Clone)] #[non_exhaustive] pub enum ResolvedTypeDeclaration { - // Alias(String, ResolvedType), - // Enum(String, Vec, crate::Location), + Alias(String, ResolvedType), + Enum(TypedEnumDeclaration), Struct(StructDefinition), + Dependent { base: Box, actual: Box }, } + +impl Into for &ResolvedTypeDeclaration { + fn into(self) -> ResolvedType { + match self { + ResolvedTypeDeclaration::Alias(_, resolved_type) => resolved_type.clone(), + ResolvedTypeDeclaration::Enum(TypedEnumDeclaration { + ident, + loc, + generics, + .. + }) + | ResolvedTypeDeclaration::Struct(StructDefinition { + ident, + loc, + generics, + .. + }) => ResolvedType::User { + name: ident.clone(), + generics: generics + .as_ref() + .map(|generics| generics.decls.iter().map(|(_, it)| it).cloned().collect()) + .unwrap_or_default(), + loc: *loc, + }, + ResolvedTypeDeclaration::Dependent { base, actual } => actual.as_ref().into(), + } + } +} + impl ResolvedTypeDeclaration { fn try_from( origin: ast::TypeDefinition, @@ -330,7 +445,7 @@ impl ResolvedTypeDeclaration { ) -> Result { match origin { // ast::TypeDefinition::Alias(new, old) => Ok(Self::Alias(new, old)), - ast::TypeDefinition::Enum(_) => todo!(), + ast::TypeDefinition::Enum(enum_) => Ok(ResolvedTypeDeclaration::Enum(enum_.into())), ast::TypeDefinition::Struct(strct) => Ok(ResolvedTypeDeclaration::Struct( StructDefinition::try_from(strct, known_types)?, )), @@ -360,18 +475,47 @@ impl ResolvedTypeDeclaration { // } // _ => (), // }, + ResolvedTypeDeclaration::Dependent { base, actual } => { + base.lower_generics(context); //gonna leave this here just in case. should be covered by the other branches but better safe than sorry + actual.lower_generics(context); + } + ResolvedTypeDeclaration::Alias(_, ty) => { + ty.lower_generics(context); + } + ResolvedTypeDeclaration::Enum(enum_) => enum_.lower_generics(context), ResolvedTypeDeclaration::Struct(stct) => stct.lower_generics(context), } } fn get_ident(&self) -> String { match self { + ResolvedTypeDeclaration::Alias(ident, _) => ident.clone(), + ResolvedTypeDeclaration::Dependent { actual, .. } => actual.get_ident(), + ResolvedTypeDeclaration::Enum(enum_) => enum_.ident.clone(), ResolvedTypeDeclaration::Struct(strct) => strct.ident.clone(), } } fn get_generics(&self) -> Vec { match self { + //todo! generic aliases + ResolvedTypeDeclaration::Alias(_, _) => Vec::new(), + ResolvedTypeDeclaration::Dependent { actual, .. } => actual.get_generics(), + ResolvedTypeDeclaration::Enum(enum_) => enum_ + .generics + .as_ref() + .map(|g| { + g.decls + .iter() + .map(|(_, name)| { + let ResolvedType::Generic { name, .. } = name else { + unreachable!() + }; + name.clone() + }) + .collect() + }) + .unwrap_or_else(Vec::new), ResolvedTypeDeclaration::Struct(strct) => strct .generics .as_ref() @@ -392,13 +536,128 @@ impl ResolvedTypeDeclaration { fn replace_types(&mut self, types: &[(String, ResolvedType)], context: &mut LoweringContext) { match self { + ResolvedTypeDeclaration::Alias(_, _ty) => (), // do i need to do something here? + ResolvedTypeDeclaration::Dependent { base, actual } => { + base.replace_types(types, context); + actual.replace_types(types, context); + } + ResolvedTypeDeclaration::Enum(enum_) => enum_.replace_types(types, context), ResolvedTypeDeclaration::Struct(strct) => strct.replace_types(types, context), } } fn is_generic(&self) -> bool { match self { - Self::Struct(strct) => strct.generics.is_none(), + Self::Alias(_, _) => false, //todo! generic aliases + Self::Dependent { base, .. } => base.is_generic(), + Self::Enum(enum_) => enum_.generics.is_some(), + Self::Struct(strct) => strct.generics.is_some(), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct TypedEnumDeclaration { + pub ident: String, + pub generics: Option, + pub values: Vec, + pub loc: crate::Location, +} +impl TypedEnumDeclaration { + fn lower_generics(&mut self, context: &mut LoweringContext) { + if self.generics.is_none() { + for value in &mut self.values { + match value { + crate::ast::EnumVariant::Unit { .. } => (), + crate::ast::EnumVariant::Tuple { ty, .. } => ty.lower_generics(context), + crate::ast::EnumVariant::Struct { fields, .. } => { + for field in fields { + field.ty.lower_generics(context); + } + } + } + } + } + } + + fn replace_types(&mut self, types: &[(String, ResolvedType)], context: &mut LoweringContext) { + if self.generics.is_none() { + return; + } + + let generics = self + .generics + .as_ref() + .unwrap() + .decls + .iter() + .cloned() + .filter(|(_, it)| match it { + ResolvedType::Generic { name, .. } => !types.iter().map(|(n, _)| n).contains(name), + _ => true, + }) + .collect::>(); + assert_eq!( + generics.len(), + 0, + "generic not completed. should not be reached!" + ); + self.generics = None; + self.ident = format!( + "{}<{}>", + self.ident, + types.iter().map(|(_, it)| it.to_string()).join(",") + ); + for value in &mut self.values { + match value { + crate::ast::EnumVariant::Unit { .. } => (), + crate::ast::EnumVariant::Tuple { ty, .. } => { + *ty = types.iter().fold(ty.clone(), |old_ty, (name, new_ty)| { + old_ty.replace_generic(name, new_ty.clone()) + }); + ty.lower_generics(context); + } + crate::ast::EnumVariant::Struct { fields, .. } => { + for field in fields { + field.ty = types.iter().fold(field.ty.clone(), |old_ty, ty| { + old_ty.replace_generic(&ty.0, ty.1.clone()) + }); + field.ty.lower_generics(context); + } + } + } + } + } +} + +impl From for TypedEnumDeclaration { + fn from(data: crate::ast::EnumDeclaration) -> Self { + let crate::ast::EnumDeclaration { + ident, + generics, + mut values, + loc, + } = data; + if let Some(generics) = &generics { + for (_, generic) in &generics.decls { + values.iter_mut().for_each(|variant| match variant { + crate::ast::EnumVariant::Unit { .. } => (), + crate::ast::EnumVariant::Tuple { ty, .. } => { + *ty = ty.clone().replace_user_with_generic(generic) + } + crate::ast::EnumVariant::Struct { fields, .. } => { + for field in fields { + field.ty = field.ty.clone().replace_user_with_generic(&generic); + } + } + }) + } + } + Self { + ident, + generics: generics.map(ResolvedGenericsDecl::from), + values, + loc, } } } @@ -422,6 +681,7 @@ impl StructDefinition { mut values, loc, } = data; + if let Some(generics) = &generics { for (_, generic) in &generics.decls { values.iter_mut().for_each(|field| { @@ -487,7 +747,7 @@ impl StructDefinition { pub struct TypedValueDeclaration { pub loc: crate::Location, pub is_op: bool, - pub target : TypedPattern, + pub target: TypedPattern, pub args: Vec, pub value: TypedValueType, pub ty: ResolvedType, @@ -526,7 +786,7 @@ impl TypedValueDeclaration { data: ast::ValueDeclaration, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { let ast::ValueDeclaration { loc, @@ -540,10 +800,13 @@ impl TypedValueDeclaration { id: _, } = data; let mut known_values = known_values.clone(); - let args = args.into_iter().map(TypedArgDeclaration::from).collect_vec(); + let args = args + .into_iter() + .map(TypedArgDeclaration::from) + .collect_vec(); known_values.extend( args.iter() - .flat_map(|arg| arg.get_idents_with_types(known_types)) + .flat_map(|arg| arg.get_idents_with_types(known_types)), ); let value = match TypedValueType::try_from(value, known_externs, &known_values, known_types) { @@ -553,7 +816,7 @@ impl TypedValueDeclaration { TypedValueType::Err } }; - let target = TypedPattern::from(target, &ty); + let target = TypedPattern::from(target, &ty, known_types); if let Some(abi) = &abi { if abi.identifier.as_str() == "C" { if let ResolvedType::Function { @@ -595,47 +858,65 @@ impl TypedValueDeclaration { } #[derive(Debug, PartialEq, Clone)] -pub enum TypedArgDeclaration{ +pub enum TypedArgDeclaration { Simple { - loc : crate::Location, + loc: crate::Location, ident: String, - ty:ResolvedType, + ty: ResolvedType, }, - DestructureTuple(Vec,ResolvedType, crate::Location), + DestructureTuple(Vec, ResolvedType, crate::Location), DestructureStruct { - loc:crate::Location, - struct_ident : String, - fields : Vec, - renamed_fields : HashMap + loc: crate::Location, + struct_ident: String, + fields: Vec, + renamed_fields: HashMap, }, Discard { - loc:crate::Location, - ty:ResolvedType, + loc: crate::Location, + ty: ResolvedType, + }, + Unit { + loc: crate::Location, + ty: ResolvedType, }, - Unit { loc:crate::Location, ty : ResolvedType }, } impl From for TypedArgDeclaration { fn from(value: crate::inference::ast::ArgDeclaration) -> Self { match value { - ast::ArgDeclaration::Simple { loc, ident, ty, id:_ } => Self::Simple { loc, ident, ty }, - ast::ArgDeclaration::DestructureTuple(contents, ty, loc) => Self::DestructureTuple(contents.into_iter().map(|it| it.into()).collect(), ty, loc), - ast::ArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } => Self::DestructureStruct { loc, struct_ident, fields, renamed_fields }, + ast::ArgDeclaration::Simple { + loc, + ident, + ty, + id: _, + } => Self::Simple { loc, ident, ty }, + ast::ArgDeclaration::DestructureTuple(contents, ty, loc) => { + Self::DestructureTuple(contents.into_iter().map(|it| it.into()).collect(), ty, loc) + } + ast::ArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => Self::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + }, ast::ArgDeclaration::Discard { loc, ty } => Self::Discard { loc, ty }, - ast::ArgDeclaration::Unit { loc, ty } => Self::Unit { loc, ty } + ast::ArgDeclaration::Unit { loc, ty } => Self::Unit { loc, ty }, } } } impl TypedArgDeclaration { pub fn get_loc(&self) -> crate::Location { - let ( - Self::Simple { loc, .. } - | Self::DestructureStruct { loc, .. } - | Self::DestructureTuple(_, _, loc) - | Self::Discard { loc, .. } - | Self::Unit { loc, .. } - ) = self; + let (Self::Simple { loc, .. } + | Self::DestructureStruct { loc, .. } + | Self::DestructureTuple(_, _, loc) + | Self::Discard { loc, .. } + | Self::Unit { loc, .. }) = self; *loc } pub fn get_ident(&self) -> String { @@ -648,23 +929,31 @@ impl TypedArgDeclaration { } } - fn get_idents_with_types(&self, known_types : &HashMap) -> HashMap { + fn get_idents_with_types( + &self, + known_types: &HashMap, + ) -> HashMap { match self { - Self::Unit { .. } - | Self::Discard { .. } - => HashMap::new(), - Self::DestructureTuple(contents, _, _) => { - contents.iter().flat_map(|it| it.get_idents_with_types(known_types)).collect() - } - Self::DestructureStruct { loc:_, struct_ident, fields, renamed_fields } => { - let error_struct = crate::ast::StructDefinition { - ident : "".to_string(), - generics:None, - values:Vec::new(), - loc:(0,0), + // TODO! enum destructure. + Self::Unit { .. } | Self::Discard { .. } => HashMap::new(), + Self::DestructureTuple(contents, _, _) => contents + .iter() + .flat_map(|it| it.get_idents_with_types(known_types)) + .collect(), + Self::DestructureStruct { + loc: _, + struct_ident, + fields, + renamed_fields, + } => { + let error_struct = StructDefinition { + ident: "".to_string(), + generics: None, + fields: Vec::new(), + loc: (0, 0), }; let struct_ty = if let Some(typ) = known_types.get(struct_ident) { - if let ast::TypeDefinition::Struct(typ) = typ { + if let ResolvedTypeDeclaration::Struct(typ) = typ { typ } else { &error_struct @@ -672,39 +961,66 @@ impl TypedArgDeclaration { } else { &error_struct }; - let mut out : HashMap<_,_> = fields.iter().map(|ident| { - ( - ident.clone(), - struct_ty.values.iter().find_map(|field| if &field.name == ident { Some(field.ty.clone()) } else { None }).unwrap_or(types::ERROR) - ) - }).collect(); - for (old,new) in renamed_fields { + let mut out: HashMap<_, _> = fields + .iter() + .map(|ident| { + ( + ident.clone(), + struct_ty + .fields + .iter() + .find_map(|field| { + if &field.name == ident { + Some(field.ty.clone()) + } else { + None + } + }) + .unwrap_or(types::ERROR), + ) + }) + .collect(); + for (old, new) in renamed_fields { if new != "_" { out.insert( new.clone(), - struct_ty.values.iter().find_map(|field| if &field.name == old { Some(field.ty.clone()) } else { None }).unwrap_or(types::ERROR) + struct_ty + .fields + .iter() + .find_map(|field| { + if &field.name == old { + Some(field.ty.clone()) + } else { + None + } + }) + .unwrap_or(types::ERROR), ); } } out } - Self::Simple { loc:_, ident, ty } => { - [(ident.clone(),ty.clone())].into() - } + Self::Simple { loc: _, ident, ty } => [(ident.clone(), ty.clone())].into(), } } - fn replace_types(&mut self, types : &[(String,ResolvedType)]) { + fn replace_types(&mut self, types: &[(String, ResolvedType)]) { match self { - TypedArgDeclaration::Simple { ty, .. } - | TypedArgDeclaration::DestructureTuple(_, ty, _) + TypedArgDeclaration::Simple { ty, .. } + | TypedArgDeclaration::DestructureTuple(_, ty, _) | TypedArgDeclaration::Unit { ty, .. } - | TypedArgDeclaration::Discard { ty, .. } - => *ty = - types.iter() - .fold(ty.clone(),|accum,(old,new)| accum.replace_generic(old, new.clone())), + | TypedArgDeclaration::Discard { ty, .. } => { + *ty = types.iter().fold(ty.clone(), |accum, (old, new)| { + accum.replace_generic(old, new.clone()) + }) + } - TypedArgDeclaration::DestructureStruct { loc, struct_ident, fields, renamed_fields } => (), + TypedArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => (), } } } @@ -722,7 +1038,7 @@ impl TypedValueType { data: ast::ValueType, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { match data { ast::ValueType::Expr(expr) => { @@ -737,7 +1053,8 @@ impl TypedValueType { { Ok(stmnt) => { if let TypedStatement::Declaration(data) = &stmnt { - known_values.extend(data.target.get_idents_with_types());} + known_values.extend(data.target.get_idents_with_types()); + } output.push(stmnt); } Err(e) => { @@ -816,7 +1133,7 @@ impl TypedStatement { statement: ast::Statement, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { match statement { ast::Statement::Declaration(data) => Ok( @@ -916,7 +1233,7 @@ impl TypedIfBranching { value: ast::IfBranching, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Self { let ast::IfBranching { cond, @@ -948,7 +1265,7 @@ impl TypedIfBranching { TypedExpr::ErrorNode } } - .boxed(); + .into(); let true_branch = { let mut output = Vec::with_capacity(true_branch.len()); @@ -1018,7 +1335,7 @@ impl TypedIfBranching { } block }; - (cond.boxed(), block) + (cond.into(), block) }) .collect(); @@ -1114,7 +1431,7 @@ impl TypedFnCall { data: ast::FnCall, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { let ast::FnCall { loc, @@ -1157,9 +1474,9 @@ impl TypedFnCall { }; Ok(Self { loc, - value: value.boxed(), + value: value.into(), arg_t: arg.get_ty(), - arg: Some(arg.boxed()), + arg: Some(arg.into()), rt: returns, is_extern, }) @@ -1222,7 +1539,7 @@ impl TypedStructConstruction { data: ast::StructConstruction, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { let ast::StructConstruction { loc, @@ -1234,7 +1551,15 @@ impl TypedStructConstruction { } = data; let mut new_fields = HashMap::new(); let declaration = match known_types.get(&ident) { - Some(ast::TypeDefinition::Struct(decl)) => decl, + Some(ResolvedTypeDeclaration::Struct(decl)) => decl, + Some(ResolvedTypeDeclaration::Dependent { actual, .. }) => { + if let ResolvedTypeDeclaration::Struct(decl) = actual.as_ref() { + decl + } else { + println!("not a struct declaration"); + return Err(TypingError::UnknownType); + } + } Some(_) => { println!("not a struct declaration"); return Err(TypingError::UnknownType); @@ -1264,7 +1589,7 @@ impl TypedStructConstruction { } }; if field.get_ty() != ResolvedType::Error { - if let Some(old_field) = declaration.values.iter().find(|it| it.name == name) { + if let Some(old_field) = declaration.fields.iter().find(|it| it.name == name) { if old_field.ty == field.get_ty() || old_field.ty.is_generic() { new_fields.insert(name, (field, loc)); } else { @@ -1355,7 +1680,7 @@ pub enum TypedExpr { /// not recommended above 3 values TupleLiteral { contents: Vec, - loc:crate::Location, + loc: crate::Location, }, StructConstruction(TypedStructConstruction), @@ -1373,15 +1698,23 @@ impl TypedExpr { value: ast::Expr, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, already_processed_args: Vec, ) -> Result { match value { - Expr::TupleLiteral { contents, loc, id:_ }=> { - Ok(Self::TupleLiteral { contents: contents.into_iter().map(|expr| { - Self::try_from(expr, known_externs, known_values, known_types, Vec::new()) - }).collect::,_>>()?, loc }) - }, + Expr::TupleLiteral { + contents, + loc, + id: _, + } => Ok(Self::TupleLiteral { + contents: contents + .into_iter() + .map(|expr| { + Self::try_from(expr, known_externs, known_values, known_types, Vec::new()) + }) + .collect::, _>>()?, + loc, + }), Expr::NumericLiteral { value, id: _, ty } => { if ty.is_int() && value.contains('.') { Err(TypingError::ArgTypeMismatch) @@ -1464,12 +1797,13 @@ impl TypedExpr { { Err(TypingError::ArgTypeMismatch) } else { - let underlining = contents.first() - .map(|it| it.get_ty()) - .unwrap_or(types::ERROR); - Ok(Self::ArrayLiteral { - contents, - underlining, + let underlining = contents + .first() + .map(|it| it.get_ty()) + .unwrap_or(types::ERROR); + Ok(Self::ArrayLiteral { + contents, + underlining, }) } } @@ -1511,7 +1845,10 @@ impl TypedExpr { Self::UnaryOpCall(_) => todo!(), Self::FnCall(call) => Some(call.loc), Self::BoolLiteral(_, loc) | Self::ValueRead(_, _, loc) => Some(*loc), - Self::ArrayLiteral { contents: _, underlining:_ } => None, + Self::ArrayLiteral { + contents: _, + underlining: _, + } => None, Self::ListLiteral { contents: _ } => None, Self::TupleLiteral { contents: _, loc } => Some(*loc), Self::StructConstruction(con) => Some(con.loc), @@ -1538,14 +1875,18 @@ impl TypedExpr { Self::UnaryOpCall(data) => data.rt.clone(), Self::FnCall(data) => data.rt.clone(), Self::ValueRead(_, ty, _) => ty.clone(), - Self::ArrayLiteral { contents, underlining } => ResolvedType::Array { - underlining:underlining.clone().boxed(), + Self::ArrayLiteral { + contents, + underlining, + } => ResolvedType::Array { + underlining: underlining.clone().into(), size: contents.len(), }, Self::ListLiteral { .. } => todo!(), - Self::TupleLiteral { contents, loc:_ } => { - ResolvedType::Tuple { underlining: contents.iter().map(Self::get_ty).collect(), loc: (0,0) } - } + Self::TupleLiteral { contents, loc: _ } => ResolvedType::Tuple { + underlining: contents.iter().map(Self::get_ty).collect(), + loc: (0, 0), + }, Self::StructConstruction(strct) => ResolvedType::User { name: strct.ident.clone(), generics: strct.generics.clone(), @@ -1576,27 +1917,25 @@ impl TypedExpr { Self::UnaryOpCall(_) => todo!(), Self::FnCall(data) => data.replace_type(name, new_ty), Self::ValueRead(_, ty, _) => *ty = ty.replace_generic(name, new_ty.clone()), - Self::ArrayLiteral { contents, underlining } => { - if let Some(ty) = contents - .iter_mut() - .fold( - None, - |accum, it| { - it.replace_type(name, new_ty); - if accum.is_none() { - Some(it.get_ty()) - } else { - accum - } + Self::ArrayLiteral { + contents, + underlining, + } => { + if let Some(ty) = contents.iter_mut().fold(None, |accum, it| { + it.replace_type(name, new_ty); + if accum.is_none() { + Some(it.get_ty()) + } else { + accum } - ) { - *underlining=ty; + }) { + *underlining = ty; } - }, + } Self::ListLiteral { contents } => contents .iter_mut() .for_each(|it| it.replace_type(name, new_ty)), - Self::TupleLiteral { contents, loc:_ } => contents + Self::TupleLiteral { contents, loc: _ } => contents .iter_mut() .for_each(|it| it.replace_type(name, new_ty)), @@ -1675,9 +2014,12 @@ impl TypedExpr { *ident = new_name; *ty = fun_t; } - Self::ArrayLiteral { contents, underlining:_ } + Self::ArrayLiteral { + contents, + underlining: _, + } | Self::ListLiteral { contents } - | Self::TupleLiteral { contents, loc:_ } => { + | Self::TupleLiteral { contents, loc: _ } => { let mut old_args = Vec::new(); std::mem::swap(&mut old_args, &mut context.args); for value in contents { @@ -1716,7 +2058,7 @@ impl TypedIfExpr { value: ast::IfExpr, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Self { let ast::IfExpr { cond, @@ -1750,7 +2092,7 @@ impl TypedIfExpr { TypedExpr::ErrorNode } } - .boxed(); + .into(); let mut true_block_known_values = known_values.clone(); let true_branch_block = { @@ -1764,8 +2106,7 @@ impl TypedIfExpr { ) { Ok(stmnt) => { if let TypedStatement::Declaration(data) = &stmnt { - true_block_known_values - .extend(data.target.get_idents_with_types()); + true_block_known_values.extend(data.target.get_idents_with_types()); } block.push(stmnt); } @@ -1849,7 +2190,7 @@ impl TypedIfExpr { } }; - (cond.boxed(),block,ret.boxed()) + (cond.into(),block,ret.into()) }).collect(); let mut else_block_known_values = known_values.clone(); @@ -1910,9 +2251,9 @@ impl TypedIfExpr { }; Self { cond, - true_branch: (true_branch_block, true_branch_ret.boxed()), + true_branch: (true_branch_block, true_branch_ret.into()), else_ifs, - else_branch: (else_branch_block, else_branch_ret.boxed()), + else_branch: (else_branch_block, else_branch_ret.into()), loc, } } @@ -1965,7 +2306,7 @@ impl TypedMemberRead { value: ast::BinaryOpCall, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, already_processed_args: Vec, ) -> Result { let ast::BinaryOpCall { loc, lhs, rhs, .. } = value; @@ -1990,19 +2331,31 @@ impl TypedMemberRead { if !generics.is_empty() { // we will have to do checking after lowering. will do as part of lowering. Ok(Self { - target: value.boxed(), + target: value.into(), member, offset: None, ty: ResolvedType::Error, loc, }) } else if let Some(strct) = known_types.get(&ty.to_string()) { - let ast::TypeDefinition::Struct(def) = strct else { - unreachable!("how are you accessing a member not on a struct") + let def = match strct { + ResolvedTypeDeclaration::Struct(def) => def, + ResolvedTypeDeclaration::Dependent { actual, .. } => { + if let ResolvedTypeDeclaration::Struct(def) = actual.as_ref() { + def + } else { + println!("not a struct declaration"); + return Err(TypingError::UnknownType); + } + } + _ => { + println!("not a struct declaration"); + return Err(TypingError::UnknownType); + } }; - let offset = def.values.iter().position(|it| it.name == member); + let offset = def.fields.iter().position(|it| it.name == member); let ty = def - .values + .fields .iter() .find_map(|it| { if it.name == member { @@ -2018,7 +2371,7 @@ impl TypedMemberRead { }) .unwrap_or(ResolvedType::Error); Ok(Self { - target: value.boxed(), + target: value.into(), offset, member, ty, @@ -2098,8 +2451,8 @@ pub fn map_types_to_args( replaced.push((name.clone(), arg_t.clone())); ( ResolvedType::Function { - arg: arg_t.boxed(), - returns: fun.boxed(), + arg: arg_t.into(), + returns: fun.into(), loc: *loc, }, replaced, @@ -2108,8 +2461,8 @@ pub fn map_types_to_args( let (returns, replaced) = map_types_to_args(returns.as_ref().clone(), args); ( ResolvedType::Function { - arg: arg_t.boxed(), - returns: returns.boxed(), + arg: arg_t.into(), + returns: returns.into(), loc: (0, 0), }, replaced, @@ -2351,7 +2704,7 @@ impl TypedBinaryOpCall { value: ast::BinaryOpCall, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Result { let ast::BinaryOpCall { loc, @@ -2384,8 +2737,8 @@ impl TypedBinaryOpCall { if lhs_t == types::BOOL && rhs_t == types::BOOL { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::BOOL, }) @@ -2396,8 +2749,8 @@ impl TypedBinaryOpCall { { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::ERROR, }) @@ -2415,8 +2768,8 @@ impl TypedBinaryOpCall { } Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::BOOL, }) @@ -2427,8 +2780,8 @@ impl TypedBinaryOpCall { { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::ERROR, }) @@ -2443,8 +2796,8 @@ impl TypedBinaryOpCall { if lhs_t == rhs_t && (lhs_t.is_int() || lhs_t.is_float() || lhs_t == types::BOOL) { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::BOOL, }) @@ -2455,8 +2808,8 @@ impl TypedBinaryOpCall { { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: types::ERROR, }) @@ -2480,8 +2833,8 @@ impl TypedBinaryOpCall { { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: match (lhs_t, rhs_t) { (ResolvedType::Error, _) | (_, ResolvedType::Error) => types::ERROR, @@ -2544,8 +2897,8 @@ impl TypedBinaryOpCall { { Ok(Self { loc, - lhs: lhs.boxed(), - rhs: rhs.boxed(), + lhs: lhs.into(), + rhs: rhs.into(), operator, rt: match (lhs_t, rhs_t) { (ResolvedType::Error, _) | (_, ResolvedType::Error) => types::ERROR, @@ -2607,13 +2960,13 @@ fn strip_pointers(ty: &ResolvedType) -> ResolvedType { if let ResolvedType::Function { arg, returns, loc } = ty { let arg = match arg.as_ref() { ResolvedType::Pointer { underlining } if underlining.is_function() => { - strip_pointers(underlining.as_ref()).boxed() + strip_pointers(underlining.as_ref()).into() } _ => arg.clone(), }; let returns = match returns.as_ref() { ResolvedType::Pointer { underlining } if underlining.is_function() => { - strip_pointers(underlining.as_ref()).boxed() + strip_pointers(underlining.as_ref()).into() } _ => returns.clone(), }; @@ -2639,7 +2992,7 @@ impl TypedMatch { value: ast::Match, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Self { let ast::Match { loc, @@ -2647,7 +3000,7 @@ impl TypedMatch { arms, id: _, } = value; - let on = + let on: Box<_> = match TypedExpr::try_from(*on, known_externs, known_values, known_types, Vec::new()) { Ok(it) => it, Err(e) => { @@ -2655,7 +3008,7 @@ impl TypedMatch { TypedExpr::ErrorNode } } - .boxed(); + .into(); let mut new_arms = Vec::with_capacity(arms.len()); for arm in arms { let arm = @@ -2673,7 +3026,7 @@ impl TypedMatch { value: ast::Match, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, ) -> Self { let ast::Match { loc, @@ -2681,7 +3034,7 @@ impl TypedMatch { arms, id: _, } = value; - let on = + let on: Box<_> = match TypedExpr::try_from(*on, known_externs, known_values, known_types, Vec::new()) { Ok(it) => it, Err(e) => { @@ -2689,7 +3042,7 @@ impl TypedMatch { TypedExpr::ErrorNode } } - .boxed(); + .into(); let mut new_arms = Vec::with_capacity(arms.len()); for arm in arms { let arm = TypedMatchArm::as_statement( @@ -2709,7 +3062,7 @@ impl TypedMatch { } pub fn get_ty(&self) -> ResolvedType { - if dbg!(self) + if self .arms .iter() .map(|it| it.ret.as_ref().map(|it| it.get_ty())) @@ -2726,7 +3079,7 @@ impl TypedMatch { .map(|it| it.ret.as_ref().map(|it| it.get_ty()).unwrap_or(types::UNIT)) .filter(ResolvedType::is_error) .counts(); - let most_common = dbg!(types) + let most_common = types .iter() .max_by_key(|(_, it)| *it) .map(|(it, _)| it) @@ -2780,7 +3133,7 @@ impl TypedMatchArm { value: ast::MatchArm, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, expected_comp: &ResolvedType, ) -> Self { let ast::MatchArm { @@ -2791,7 +3144,7 @@ impl TypedMatchArm { } = value; let mut known_values = known_values.clone(); let mut new_block = Vec::with_capacity(block.len()); - let cond = TypedPattern::from(cond, expected_comp); + let cond = TypedPattern::from(cond, expected_comp, known_types); known_values.extend(cond.get_idents_with_types()); for stmnt in block { match TypedStatement::try_from(stmnt, known_externs, &known_values, known_types) { @@ -2815,7 +3168,7 @@ impl TypedMatchArm { TypedExpr::ErrorNode } } - .boxed() + .into() }); Self { loc, @@ -2839,21 +3192,19 @@ impl TypedMatchArm { arm: ast::MatchArm, known_externs: &HashMap, known_values: &HashMap, - known_types: &HashMap, + known_types: &HashMap, expected_comp: &ResolvedType, ) -> TypedMatchArm { let ast::MatchArm { block, ret, - cond: cond, + cond, loc, } = arm; let mut known_values = known_values.clone(); let mut new_block = Vec::with_capacity(block.len()); - let cond = TypedPattern::from(cond, expected_comp); - if let TypedPattern::Read(name, ty, _) = &cond { - known_values.insert(name.clone(), ty.clone()); - } + let cond = TypedPattern::from(cond, expected_comp, known_types); + known_values.extend(cond.get_idents_with_types()); for stmnt in block { match TypedStatement::try_from(stmnt, known_externs, &known_values, known_types) { Ok(stmnt) => { @@ -2903,13 +3254,49 @@ pub enum TypedPattern { Read(String, ResolvedType, crate::Location), Err, Default, - Or(Box,Box), - Destructure(TypedDestructure) + Or(Box, Box), + Destructure(TypedDestructure), + EnumVariant { + ty: ResolvedType, + variant: String, + pattern: Option>, + loc: crate::Location, + }, } impl TypedPattern { - fn from(value: ast::Pattern, expected_type: &ResolvedType) -> Self { - match value { + fn from( + value: ast::Pattern, + expected_type: &ResolvedType, + known_types: &HashMap, + ) -> Self { + match dbg!(value) { + ast::Pattern::EnumVariant { + ty, + variant, + pattern, + loc, + } => { + if let Some(ResolvedTypeDeclaration::Dependent { base, actual }) = + known_types.get(&variant) + { + let base: ResolvedType = base.as_ref().into(); + if &base != expected_type { + println!("Err incorrect enum matched"); + return Self::Err; + } + Self::EnumVariant { + ty, + variant, + pattern: pattern.map(|pat| { + Self::from(*pat, &actual.as_ref().into(), known_types).into() + }), + loc, + } + } else { + Self::Err + } + } ast::Pattern::Default => Self::Default, ast::Pattern::ConstNumber(n, ty) if &ty == expected_type => { Self::Const(n, expected_type.clone()) @@ -2949,61 +3336,71 @@ impl TypedPattern { ); Self::Const(b.to_string(), types::ERROR) } - ast::Pattern::Read{ + ast::Pattern::Read { ident, loc, ty, - id:_, + id: _, } => { - if dbg!(&ty)!=dbg!(expected_type) { + if &ty != expected_type { println!("this should report a diagnostic"); Self::Err } else { - Self::Read(ident, ty,loc) + Self::Read(ident, ty, loc) } - }, - ast::Pattern::Destructure(destruct)=> Self::Destructure(TypedDestructure::from(destruct, expected_type)), - ast::Pattern::Or(lhs,rhs) => + } + ast::Pattern::Destructure(destruct) => { + Self::Destructure(TypedDestructure::from(destruct, expected_type, known_types)) + } + ast::Pattern::Or(lhs, rhs) => //TODO! diagnostics if not all binds are in both patterns. - Self::Or( - Self::from(*lhs, expected_type).boxed(), - Self::from(*rhs,expected_type).boxed() - ), + { + Self::Or( + Self::from(*lhs, expected_type, known_types).into(), + Self::from(*rhs, expected_type, known_types).into(), + ) + } ast::Pattern::Err => Self::Err, } } pub fn get_binds(&self) -> HashSet { match self { - Self::Default - | Self::Err - | Self::Const(_, _) => HashSet::new(), + Self::Default | Self::Err | Self::Const(_, _) => HashSet::new(), Self::Destructure(d) => d.get_binds(), - Self::Read(name, _, _)=>[name.clone()].into(), + Self::Read(name, _, _) => [name.clone()].into(), Self::Or(lhs, rhs) => { let lhs = lhs.get_binds(); lhs } + Self::EnumVariant { pattern, .. } => pattern + .as_ref() + .map(Box::as_ref) + .map(Self::get_binds) + .unwrap_or_default(), } } - pub fn get_idents_with_types(&self) -> HashMap { + pub fn get_idents_with_types(&self) -> HashMap { match self { - Self::Default - | Self::Err - | Self::Const(_, _) => HashMap::new(), + Self::Default | Self::Err | Self::Const(_, _) => HashMap::new(), Self::Destructure(d) => d.get_idents_with_types(), - Self::Or(lhs,rhs) => { + Self::Or(lhs, rhs) => { let mut lhs = lhs.get_idents_with_types(); let rhs = rhs.get_idents_with_types(); if lhs == rhs { lhs - }else { - lhs.insert("".to_string(),types::ERROR); + } else { + lhs.insert("".to_string(), types::ERROR); lhs } } - Self::Read(ident, ty, _) => [(ident.clone(),ty.clone())].into() + Self::Read(ident, ty, _) => [(ident.clone(), ty.clone())].into(), + Self::EnumVariant { pattern, .. } => pattern + .as_ref() + .map(Box::as_ref) + .map(Self::get_idents_with_types) + .unwrap_or_default(), } } pub fn is_simple(&self) -> bool { @@ -3012,8 +3409,12 @@ impl TypedPattern { Self::Const(_, ty) => ty.is_int() || ty.is_float(), Self::Or(lhs, rhs) => lhs.is_simple() && rhs.is_simple(), Self::Destructure(d) => d.is_simple(), - Self::Read(_, _, _) - | Self::Err => false, + Self::Read(_, _, _) | Self::Err => false, + Self::EnumVariant { pattern, .. } => pattern + .as_ref() + .map(Box::as_ref) + .map(|it| matches!(it,Self::Default)) + .unwrap_or(true), } } } @@ -3021,47 +3422,64 @@ impl TypedPattern { #[derive(Debug, PartialEq, Clone)] pub enum TypedDestructure { Tuple(Vec), - Struct{ - fields : HashMap, + Struct { + fields: HashMap, }, Unit, } impl TypedDestructure { - - fn get_idents_with_types(&self) -> HashMap { + fn get_idents_with_types(&self) -> HashMap { match self { - TypedDestructure::Tuple(contents) => contents.iter().flat_map(TypedPattern::get_idents_with_types).collect(), - TypedDestructure::Struct { fields } => todo!("not yet supporting field destructuring on match arms."), + TypedDestructure::Tuple(contents) => contents + .iter() + .flat_map(TypedPattern::get_idents_with_types) + .collect(), + TypedDestructure::Struct { fields } => { + todo!("not yet supporting field destructuring on match arms.") + } TypedDestructure::Unit => HashMap::new(), } } - fn from(destructure:ast::DestructurePattern, expected_ty:&ResolvedType) -> Self { + fn from( + destructure: ast::DestructurePattern, + expected_ty: &ResolvedType, + known_types: &HashMap, + ) -> Self { match destructure { - ast::DestructurePattern::Struct { fields } => todo!("need to expand structure destructuring - "), + ast::DestructurePattern::Struct { base_ty, fields } => todo!( + "need to expand structure destructuring + " + ), ast::DestructurePattern::Tuple(patterns, ty, _) => { let mut patterns = if let ResolvedType::Tuple { underlining, .. } = expected_ty { - patterns.into_iter().zip(underlining).map(|(pat,ty)| TypedPattern::from(pat, ty)).collect() + patterns + .into_iter() + .zip(underlining) + .map(|(pat, ty)| TypedPattern::from(pat, ty, known_types)) + .collect() } else { - patterns.into_iter().map(|pat| TypedPattern::from(pat,&types::ERROR)).collect() + patterns + .into_iter() + .map(|pat| TypedPattern::from(pat, &types::ERROR, known_types)) + .collect() }; if &ty != expected_ty { // todo! report diagnostic } Self::Tuple(patterns) - }, + } ast::DestructurePattern::Unit if expected_ty == &types::UNIT => Self::Unit, ast::DestructurePattern::Unit => Self::Tuple(vec![TypedPattern::Err]), } } - + fn get_binds(&self) -> HashSet { match self { Self::Struct { fields } => todo!(), Self::Tuple(patterns) => patterns.iter().flat_map(TypedPattern::get_binds).collect(), - Self::Unit => HashSet::new() + Self::Unit => HashSet::new(), } } @@ -3114,11 +3532,11 @@ mod tests { TypedModuleDeclaration, TypedStatement, TypedValueDeclaration, TypedValueType, }; use crate::types::{self, ResolvedType}; - use crate::util::ExtraUtilFunctions; + use pretty_assertions::assert_eq; lazy_static::lazy_static! { static ref PREDEFINED_VALUES : HashMap = { let mut out = HashMap::new(); - out.insert("foo".to_string(), ResolvedType::Function { arg: types::INT32.boxed(), returns: types::INT32.boxed(), loc:(0,0) }); + out.insert("foo".to_string(), ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), loc:(0,0) }); out.insert("bar".to_string(), types::INT32); out }; @@ -3245,13 +3663,13 @@ let b value : (int32,(int32,int32)) -> int32 = match value where ty: types::INT32, id: 0 } - .boxed(), + .into(), rhs: Expr::NumericLiteral { value: "2".to_string(), ty: types::INT32, id: 0 } - .boxed(), + .into(), operator: "+".to_string(), result: types::INT32, id: 0 @@ -3268,12 +3686,12 @@ let b value : (int32,(int32,int32)) -> int32 = match value where value: "1".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed(), + .into(), rhs: TypedExpr::IntegerLiteral { value: "2".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed(), + .into(), operator: "+".to_string(), rt: types::INT32 }), @@ -3299,8 +3717,8 @@ let b value : (int32,(int32,int32)) -> int32 = match value where TypedExpr::try_from( Expr::FnCall(ast::FnCall { loc: (0, 0), - value: Expr::ValueRead("foo".to_string(), (0, 0), 0).boxed(), - arg: Expr::ValueRead("bar".to_string(), (0, 0), 0).boxed(), + value: Expr::ValueRead("foo".to_string(), (0, 0), 0).into(), + arg: Expr::ValueRead("bar".to_string(), (0, 0), 0).into(), id: 0, returns: types::INT32, }), @@ -3315,14 +3733,14 @@ let b value : (int32,(int32,int32)) -> int32 = match value where value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (0, 0) ) - .boxed(), - arg: Some(TypedExpr::ValueRead("bar".to_string(), types::INT32, (0, 0)).boxed()), + .into(), + arg: Some(TypedExpr::ValueRead("bar".to_string(), types::INT32, (0, 0)).into()), arg_t: types::INT32, rt: types::INT32, is_extern: false, @@ -3389,7 +3807,12 @@ let b value : (int32,(int32,int32)) -> int32 = match value where Statement::Declaration(ast::ValueDeclaration { loc: (0, 0), is_op: false, - target: ast::Pattern::Read { ident: "foo".to_string(), loc: (0,0), ty: types::INT32, id: 0 }, + target: ast::Pattern::Read { + ident: "foo".to_string(), + loc: (0, 0), + ty: types::INT32, + id: 0 + }, args: Vec::new(), ty: types::INT32, value: ast::ValueType::Expr(ast::Expr::NumericLiteral { @@ -3409,7 +3832,7 @@ let b value : (int32,(int32,int32)) -> int32 = match value where TypedStatement::Declaration(TypedValueDeclaration { loc: (0, 0), is_op: false, - target: TypedPattern::Read("foo".to_string(),types::INT32,(0,0)), + target: TypedPattern::Read("foo".to_string(), types::INT32, (0, 0)), args: Vec::new(), value: TypedValueType::Expr(TypedExpr::IntegerLiteral { value: "1".to_string(), @@ -3442,8 +3865,8 @@ let b value : (int32,(int32,int32)) -> int32 = match value where TypedStatement::try_from( Statement::FnCall(ast::FnCall { loc: (0, 0), - value: ast::Expr::ValueRead("foo".to_string(), (0, 0), 0).boxed(), - arg: ast::Expr::ValueRead("bar".to_string(), (0, 0), 0).boxed(), + value: ast::Expr::ValueRead("foo".to_string(), (0, 0), 0).into(), + arg: ast::Expr::ValueRead("bar".to_string(), (0, 0), 0).into(), returns: types::INT32, id: 0 }), @@ -3457,14 +3880,14 @@ let b value : (int32,(int32,int32)) -> int32 = match value where value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (0, 0) ) - .boxed(), - arg: Some(TypedExpr::ValueRead("bar".to_string(), types::INT32, (0, 0)).boxed()), + .into(), + arg: Some(TypedExpr::ValueRead("bar".to_string(), types::INT32, (0, 0)).into()), arg_t: types::INT32, rt: types::INT32, is_extern: false, @@ -3477,23 +3900,23 @@ let b value : (int32,(int32,int32)) -> int32 = match value where #[test] fn decl_convert() { - use super::TypedDeclaration; use super::TypedArgDeclaration; + use super::TypedDeclaration; assert_eq!( TypedDeclaration::try_from( ast::TopLevelDeclaration::Value(ast::TopLevelValue { loc: (0, 0), is_op: false, - ident:"test".to_string(), + ident: "test".to_string(), args: vec![ast::ArgDeclaration::Simple { ident: "a".to_string(), loc: (0, 0), ty: types::INT32, - id:0 + id: 0 }], ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, value: ast::ValueType::Function(vec![ast::Statement::Return( @@ -3524,8 +3947,8 @@ let b value : (int32,(int32,int32)) -> int32 = match value where ty: types::INT32, }], ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, value: super::TypedValueType::Function(vec![super::TypedStatement::Return( @@ -3586,7 +4009,7 @@ let main _ : () -> () = is_op: false, ident: "test".to_string(), args: vec![TypedArgDeclaration::Simple { - loc:(1,16), + loc: (1, 16), ident: "a".to_string(), ty: ResolvedType::Generic { name: "T".to_string(), @@ -3606,12 +4029,12 @@ let main _ : () -> () = name: "T".to_string(), loc: (1, 20), } - .boxed(), + .into(), returns: ResolvedType::Generic { name: "T".to_string(), loc: (1, 25) } - .boxed(), + .into(), loc: (0, 0) }, generics: Some(ResolvedGenericsDecl { @@ -3642,7 +4065,7 @@ let main _ : () -> () = TypedStatement::Declaration(TypedValueDeclaration { loc: (4, 8), is_op: false, - target: TypedPattern::Read("x".to_string(),types::INT32,(4,8)), + target: TypedPattern::Read("x".to_string(), types::INT32, (4, 8)), args: Vec::new(), value: TypedValueType::Expr(TypedExpr::IntegerLiteral { value: "3".to_string(), @@ -3662,19 +4085,19 @@ let main _ : () -> () = name: "T".to_string(), loc: (1, 20) } - .boxed(), + .into(), returns: ResolvedType::Generic { name: "T".to_string(), loc: (1, 25) } - .boxed(), + .into(), loc: (0, 0), }, (5, 4) ) - .boxed(), + .into(), arg: Some( - TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).boxed() + TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).into() ), rt: ResolvedType::Generic { name: "T".to_string(), @@ -3685,8 +4108,8 @@ let main _ : () -> () = }) ]), ty: ResolvedType::Function { - arg: types::UNIT.boxed(), - returns: types::UNIT.boxed(), + arg: types::UNIT.into(), + returns: types::UNIT.into(), loc: (0, 0) }, generics: None, @@ -3814,8 +4237,8 @@ let first a : Tuple -> int32 = generics: Vec::new(), loc: (7, 14) } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (7, 36) }, generics: None, @@ -3913,12 +4336,12 @@ let main x : int32 -> int32 = name: "T".to_string(), loc: (1, 20), } - .boxed(), + .into(), returns: ResolvedType::Generic { name: "T".to_string(), loc: (1, 25), } - .boxed(), + .into(), loc: (1, 23), }, generics: Some(ResolvedGenericsDecl { @@ -3952,15 +4375,15 @@ let main x : int32 -> int32 = value: TypedExpr::ValueRead( "test".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (5, 4) }, (5, 4) ) - .boxed(), + .into(), arg: Some( - TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).boxed() + TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).into() ), rt: types::INT32, arg_t: types::INT32, @@ -3975,8 +4398,8 @@ let main x : int32 -> int32 = ) ]), ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (6, 20) }, generics: None, @@ -4000,8 +4423,8 @@ let main x : int32 -> int32 = (2, 4) )]), ty: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, generics: None, @@ -4051,9 +4474,7 @@ let statement_with_else_if a b : bool -> bool -> int32 = let module = inference_context.inference(module); let mut module = TypedModuleDeclaration::from(module, &fwd_decls, &HashMap::new()); - module - .declarations - .sort_by_key(TypedDeclaration::get_ident); + module.declarations.sort_by_key(TypedDeclaration::get_ident); let [expr, stmnt] = &module.declarations[..] else { unreachable!("more than two?") }; @@ -4068,26 +4489,26 @@ let statement_with_else_if a b : bool -> bool -> int32 = ty: types::BOOL, }], value: TypedValueType::Expr(TypedExpr::IfExpr(TypedIfExpr { - cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (1, 47)).boxed(), + cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (1, 47)).into(), true_branch: ( vec![TypedStatement::FnCall(TypedFnCall { loc: (2, 8), value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (2, 8) ) - .boxed(), + .into(), arg: Some( TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), rt: types::INT32, arg_t: types::INT32, @@ -4097,7 +4518,7 @@ let statement_with_else_if a b : bool -> bool -> int32 = value: "0".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), else_ifs: Vec::new(), else_branch: ( @@ -4106,19 +4527,19 @@ let statement_with_else_if a b : bool -> bool -> int32 = value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (5, 8) ) - .boxed(), + .into(), arg: Some( TypedExpr::IntegerLiteral { value: "4".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), rt: types::INT32, arg_t: types::INT32, @@ -4128,13 +4549,13 @@ let statement_with_else_if a b : bool -> bool -> int32 = value: "1".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), loc: (1, 44) })), ty: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (0, 0) }, generics: None, @@ -4149,7 +4570,6 @@ let statement_with_else_if a b : bool -> bool -> int32 = is_op: false, ident: "statement_with_else_if".to_string(), args: vec![ - TypedArgDeclaration::Simple { loc: (8, 27), ident: "a".to_string(), @@ -4160,21 +4580,20 @@ let statement_with_else_if a b : bool -> bool -> int32 = ident: "b".to_string(), ty: types::BOOL, }, - ], ty: ResolvedType::Function { - arg: types::BOOL.boxed(), + arg: types::BOOL.into(), returns: ResolvedType::Function { - arg: types::BOOL.boxed(), - returns: types::INT32.boxed(), + arg: types::BOOL.into(), + returns: types::INT32.into(), loc: (0, 0) } - .boxed(), + .into(), loc: (0, 0) }, value: TypedValueType::Function(vec![TypedStatement::IfBranching( TypedIfBranching { - cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (9, 7)).boxed(), + cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (9, 7)).into(), true_branch: vec![TypedStatement::Return( TypedExpr::IntegerLiteral { value: "0".to_string(), @@ -4183,7 +4602,7 @@ let statement_with_else_if a b : bool -> bool -> int32 = (10, 8) )], else_ifs: vec![( - TypedExpr::ValueRead("b".to_string(), types::BOOL, (11, 12)).boxed(), + TypedExpr::ValueRead("b".to_string(), types::BOOL, (11, 12)).into(), vec![TypedStatement::Return( TypedExpr::IntegerLiteral { value: "1".to_string(), @@ -4281,7 +4700,6 @@ let as_statement a b : int32 -> int32 -> () = ident: "fun".to_string(), ty: types::INT32.fn_ty(&types::INT32), }, - ], value: TypedValueType::Expr(TypedExpr::Match(TypedMatch { loc: (1, 61), @@ -4290,21 +4708,21 @@ let as_statement a b : int32 -> int32 -> () = value: TypedExpr::ValueRead( "fun".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (1, 67) ) - .boxed(), + .into(), arg: Some( - TypedExpr::ValueRead("a".to_string(), types::INT32, (1, 71)).boxed() + TypedExpr::ValueRead("a".to_string(), types::INT32, (1, 71)).into() ), rt: types::INT32, arg_t: types::INT32, is_extern: false, }) - .boxed(), + .into(), arms: vec![ TypedMatchArm { loc: (2, 2), @@ -4318,7 +4736,7 @@ let as_statement a b : int32 -> int32 -> () = value: "0".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ) }, TypedMatchArm { @@ -4333,7 +4751,7 @@ let as_statement a b : int32 -> int32 -> () = value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ) }, TypedMatchArm { @@ -4341,7 +4759,7 @@ let as_statement a b : int32 -> int32 -> () = cond: crate::typed_ast::TypedPattern::Read( "a".to_string(), types::INT32, - (4,2) + (4, 2) ), block: Vec::new(), ret: Some( @@ -4352,33 +4770,33 @@ let as_statement a b : int32 -> int32 -> () = types::INT32, (4, 7) ) - .boxed(), + .into(), rhs: TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed(), + .into(), operator: "*".to_string(), rt: types::INT32 }) - .boxed() + .into() ) }, ] })), ty: ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { arg: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (0, 0) } - .boxed(), + .into(), loc: (0, 0) }, generics: None, @@ -4394,7 +4812,6 @@ let as_statement a b : int32 -> int32 -> () = is_op: false, ident: "nest_in_call".to_string(), args: vec![ - TypedArgDeclaration::Simple { loc: (6, 17), ident: "a".to_string(), @@ -4405,25 +4822,23 @@ let as_statement a b : int32 -> int32 -> () = ident: "fun".to_string(), ty: types::INT32.fn_ty(&types::INT32), }, - ], value: TypedValueType::Expr(TypedExpr::FnCall(TypedFnCall { loc: (6, 62), value: TypedExpr::ValueRead( "fun".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) }, (6, 62) ) - .boxed(), + .into(), arg: Some( TypedExpr::Match(TypedMatch { loc: (6, 67), - on: TypedExpr::ValueRead("a".to_string(), types::INT32, (6, 73)) - .boxed(), + on: TypedExpr::ValueRead("a".to_string(), types::INT32, (6, 73)).into(), arms: vec![ TypedMatchArm { loc: (7, 2), @@ -4437,7 +4852,7 @@ let as_statement a b : int32 -> int32 -> () = value: "0".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ) }, TypedMatchArm { @@ -4452,7 +4867,7 @@ let as_statement a b : int32 -> int32 -> () = value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ) }, TypedMatchArm { @@ -4467,39 +4882,39 @@ let as_statement a b : int32 -> int32 -> () = types::INT32, (9, 7) ) - .boxed(), + .into(), rhs: TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed(), + .into(), operator: "*".to_string(), rt: types::INT32 }) - .boxed() + .into() ) }, ] }) - .boxed() + .into() ), rt: types::INT32, arg_t: types::INT32, is_extern: false, })), ty: ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { arg: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::INT32.boxed(), + arg: types::INT32.into(), + returns: types::INT32.into(), loc: (0, 0) } - .boxed(), - returns: types::INT32.boxed(), + .into(), + returns: types::INT32.into(), loc: (0, 0) } - .boxed(), + .into(), loc: (0, 0) }, generics: None, @@ -4510,12 +4925,11 @@ let as_statement a b : int32 -> int32 -> () = ); assert_eq!( - &TypedDeclaration::Value(TypedTopLevelValue{ + &TypedDeclaration::Value(TypedTopLevelValue { loc: (12, 4), is_op: false, ident: "as_statement".to_string(), args: vec![ - TypedArgDeclaration::Simple { loc: (12, 17), ident: "a".to_string(), @@ -4526,11 +4940,10 @@ let as_statement a b : int32 -> int32 -> () = ident: "b".to_string(), ty: types::INT32, }, - ], value: TypedValueType::Function(vec![TypedStatement::Match(TypedMatch { loc: (13, 4), - on: TypedExpr::ValueRead("a".to_string(), types::INT32, (13, 10)).boxed(), + on: TypedExpr::ValueRead("a".to_string(), types::INT32, (13, 10)).into(), arms: vec![ TypedMatchArm { loc: (14, 6), @@ -4541,7 +4954,7 @@ let as_statement a b : int32 -> int32 -> () = block: vec![TypedStatement::Match(TypedMatch { loc: (15, 8), on: TypedExpr::ValueRead("b".to_string(), types::INT32, (15, 14)) - .boxed(), + .into(), arms: vec![ TypedMatchArm { loc: (16, 10), @@ -4555,19 +4968,19 @@ let as_statement a b : int32 -> int32 -> () = value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::UNIT.boxed(), + arg: types::INT32.into(), + returns: types::UNIT.into(), loc: (0, 0) }, (16, 15) ) - .boxed(), + .into(), arg: Some( TypedExpr::IntegerLiteral { value: "1".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), rt: types::UNIT, arg_t: types::INT32, @@ -4588,19 +5001,19 @@ let as_statement a b : int32 -> int32 -> () = value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::UNIT.boxed(), + arg: types::INT32.into(), + returns: types::UNIT.into(), loc: (0, 0) }, (18, 12) ) - .boxed(), + .into(), arg: Some( TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo } - .boxed() + .into() ), rt: types::UNIT, arg_t: types::INT32, @@ -4633,13 +5046,13 @@ let as_statement a b : int32 -> int32 -> () = ] })]), ty: ResolvedType::Function { - arg: types::INT32.boxed(), + arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.boxed(), - returns: types::UNIT.boxed(), + arg: types::INT32.into(), + returns: types::UNIT.into(), loc: (0, 0) } - .boxed(), + .into(), loc: (0, 0) }, generics: None, @@ -4722,15 +5135,15 @@ let not_so_simple a : int32 -> [int32;4] = size: types::IntWidth::ThirtyTwo }, ], - underlining:types::INT32, + underlining: types::INT32, }), ty: ResolvedType::Function { - arg: types::UNIT.boxed(), + arg: types::UNIT.into(), returns: ResolvedType::Array { - underlining: types::INT32.boxed(), + underlining: types::INT32.into(), size: 5 } - .boxed(), + .into(), loc: (0, 0) }, generics: None, @@ -4741,7 +5154,7 @@ let not_so_simple a : int32 -> [int32;4] = ); println!("{should_fail:?}"); - const USAGE : &'static str = " + const USAGE: &'static str = " let f (a:[int32;5]) = (); let main _ : () -> () = @@ -4751,80 +5164,110 @@ let main _ : () -> () = let ast = crate::Parser::from_source(USAGE).module(String::new()).ast; let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut inference_ctx = crate::inference::Context::new( - dtree, + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); let ast = inference_ctx.inference(ast); - let mut ast = TypedModuleDeclaration::from( - ast, - &HashMap::new(), - &HashMap::new(), - ); + let mut ast = TypedModuleDeclaration::from(ast, &HashMap::new(), &HashMap::new()); ast.declarations.sort_by_key(|decl| decl.get_ident()); - let [f,main]=&ast.declarations[..] else { unreachable!() }; + let [f, main] = &ast.declarations[..] else { + unreachable!() + }; assert_eq!( - &TypedDeclaration::Value(TypedTopLevelValue{ - loc : (1,4), - is_op:false, - ident:"f".to_string(), - args:vec![ - - TypedArgDeclaration::Simple { - loc:(1,7), - ident:"a".to_string(), - ty : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, + &TypedDeclaration::Value(TypedTopLevelValue { + loc: (1, 4), + is_op: false, + ident: "f".to_string(), + args: vec![TypedArgDeclaration::Simple { + loc: (1, 7), + ident: "a".to_string(), + ty: ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 }, - - ], - ty:ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT), - value:TypedValueType::Expr(TypedExpr::UnitLiteral), - generics:None, - abi:None, + },], + ty: ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 + } + .fn_ty(&types::UNIT), + value: TypedValueType::Expr(TypedExpr::UnitLiteral), + generics: None, + abi: None, }), f, "the function" ); assert_eq!( - &TypedDeclaration::Value(TypedTopLevelValue{ - loc : (3,4), - is_op:false, - ident:"main".to_string(), - args:vec![ - - TypedArgDeclaration::Discard { - loc:(3,9), - ty : types::UNIT, - }, - - ], - ty:types::UNIT.fn_ty(&types::UNIT), - value:TypedValueType::Function(vec![ + &TypedDeclaration::Value(TypedTopLevelValue { + loc: (3, 4), + is_op: false, + ident: "main".to_string(), + args: vec![TypedArgDeclaration::Discard { + loc: (3, 9), + ty: types::UNIT, + },], + ty: types::UNIT.fn_ty(&types::UNIT), + value: TypedValueType::Function(vec![ TypedStatement::FnCall(TypedFnCall { - loc:(4,4), - value:TypedExpr::ValueRead("f".to_string(), ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT),(4,4)).boxed(), - arg:Some(TypedExpr::ArrayLiteral { - contents: vec![ - TypedExpr::IntegerLiteral { value: "1".to_string(), size: types::IntWidth::ThirtyTwo }, - TypedExpr::IntegerLiteral { value: "2".to_string(), size: types::IntWidth::ThirtyTwo }, - TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo }, - TypedExpr::IntegerLiteral { value: "4".to_string(), size: types::IntWidth::ThirtyTwo }, - TypedExpr::IntegerLiteral { value: "5".to_string(), size: types::IntWidth::ThirtyTwo }, - ], - underlining:types::INT32, - }.boxed()), - rt:types::UNIT, - arg_t : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, - is_extern:false, + loc: (4, 4), + value: TypedExpr::ValueRead( + "f".to_string(), + ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 + } + .fn_ty(&types::UNIT), + (4, 4) + ) + .into(), + arg: Some( + TypedExpr::ArrayLiteral { + contents: vec![ + TypedExpr::IntegerLiteral { + value: "1".to_string(), + size: types::IntWidth::ThirtyTwo + }, + TypedExpr::IntegerLiteral { + value: "2".to_string(), + size: types::IntWidth::ThirtyTwo + }, + TypedExpr::IntegerLiteral { + value: "3".to_string(), + size: types::IntWidth::ThirtyTwo + }, + TypedExpr::IntegerLiteral { + value: "4".to_string(), + size: types::IntWidth::ThirtyTwo + }, + TypedExpr::IntegerLiteral { + value: "5".to_string(), + size: types::IntWidth::ThirtyTwo + }, + ], + underlining: types::INT32, + } + .into() + ), + rt: types::UNIT, + arg_t: ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 + }, + is_extern: false, }), - TypedStatement::Return(TypedExpr::UnitLiteral, (5,4)) + TypedStatement::Return(TypedExpr::UnitLiteral, (5, 4)) ]), - generics:None, - abi:None, + generics: None, + abi: None, }), main, "main" @@ -4832,86 +5275,272 @@ let main _ : () -> () = } #[test] fn destructuring_statement() { - let ast = Parser::from_source(" + let ast = Parser::from_source( + " let a (v:(int32,int32)) = let (x,y) = v; - return ();").module("".to_string()).ast; + return ();", + ) + .module("".to_string()) + .ast; let dtree = ast.get_dependencies(); - let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut inference_ctx = crate::inference::Context::new( - dtree, + dtree, + HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new() ); let ast = inference_ctx.inference(ast); - let mut ast = TypedModuleDeclaration::from( - ast, - &HashMap::new(), - &HashMap::new(), - ); - let [a] = &ast.declarations[..] else {unreachable!()}; + let mut ast = TypedModuleDeclaration::from(ast, &HashMap::new(), &HashMap::new()); + let [a] = &ast.declarations[..] else { + unreachable!() + }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc:(1,4), - is_op:false, - ident:"a".to_string(), - args:vec![TypedArgDeclaration::Simple{ - ident:"v".to_string(), - ty:ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + loc: (1, 4), + is_op: false, + ident: "a".to_string(), + args: vec![TypedArgDeclaration::Simple { + ident: "v".to_string(), + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, - loc:(1,7) + loc: (1, 7) }], ty: ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) - }.fn_ty(&types::UNIT), + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) + } + .fn_ty(&types::UNIT), value: TypedValueType::Function(vec![ TypedStatement::Declaration(TypedValueDeclaration { - loc:(2,8), - is_op:false, - is_curried:false, - target:TypedPattern::Destructure(TypedDestructure::Tuple(vec![ - TypedPattern::Read("x".to_string(), types::INT32, (2,9)), - TypedPattern::Read("y".to_string(), types::INT32, (2,11)), + loc: (2, 8), + is_op: false, + is_curried: false, + target: TypedPattern::Destructure(TypedDestructure::Tuple(vec![ + TypedPattern::Read("x".to_string(), types::INT32, (2, 9)), + TypedPattern::Read("y".to_string(), types::INT32, (2, 11)), ])), - args:Vec::new(), - value:TypedValueType::Expr( - TypedExpr::ValueRead("v".to_string(), + args: Vec::new(), + value: TypedValueType::Expr(TypedExpr::ValueRead( + "v".to_string(), ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, - (2,16) + (2, 16) )), - ty:ResolvedType::Tuple { - underlining:vec![ - types::INT32, - types::INT32, - ], - loc:(0,0) + ty: ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (0, 0) }, - generictypes:None, - abi:None, + generictypes: None, + abi: None, }), - TypedStatement::Return(TypedExpr::UnitLiteral,(3,4)) - ]), - generics: None, + TypedStatement::Return(TypedExpr::UnitLiteral, (3, 4)) + ]), + generics: None, abi: None, }), a ) } + #[test] + fn enum_variants() { + const SRC: &'static str = r#" +enum Test = | A (int8,int8) | B +let fun a = match a where +| Test::A ((a,0) | (0,a)) -> a, +| Test::A (a,b) -> 1, +| Test::B -> 0, +"#; + let ast = Parser::from_source(SRC).module("".to_string()).ast; + let dtree = ast.get_dependencies(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); + let mut inference_ctx = crate::inference::Context::new( + dtree, + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + ); + let ast = inference_ctx.inference(ast); + + println!("{:#?}", ast.decls[1]); + let ast = TypedModuleDeclaration::from(ast, &HashMap::new(), &HashMap::new()); + let [ty, fun] = &ast.declarations[..] else { + unreachable!() + }; + + assert_eq!( + ty, + &super::TypedDeclaration::TypeDefinition(super::ResolvedTypeDeclaration::Enum( + super::TypedEnumDeclaration { + ident: "Test".into(), + generics: None, + values: vec![ + crate::ast::EnumVariant::Tuple { + ident: "A".into(), + ty: ResolvedType::Tuple { + underlining: vec![types::INT8; 2], + loc: (0, 0) + }, + loc: (1, 14) + }, + crate::ast::EnumVariant::Unit { + ident: "B".into(), + loc: (1, 30) + } + ], + loc: (1, 5), + } + )) + ); + + assert_eq!( + fun, + &super::TypedDeclaration::Value(super::TypedTopLevelValue { + loc: (2, 4), + is_op: false, + ident: "fun".into(), + args: vec![TypedArgDeclaration::Simple { + loc: (2, 8), + ident: "a".into(), + ty: ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + }, + }], + ty: ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + } + .fn_ty(&types::INT8), + value: TypedValueType::Expr(super::TypedExpr::Match(super::TypedMatch { + loc: (2, 12), + on: super::TypedExpr::ValueRead( + "a".into(), + ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + }, + (2, 18) + ) + .into(), + arms: vec![ + super::TypedMatchArm { + loc: (3, 2), + cond: TypedPattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + } + .into(), + actual: ResolvedType::Tuple { + underlining: vec![types::INT8, types::INT8], + loc: (0, 0) + } + .into(), + generics: Vec::new(), + ident: "Test::A".into(), + loc: (0, 0) + }, + variant: "Test::A".into(), + pattern: Some( + TypedPattern::Or( + TypedPattern::Destructure(TypedDestructure::Tuple(vec![ + TypedPattern::Read("a".into(), types::INT8, (3, 12)), + TypedPattern::Const("0".into(), types::INT8), + ])) + .into(), + TypedPattern::Destructure(TypedDestructure::Tuple(vec![ + TypedPattern::Const("0".into(), types::INT8), + TypedPattern::Read("a".into(), types::INT8, (3, 22)), + ])) + .into() + ) + .into() + ), + loc: (3, 2) + }, + block: Vec::new(), + ret: Some( + super::TypedExpr::ValueRead("a".into(), types::INT8, (3, 29)) + .into() + ) + }, + super::TypedMatchArm { + loc: (4, 2), + cond: TypedPattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + } + .into(), + actual: ResolvedType::Tuple { + underlining: vec![types::INT8, types::INT8], + loc: (0, 0) + } + .into(), + generics: Vec::new(), + ident: "Test::A".into(), + loc: (0, 0) + }, + variant: "Test::A".into(), + pattern: Some( + super::TypedPattern::Destructure(TypedDestructure::Tuple(vec![ + TypedPattern::Read("a".into(), types::INT8, (4, 11)), + TypedPattern::Read("b".into(), types::INT8, (4, 13)), + ])).into() + ), + loc: (4, 2) + }, + block: Vec::new(), + ret: Some(super::TypedExpr::IntegerLiteral { value: "1".into(), size: types::IntWidth::Eight }.into()) + }, + super::TypedMatchArm { + loc:(5,2), + cond: TypedPattern::EnumVariant { + ty: ResolvedType::Dependent { + base: ResolvedType::User { + name: "Test".into(), + generics: Vec::new(), + loc: (1, 5) + } + .into(), + actual: ResolvedType::Void.into(), + generics: Vec::new(), + ident: "Test::B".into(), + loc: (0, 0) + }, variant: "Test::B".into(), + pattern: None, + loc: (5,2) + + }, + block:Vec::new(), + ret: Some(super::TypedExpr::IntegerLiteral { value: "0".into(), size: types::IntWidth::Eight }.into()) + } + ] + })), + generics: None, + abi: None + }) + ); + } } diff --git a/compiler/src/types.rs b/compiler/src/types.rs index 12c558b..6fb671b 100644 --- a/compiler/src/types.rs +++ b/compiler/src/types.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::{typed_ast, util::ExtraUtilFunctions}; +use crate::typed_ast; use itertools::Itertools; #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] @@ -86,39 +86,48 @@ pub enum ResolvedType { Str, //probably going to be implimented as a null checked pointer (at time of creation). Ref { - underlining: Box, + underlining: Box, }, Pointer { - underlining: Box, + underlining: Box, }, Unit, //used as rt only Void, Slice { - underlining: Box, + underlining: Box, }, Function { - arg: Box, - returns: Box, + arg: Box, + returns: Box, loc: crate::Location, }, User { name: String, - generics: Vec, + generics: Vec, + loc: crate::Location, + }, + + /// atm no way to express this in source. Associated types and possibly variant types to come. + Dependent { + base: Box, + ident: String, + actual : Box, + generics: Vec, loc: crate::Location, }, Array { - underlining: Box, + underlining: Box, size: usize, }, // ForwardUser{name:String}, Alias { - actual: Box, + actual: Box, loc: crate::Location, }, Tuple { - underlining: Vec, + underlining: Vec, loc: crate::Location, }, Generic { @@ -269,8 +278,8 @@ impl ResolvedType { pub fn fn_ty(&self, returns: &Self) -> Self { Self::Function { - arg: self.clone().boxed(), - returns: returns.clone().boxed(), + arg: self.clone().into(), + returns: returns.clone().into(), loc: (0, 0), } } @@ -284,16 +293,15 @@ impl ResolvedType { pub fn pass_by_pointer(&self) -> bool { match self { - Self::Array { .. } - | Self::Tuple { .. } - | Self::Function { .. } - | Self::User { .. } => true, - _ => false + Self::Array { .. } | Self::Tuple { .. } | Self::Function { .. } | Self::User { .. } => { + true + } + _ => false, } } pub fn is_array(&self) -> bool { - matches!(self,Self::Array { .. }) + matches!(self, Self::Array { .. }) } pub fn is_user(&self) -> bool { @@ -302,20 +310,20 @@ impl ResolvedType { pub fn get_all_types(&self) -> HashSet { match self { - ResolvedType::User { .. } - | ResolvedType::Bool - | ResolvedType::Int { .. } - | ResolvedType::Float { .. } - | ResolvedType::Char - | ResolvedType::Str => [self.to_string()].into(), - ResolvedType::Ref { underlining } - | ResolvedType::Pointer { underlining } - | ResolvedType::Slice { underlining } - | ResolvedType::Array { underlining, .. } => { + Self::User { .. } + | Self::Bool + | Self::Int { .. } + | Self::Float { .. } + | Self::Char + | Self::Str => [self.to_string()].into(), + Self::Ref { underlining } + | Self::Pointer { underlining } + | Self::Slice { underlining } + | Self::Array { underlining, .. } => { let tys = underlining.get_all_types(); tys } - ResolvedType::Function { + Self::Function { arg, returns, loc: _, @@ -324,23 +332,25 @@ impl ResolvedType { tys.extend(returns.get_all_types().into_iter()); tys } - ResolvedType::Alias { actual, loc: _ } => actual.get_all_types(), - ResolvedType::Tuple { + Self::Alias { actual, loc: _ } => actual.get_all_types(), + Self::Tuple { underlining: underling, loc: _, } => underling.iter().flat_map(Self::get_all_types).collect(), - ResolvedType::Unit - | ResolvedType::Number - | ResolvedType::Void - | ResolvedType::Generic { .. } - | ResolvedType::Unknown(_) => HashSet::new(), - ResolvedType::Error => todo!(), + Self::Dependent { base, .. } => { + base.get_all_types() + // todo associated types. + } + Self::Unit | Self::Number | Self::Void | Self::Generic { .. } | Self::Unknown(_) => { + HashSet::new() + } + Self::Error => todo!(), } } pub fn as_c_function(&self) -> (Vec, Self) { // (args, return type) - match dbg!(self) { + match self { Self::Function { arg, returns, .. } => { let (mut args, rt) = returns.as_c_function(); args.push(arg.as_ref().clone()); @@ -405,24 +415,24 @@ impl ResolvedType { pub(crate) fn replace_user_with_generic(self, target_name: &str) -> Self { match self { ResolvedType::Ref { underlining } => Self::Ref { - underlining: underlining.replace_user_with_generic(target_name).boxed(), + underlining: underlining.replace_user_with_generic(target_name).into(), }, ResolvedType::Pointer { underlining } => Self::Ref { - underlining: underlining.replace_user_with_generic(target_name).boxed(), + underlining: underlining.replace_user_with_generic(target_name).into(), }, ResolvedType::Slice { underlining } => Self::Slice { - underlining: underlining.replace_user_with_generic(target_name).boxed(), + underlining: underlining.replace_user_with_generic(target_name).into(), }, ResolvedType::Function { arg, returns, loc } => Self::Function { - arg: arg.replace_user_with_generic(target_name).boxed(), - returns: returns.replace_user_with_generic(target_name).boxed(), + arg: arg.replace_user_with_generic(target_name).into(), + returns: returns.replace_user_with_generic(target_name).into(), loc: loc, }, ResolvedType::Array { underlining: underlying, size, } => Self::Array { - underlining: underlying.replace_user_with_generic(target_name).boxed(), + underlining: underlying.replace_user_with_generic(target_name).into(), size, }, ResolvedType::User { name, loc, .. } if &name == target_name => { @@ -449,6 +459,9 @@ impl ResolvedType { actual: underlining, .. } + | ResolvedType::Dependent { + base: underlining, .. + } | ResolvedType::Ref { underlining } => underlining.as_mut().lower_generics(context), ResolvedType::Function { arg, returns, .. } => { arg.as_mut().lower_generics(context); @@ -464,6 +477,8 @@ impl ResolvedType { generics.iter().map(ResolvedType::to_string).join(",") ); if !context.generated_generics.contains_key(&new_name) { + // println!("{name}"); + let mut target = context.globals.get(name).unwrap().clone(); let zipped = target .get_generics() @@ -472,7 +487,9 @@ impl ResolvedType { .collect_vec(); target.replace_types(&zipped, context); target.lower_generics(context); - let _ = context.generated_generics.insert(new_name.clone(), target); + let _ = context + .generated_generics + .insert(new_name.clone(), dbg!(target)); } *name = new_name; *generics = Vec::new(); @@ -514,8 +531,8 @@ impl ResolvedType { } } Self::Function { arg, returns, loc } => Self::Function { - arg: arg.replace(nice_name, actual).boxed(), - returns: returns.replace(nice_name, actual).boxed(), + arg: arg.replace(nice_name, actual).into(), + returns: returns.replace(nice_name, actual).into(), loc: *loc, }, _ => self.clone(), @@ -614,6 +631,7 @@ impl ResolvedType { impl ToString for ResolvedType { fn to_string(&self) -> String { match self { + ResolvedType::Dependent { .. } => todo!(), ResolvedType::Number => "{number}".to_string(), ResolvedType::Bool => "bool".to_string(), ResolvedType::Alias { actual, .. } => actual.to_string(), @@ -729,20 +747,20 @@ pub use consts::*; #[cfg(test)] mod tests { - use crate::util::ExtraUtilFunctions; + use pretty_assertions::assert_eq; #[test] #[ignore = "for testing equality"] fn eq() { println!( "{}", super::ResolvedType::Function { - arg: super::INT32.boxed(), - returns: super::INT32.boxed(), + arg: super::INT32.into(), + returns: super::INT32.into(), loc: (0, 0) } == super::ResolvedType::Function { - arg: super::INT32.boxed(), - returns: super::INT32.boxed(), + arg: super::INT32.into(), + returns: super::INT32.into(), loc: (1, 0) } ) diff --git a/compiler/src/util.rs b/compiler/src/util.rs index 22dbd1d..8860118 100644 --- a/compiler/src/util.rs +++ b/compiler/src/util.rs @@ -1,19 +1,3 @@ -use std::{rc::Rc, sync::Arc}; - -pub trait ExtraUtilFunctions: Sized { - fn boxed(self) -> Box { - Box::new(self) - } - fn into_rc(self) -> Rc { - Rc::new(self) - } - - fn into_arc(self) -> Arc { - Arc::new(self) - } -} -impl ExtraUtilFunctions for T {} - pub trait ExtraIterUtils: Iterator { fn advance_by(&mut self, n: usize) { for _ in 0..n { diff --git a/llvm-codegen/Cargo.toml b/llvm-codegen/Cargo.toml index 80de297..3ceb7a2 100644 --- a/llvm-codegen/Cargo.toml +++ b/llvm-codegen/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm15-0-force-dynamic"] } +inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm18-0-force-dynamic"] } compiler = { path = "../compiler" } -itertools = "0.12.1" +itertools = "0.13" multimap = "0.10.0" self_cell = "1.0.3" \ No newline at end of file diff --git a/llvm-codegen/src/code_gen.rs b/llvm-codegen/src/code_gen.rs index a4f20e4..f7b81a2 100644 --- a/llvm-codegen/src/code_gen.rs +++ b/llvm-codegen/src/code_gen.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::convert::TryInto; use std::iter::once; +use compiler::ast::EnumVariant; use inkwell::attributes::Attribute; use inkwell::basic_block::BasicBlock; use inkwell::builder::Builder; @@ -14,7 +15,8 @@ use inkwell::module::Module; use inkwell::targets::TargetData; use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, PointerType, StructType}; use inkwell::values::{ - AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, FunctionValue, GlobalValue, IntValue, PhiValue, PointerValue + AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, FunctionValue, GlobalValue, IntValue, + PhiValue, PointerValue, }; use inkwell::{AddressSpace, FloatPredicate, IntPredicate}; @@ -22,7 +24,10 @@ use itertools::Itertools; use crate::type_resolver::TypeResolver; use compiler::typed_ast::{ - collect_args, ResolvedTypeDeclaration, StructDefinition, TypedArgDeclaration, TypedBinaryOpCall, TypedDeclaration, TypedDestructure, TypedExpr, TypedFnCall, TypedIfBranching, TypedIfExpr, TypedMatch, TypedMatchArm, TypedMemberRead, TypedPattern, TypedStatement, TypedTopLevelValue, TypedValueDeclaration, TypedValueType + collect_args, ResolvedTypeDeclaration, StructDefinition, TypedArgDeclaration, + TypedBinaryOpCall, TypedDeclaration, TypedDestructure, TypedExpr, TypedFnCall, + TypedIfBranching, TypedIfExpr, TypedMatch, TypedMatchArm, TypedMemberRead, TypedPattern, + TypedStatement, TypedTopLevelValue, TypedValueDeclaration, TypedValueType, }; use compiler::types::{self, ResolvedType}; use multimap::MultiMap; @@ -40,7 +45,8 @@ pub struct CodeGen<'ctx> { locals: HashMap>, current_module: String, target_info: TargetData, - curry_ty : StructType<'ctx>, + enum_discrims:HashMap>, + curry_ty: StructType<'ctx>, ret_target: Option>, // debug info starts here dibuilder: Option>, @@ -65,13 +71,10 @@ impl<'ctx> CodeGen<'ctx> { let builder = ctx.create_builder(); let known_functions = seed_functions .into_iter() - .map(|(name, _)| { + .map(|(name, _a)| { let ty = module.get_global(&name).unwrap_or_else(|| { module.add_global( - ctx.struct_type( - &[ctx.i8_type().ptr_type(AddressSpace::default()).into()], - false, - ), + ctx.struct_type(&[ctx.ptr_type(AddressSpace::default()).into()], false), None, &name, ) @@ -79,7 +82,7 @@ impl<'ctx> CodeGen<'ctx> { (name, ty) }) .collect(); - let curry_ty = ctx.struct_type(&[ctx.i8_type().ptr_type(AddressSpace::default()).into()], false); + let curry_ty = ctx.struct_type(&[ctx.ptr_type(AddressSpace::default()).into()], false); Self { ctx, module, @@ -93,6 +96,7 @@ impl<'ctx> CodeGen<'ctx> { locals: HashMap::new(), ret_target: None, current_module: String::new(), + enum_discrims:HashMap::new(), dibuilder: None, compile_unit: None, difile: None, @@ -105,11 +109,11 @@ impl<'ctx> CodeGen<'ctx> { } } - fn compile_arg(&mut self, arg:&TypedArgDeclaration, value:BasicValueEnum<'ctx>) { + fn compile_arg(&mut self, arg: &TypedArgDeclaration, value: BasicValueEnum<'ctx>) { match arg { TypedArgDeclaration::Discard { .. } => { //todo! check if drop/whatever I will call it is needed - }, + } TypedArgDeclaration::Simple { loc, ident, ty } => { let actual_ty = self.type_resolver.resolve_arg_type(ty); let arg = self @@ -118,25 +122,31 @@ impl<'ctx> CodeGen<'ctx> { .unwrap(); let value = self.value_or_load(ty.clone(), value); self.builder.build_store(arg, value).unwrap(); - self.locals.insert(ident.clone(),arg); - }, + self.locals.insert(ident.clone(), arg); + } TypedArgDeclaration::DestructureTuple(contents, ty, loc) => { let ptr = value.into_pointer_value(); - let ty = self.type_resolver.resolve_type_as_basic(ty.clone()).into_struct_type(); - for (idx,arg) in contents.iter().enumerate() { - let gep = self.builder.build_struct_gep(ty, ptr, idx as u32, "").unwrap(); + let ty = self + .type_resolver + .resolve_type_as_basic(ty.clone()) + .into_struct_type(); + for (idx, arg) in contents.iter().enumerate() { + let gep = self + .builder + .build_struct_gep(ty, ptr, idx as u32, "") + .unwrap(); self.compile_arg(arg, gep.as_basic_value_enum()); } - }, - TypedArgDeclaration::DestructureStruct { loc, - struct_ident, - fields, - renamed_fields - }=> { + } + TypedArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => { todo!() - }, - TypedArgDeclaration::Discard { loc, ty } - |TypedArgDeclaration::Unit { loc, ty } => { + } + TypedArgDeclaration::Discard { loc, ty } | TypedArgDeclaration::Unit { loc, ty } => { //TODO debug info for these args. } } @@ -242,18 +252,14 @@ impl<'ctx> CodeGen<'ctx> { curried_args.insert( 0, self.ctx - .i8_type() .ptr_type(AddressSpace::default()) .as_basic_type_enum(), ); let curried_args = curried_args.into_iter().map(|it| it.into()).collect_vec(); let first_arg = v.get_first_param().unwrap().into_pointer_value(); - let actual_ty = self - .ctx - .struct_type(&curried_args, false) - ; + let actual_ty = self.ctx.struct_type(&curried_args, false); self.builder - .build_bitcast(first_arg, actual_ty.ptr_type(AddressSpace::default()), "") + .build_bit_cast(first_arg, self.ctx.ptr_type(AddressSpace::default()), "") .unwrap() }; let actual_ty = { @@ -261,21 +267,21 @@ impl<'ctx> CodeGen<'ctx> { curried_args.insert( 0, self.ctx - .i8_type() .ptr_type(AddressSpace::default()) .as_basic_type_enum(), ); self.ctx.struct_type(&curried_args, false) }; for (idx, arg) in decl.args.iter().enumerate().take(decl.args.len() - 1) { - let gep = self.builder - .build_struct_gep( - actual_ty, - first_arg.into_pointer_value(), - idx as u32 +1, - "", - ) - .unwrap(); + let gep = self + .builder + .build_struct_gep( + actual_ty, + first_arg.into_pointer_value(), + idx as u32 + 1, + "", + ) + .unwrap(); self.compile_arg(arg, gep.as_basic_value_enum()); if let Some(fnscope) = &self.difunction { let Some(dibuilder) = &self.dibuilder else { @@ -363,7 +369,7 @@ impl<'ctx> CodeGen<'ctx> { match decl.value { TypedValueType::Expr(expr) => { let rt = expr.get_ty(); - + let value = self.compile_expr(expr); let value: BasicValueEnum<'ctx> = value.try_into().unwrap(); let ret_bb = self @@ -399,16 +405,23 @@ impl<'ctx> CodeGen<'ctx> { let _ = ret_block.move_after(v.get_last_basic_block().unwrap()); } - fn compile_destructure(&mut self, expr_ty : ResolvedType, value:BasicValueEnum<'ctx>, pat:TypedPattern) { + fn compile_destructure( + &mut self, + expr_ty: ResolvedType, + value: BasicValueEnum<'ctx>, + pat: TypedPattern, + ) { match pat { + TypedPattern::EnumVariant { .. } => todo!("enum variant destructure. should be type checked."), + TypedPattern::Const(_, _) => { println!("invalid code."); - }, - TypedPattern::Read(name, ty, loc) =>{ + } + TypedPattern::Read(name, ty, loc) => { let value = self.value_or_load(ty.clone(), value); let ty = self.type_resolver.resolve_type_as_basic(ty); let target = self.builder.build_alloca(ty, &name).unwrap(); - self.builder.build_store(target,value).unwrap(); + self.builder.build_store(target, value).unwrap(); if let Some(fnscope) = &self.difunction { let Some(dibuilder) = &self.dibuilder else { unreachable!() @@ -442,21 +455,25 @@ impl<'ctx> CodeGen<'ctx> { self.builder.get_insert_block().unwrap(), ); } - - self.locals.insert(name,target); - }, + + self.locals.insert(name, target); + } TypedPattern::Err => println!("errors shouldn't be here"), - TypedPattern::Destructure(TypedDestructure::Unit) | - TypedPattern::Default => (), + TypedPattern::Destructure(TypedDestructure::Unit) | TypedPattern::Default => (), TypedPattern::Or(_, _) => todo!("or patterns aren't allowed in here"), TypedPattern::Destructure(TypedDestructure::Tuple(patterns)) => { let tuple_ty = self.type_resolver.resolve_type_as_basic(expr_ty.clone()); - let ResolvedType::Tuple { underlining, .. } = expr_ty else { unreachable!() }; - for (idx,(pat,expr_ty)) in patterns.into_iter().zip(underlining).enumerate() { - let value = self.builder.build_struct_gep(tuple_ty, value.into_pointer_value(), idx as _, "").unwrap(); + let ResolvedType::Tuple { underlining, .. } = expr_ty else { + unreachable!() + }; + for (idx, (pat, expr_ty)) in patterns.into_iter().zip(underlining).enumerate() { + let value = self + .builder + .build_struct_gep(tuple_ty, value.into_pointer_value(), idx as _, "") + .unwrap(); self.compile_destructure(expr_ty, value.as_basic_value_enum(), pat); } - }, + } TypedPattern::Destructure(TypedDestructure::Struct { fields }) => todo!(), } } @@ -561,9 +578,11 @@ impl<'ctx> CodeGen<'ctx> { for (cond, true_block, cond_block, false_block) in blocks { self.builder.position_at_end(cond_block); let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => { - self.builder.build_load(self.ctx.bool_type(), p, "").unwrap().into_int_value() - } + AnyValueEnum::PointerValue(p) => self + .builder + .build_load(self.ctx.bool_type(), p, "") + .unwrap() + .into_int_value(), AnyValueEnum::IntValue(i) => i, _ => unreachable!(), }; @@ -617,9 +636,11 @@ impl<'ctx> CodeGen<'ctx> { for (cond, true_block, cond_block, false_block) in blocks { self.builder.position_at_end(cond_block); let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => { - self.builder.build_load(self.ctx.bool_type(), p, "").unwrap().into_int_value() - } + AnyValueEnum::PointerValue(p) => self + .builder + .build_load(self.ctx.bool_type(), p, "") + .unwrap() + .into_int_value(), AnyValueEnum::IntValue(i) => i, _ => unreachable!(), }; @@ -665,7 +686,7 @@ impl<'ctx> CodeGen<'ctx> { } else { let expr_ty = expr.get_ty(); let value = self.compile_expr(expr); - + let value = self.value_or_load(expr_ty, value.try_into().unwrap()); if let Some(ret_target) = self.ret_target.as_ref() { self.builder.build_store(*ret_target, value).unwrap(); @@ -743,9 +764,11 @@ impl<'ctx> CodeGen<'ctx> { .get_parent() .unwrap(); let root_cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => { - self.builder.build_load(self.ctx.bool_type(), p, "").unwrap().into_int_value() - } + AnyValueEnum::PointerValue(p) => self + .builder + .build_load(self.ctx.bool_type(), p, "") + .unwrap() + .into_int_value(), AnyValueEnum::IntValue(i) => i, _ => unreachable!(), }; @@ -853,9 +876,11 @@ impl<'ctx> CodeGen<'ctx> { { self.builder.position_at_end(cond_block); let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => { - self.builder.build_load(self.ctx.bool_type(), p, "").unwrap().into_int_value() - } + AnyValueEnum::PointerValue(p) => self + .builder + .build_load(self.ctx.bool_type(), p, "") + .unwrap() + .into_int_value(), AnyValueEnum::IntValue(i) => i, _ => unreachable!(), }; @@ -938,7 +963,10 @@ impl<'ctx> CodeGen<'ctx> { .build_unconditional_branch(continue_block) .unwrap(); self.builder.position_at_end(continue_block); - let result = self.builder.build_load(self.ctx.bool_type(), result, "").unwrap(); + let result = self + .builder + .build_load(self.ctx.bool_type(), result, "") + .unwrap(); result.as_any_value_enum() } @@ -973,7 +1001,10 @@ impl<'ctx> CodeGen<'ctx> { .build_unconditional_branch(continue_block) .unwrap(); self.builder.position_at_end(continue_block); - let result = self.builder.build_load(self.ctx.bool_type(), result, "").unwrap(); + let result = self + .builder + .build_load(self.ctx.bool_type(), result, "") + .unwrap(); result.as_any_value_enum() } @@ -1391,7 +1422,11 @@ impl<'ctx> CodeGen<'ctx> { loc, is_extern, }) => { - let Some(arg) = arg else {unimplemented!("implicit calling not implemented. should be caught by type checker.")}; + let Some(arg) = arg else { + unimplemented!( + "implicit calling not implemented. should be caught by type checker." + ) + }; if is_extern { let TypedExpr::ValueRead(ident, _, _) = *value else { unreachable!( @@ -1408,7 +1443,7 @@ impl<'ctx> CodeGen<'ctx> { loc: _, } = fn_arg_t { - let TypedExpr::TupleLiteral { contents, loc:_ } = *arg else { + let TypedExpr::TupleLiteral { contents, loc: _ } = *arg else { unreachable!("shouldn't be a tuple?") }; contents @@ -1428,14 +1463,13 @@ impl<'ctx> CodeGen<'ctx> { let arg_t = self.type_resolver.resolve_arg_type(&fn_arg_t); let arg = self.compile_expr(*arg); let arg: BasicValueEnum = arg.try_into().unwrap(); - let arg = if arg.is_pointer_value() - && !arg_t.is_pointer_type() - // && !arg - // .into_pointer_value() - // .get_type() - // .get_element_type() - // .is_struct_type() - // need to figure out replacement for this type + let arg = if arg.is_pointer_value() && !arg_t.is_pointer_type() + // && !arg + // .into_pointer_value() + // .get_type() + // .get_element_type() + // .is_struct_type() + // need to figure out replacement for this type { //there has to be a better way to do this. self.builder @@ -1458,19 +1492,42 @@ impl<'ctx> CodeGen<'ctx> { // self.builder.set_current_debug_location(loc); } - let target = self.builder.build_struct_gep(self.curry_ty, value.into_pointer_value(), 0, "").unwrap(); - let target = self.builder.build_load(self.ctx.i8_type().ptr_type(AddressSpace::default()),target, "").unwrap().into_pointer_value(); - let value : BasicValueEnum = value.try_into().unwrap(); - let fn_t = self.type_resolver.resolve_type_as_function(&fn_arg_t.fn_ty(&rt)); + let target = self + .builder + .build_struct_gep(self.curry_ty, value.into_pointer_value(), 0, "") + .unwrap(); + let target = self + .builder + .build_load( + self.ctx.i8_type().ptr_type(AddressSpace::default()), + target, + "", + ) + .unwrap() + .into_pointer_value(); + let value: BasicValueEnum = value.try_into().unwrap(); + let fn_t = self + .type_resolver + .resolve_type_as_function(&fn_arg_t.fn_ty(&rt)); if rt.is_user() { - let result = self.builder.build_alloca( - self.type_resolver.resolve_type_as_basic(rt), - "" - ).unwrap(); - self.builder.build_indirect_call(fn_t, target, &[value.into(),result.into(),arg.into()], "").unwrap(); + let result = self + .builder + .build_alloca(self.type_resolver.resolve_type_as_basic(rt), "") + .unwrap(); + self.builder + .build_indirect_call( + fn_t, + target, + &[value.into(), result.into(), arg.into()], + "", + ) + .unwrap(); result.as_any_value_enum() } else { - self.builder.build_indirect_call(fn_t, target, &[value.into(),arg.into()], "").unwrap().as_any_value_enum() + self.builder + .build_indirect_call(fn_t, target, &[value.into(), arg.into()], "") + .unwrap() + .as_any_value_enum() } /* match value { @@ -1592,7 +1649,7 @@ impl<'ctx> CodeGen<'ctx> { } */ } - // + // // TypedExpr::FnCall(TypedFnCall { value, loc, .. }) => { // //this should only ever be a named value? // if let Some(dibuilder) = &self.dibuilder { @@ -1621,7 +1678,6 @@ impl<'ctx> CodeGen<'ctx> { // .unwrap() // .as_any_value_enum() // } - TypedExpr::ValueRead(ident, _, _) => self .locals .get(&ident) @@ -1663,7 +1719,7 @@ impl<'ctx> CodeGen<'ctx> { .type_resolver .resolve_type_as_basic(ResolvedType::Float { width: size }) .into_float_type(); - let v = ty.const_float_from_string(&value); + let v = unsafe { ty.const_float_from_string(&value) }; v.as_any_value_enum() } TypedExpr::StringLiteral(value) => { @@ -1674,16 +1730,22 @@ impl<'ctx> CodeGen<'ctx> { let str_t = cs.get_type(); // let str_t = self.type_resolver.resolve_type_as_basic(types::STR); let ptr = unsafe { - gs.as_pointer_value().const_in_bounds_gep(str_t,&[ - self.ctx.i32_type().const_zero(), - self.ctx.i32_type().const_zero(), - ]) + gs.as_pointer_value().const_in_bounds_gep( + str_t, + &[ + self.ctx.i32_type().const_zero(), + self.ctx.i32_type().const_zero(), + ], + ) }; let ptr_end = unsafe { - gs.as_pointer_value().const_in_bounds_gep( str_t,&[ - self.ctx.i32_type().const_zero(), - self.ctx.i32_type().const_int(value.len() as u64, false), - ]) + gs.as_pointer_value().const_in_bounds_gep( + str_t, + &[ + self.ctx.i32_type().const_zero(), + self.ctx.i32_type().const_int(value.len() as u64, false), + ], + ) }; let ty = self .type_resolver @@ -1740,12 +1802,12 @@ impl<'ctx> CodeGen<'ctx> { } let result = convert_to_basic_value(self.compile_expr(value)); let result = if result.is_pointer_value() - // && !result - // .get_type() - // .into_pointer_type() - // .get_element_type() - // .is_struct_type() - // TODO! need a replacement + // && !result + // .get_type() + // .into_pointer_type() + // .get_element_type() + // .is_struct_type() + // TODO! need a replacement { self.builder .build_load(target_t, result.into_pointer_value(), "") @@ -1769,9 +1831,13 @@ impl<'ctx> CodeGen<'ctx> { let target_t = self.type_resolver.resolve_type_as_basic(ty); let target_result = self.compile_expr(*target); if let Some(offset) = offset { - self - .builder - .build_struct_gep(target_t, (target_result).into_pointer_value(), offset as _, "") + self.builder + .build_struct_gep( + target_t, + (target_result).into_pointer_value(), + offset as _, + "", + ) .unwrap() .as_any_value_enum() } else { @@ -1779,39 +1845,54 @@ impl<'ctx> CodeGen<'ctx> { } } TypedExpr::Match(match_) => self.compile_match(match_), - TypedExpr::ArrayLiteral { contents, underlining } => { - let arr_ty = self.type_resolver.resolve_type_as_basic(underlining).array_type(contents.len() as u32); + TypedExpr::ArrayLiteral { + contents, + underlining, + } => { + let arr_ty = self + .type_resolver + .resolve_type_as_basic(underlining) + .array_type(contents.len() as u32); let arr = self.builder.build_alloca(arr_ty, "").unwrap(); - for (idx,expr) in contents.into_iter().enumerate() { + for (idx, expr) in contents.into_iter().enumerate() { let ele = convert_to_basic_value(self.compile_expr(expr)); - let loc = unsafe { - self.builder.build_in_bounds_gep( - arr_ty, - arr, - &[ - self.ctx.i32_type().const_zero(), - self.ctx.i32_type().const_int(idx as u64, false) - ], - "" - ).unwrap() + let loc = unsafe { + self.builder + .build_in_bounds_gep( + arr_ty, + arr, + &[ + self.ctx.i32_type().const_zero(), + self.ctx.i32_type().const_int(idx as u64, false), + ], + "", + ) + .unwrap() }; - self.builder.build_store(loc,ele).unwrap(); + self.builder.build_store(loc, ele).unwrap(); } arr.as_any_value_enum() - }, + } TypedExpr::ListLiteral { contents } => todo!(), TypedExpr::TupleLiteral { contents, .. } => { - let tys = contents.iter().map(|it| it.get_ty()).collect(); - let ty = self.type_resolver.resolve_type_as_basic(ResolvedType::Tuple { underlining: tys, loc: (0,0) }); + let ty = self + .type_resolver + .resolve_type_as_basic(ResolvedType::Tuple { + underlining: tys, + loc: (0, 0), + }); let tuple = self.builder.build_alloca(ty, "").unwrap(); - for (idx,expr) in contents.into_iter().enumerate() { + for (idx, expr) in contents.into_iter().enumerate() { let ele = convert_to_basic_value(self.compile_expr(expr)); - let loc = self.builder.build_struct_gep(ty, tuple, idx as u32, "").unwrap(); - self.builder.build_store(loc,ele); + let loc = self + .builder + .build_struct_gep(ty, tuple, idx as u32, "") + .unwrap(); + self.builder.build_store(loc, ele); } tuple.as_any_value_enum() - }, + } TypedExpr::ErrorNode => unreachable!(), } } @@ -1887,32 +1968,16 @@ impl<'ctx> CodeGen<'ctx> { self.compile_function(data); } TypedDeclaration::TypeDefinition(def) => match def { + compiler::typed_ast::ResolvedTypeDeclaration::Enum(enum_) => { + if !enum_.generics.is_none() { + return self.module.clone(); + } + } compiler::typed_ast::ResolvedTypeDeclaration::Struct(def) => { if !def.generics.is_none() { return self.module.clone(); } let strct = self.ctx.get_struct_type(&def.ident).unwrap(); - self.known_types.insert( - def.ident.clone(), - ResolvedTypeDeclaration::Struct(def.clone()), - ); - let fields = def - .fields - .iter() - .map(|field| { - ( - field.name.clone(), - self.type_resolver.resolve_type_as_basic(field.ty.clone()), - ) - }) - .collect_vec(); - let fields_no_name = fields.iter().map(|(_, it)| it.clone()).collect_vec(); - strct.set_body(&fields_no_name, false); - if let Some(_dibuilder) = &self.dibuilder { - if !self.add_struct_di(&def) { - self.needsdi.push(ResolvedTypeDeclaration::Struct(def)); - } - } } _ => todo!(), }, @@ -1965,7 +2030,8 @@ impl<'ctx> CodeGen<'ctx> { } else { let ty = self.type_resolver.resolve_type_as_basic(decl.ty.clone()); let gs = self.module.add_global(ty, None, &decl.ident); - self.known_values.insert(decl.ident.clone(),gs.as_basic_value_enum()); + self.known_values + .insert(decl.ident.clone(), gs.as_basic_value_enum()); } } "intrinsic" => { @@ -1979,35 +2045,134 @@ impl<'ctx> CodeGen<'ctx> { let fun = self.create_curry_list(decl); self.known_functions.insert(decl.ident.clone(), fun); } else if decl.ty.is_function() { - let TypedValueType::Expr(expr) = &decl.value else { unreachable!() }; + let TypedValueType::Expr(expr) = &decl.value else { + unreachable!() + }; let ty = if let TypedExpr::ValueRead(name, _, _) = expr { - self.ctx.struct_type(&[self.ctx.i8_type().ptr_type(AddressSpace::default()).into()], false) + self.ctx.struct_type( + &[self.ctx.i8_type().ptr_type(AddressSpace::default()).into()], + false, + ) } else if let TypedExpr::FnCall(fun) = expr { let fields = self.fold_arg_ty(fun); let fields = [self.ctx.i8_type().ptr_type(AddressSpace::default()).into()] .into_iter() .chain(fields) .collect_vec(); - self.ctx.struct_type(&fields,false) + self.ctx.struct_type(&fields, false) } else { todo!("const other expressions?"); }; let value = self.module.add_global(ty, None, &decl.ident); value.set_initializer(&ty.const_zero()); - self.known_values.insert(decl.ident.clone(),value.as_basic_value_enum()); + self.known_values + .insert(decl.ident.clone(), value.as_basic_value_enum()); } else { let ty = self.type_resolver.resolve_type_as_basic(decl.ty.clone()); let value = self.module.add_global(ty, None, &decl.ident); - self.known_values.insert(decl.ident.clone(),value.as_basic_value_enum()); + self.known_values + .insert(decl.ident.clone(), value.as_basic_value_enum()); todo!("compile time values?") } } TypedDeclaration::TypeDefinition(def) => match def { compiler::typed_ast::ResolvedTypeDeclaration::Struct(decl) => { + dbg!(&decl.ident); if decl.generics.is_some() { return; } - let _strct = self.ctx.opaque_struct_type(&decl.ident); + let strct = self.ctx.opaque_struct_type(&decl.ident); + self.known_types.insert( + decl.ident.clone(), + ResolvedTypeDeclaration::Struct(decl.clone()), + ); + let fields = decl + .fields + .iter() + .map(|field| { + ( + field.name.clone(), + self.type_resolver.resolve_type_as_basic(field.ty.clone()), + ) + }) + .collect_vec(); + let fields_no_name = fields.iter().map(|(_, it)| it.clone()).collect_vec(); + strct.set_body(&fields_no_name, false); + if let Some(_dibuilder) = &self.dibuilder { + if !self.add_struct_di(decl) { + self.needsdi + .push(ResolvedTypeDeclaration::Struct(decl.clone())); + } + } + } + compiler::typed_ast::ResolvedTypeDeclaration::Enum(enum_) => { + let i32_t = self.type_resolver.resolve_type_as_basic(types::INT32); + let i8_t = self.type_resolver.resolve_type_as_basic(types::INT8); + + if enum_.generics.is_some() { + return; + } + let enum_struct = self.ctx.opaque_struct_type(&enum_.ident); + let mut enum_discrims = Vec::new(); + for variant in &enum_.values { + match variant { + compiler::ast::EnumVariant::Unit { ident, .. } + | compiler::ast::EnumVariant::Tuple { ident, .. } + | compiler::ast::EnumVariant::Struct { ident, .. } => { + enum_discrims.push(ident.clone()); + let _variant = self + .ctx + .opaque_struct_type(&format!("{}::{}", &enum_.ident, ident)); + } + } + } + self.known_types.insert( + enum_.ident.clone(), + ResolvedTypeDeclaration::Enum(enum_.clone()), + ); + self.enum_discrims.insert(enum_.ident.clone(),enum_discrims); + let mut max_size = 0; + for variant in &enum_.values { + let variant_struct = self + .ctx + .get_struct_type(&format!("{}::{}", &enum_.ident, &variant.get_ident())) + .unwrap(); + match variant { + EnumVariant::Unit { .. } => variant_struct.set_body(&[], false), + EnumVariant::Tuple { ty, .. } => variant_struct.set_body( + &[i8_t, self.type_resolver.resolve_type_as_basic(ty.clone())], + false, + ), + EnumVariant::Struct { fields, .. } => { + let fields = fields + .iter() + .map(|field| { + ( + field.name.clone(), + self.type_resolver + .resolve_type_as_basic(field.ty.clone()), + ) + }) + .collect_vec(); + let fields_no_name = + fields.iter().map(|(_, it)| it.clone()).collect_vec(); + let sub_struct = self.ctx.struct_type(&fields_no_name, false); + variant_struct.set_body(&[i8_t, sub_struct.into()], false) + } + }; + max_size = max_size.max(self.target_info.get_abi_size(&variant_struct)); + } + enum_struct.set_body( + &[ + i8_t, + i32_t + .array_type( + (max_size / 4 + if max_size % 4 == 0 { 0 } else { 1 }) as u32, + ) + .into(), + ], + false, + ); } _ => todo!(), }, @@ -2018,20 +2183,12 @@ impl<'ctx> CodeGen<'ctx> { let TypedTopLevelValue { ident, args, ty, .. } = decl; - let curry_placeholder = self - .ctx - .struct_type( - &[self.ctx.i8_type().ptr_type(AddressSpace::default()).into()], - false, - ) - .ptr_type(AddressSpace::default()); + let curry_placeholder = self.ctx.ptr_type(AddressSpace::default()); let mut result_ty = ty.clone(); let mut curried_args = Vec::with_capacity(args.len()); let gs = self.module.add_global( - self.ctx.struct_type( - &[self.ctx.i8_type().ptr_type(AddressSpace::default()).into()], - false, - ), + self.ctx + .struct_type(&[self.ctx.ptr_type(AddressSpace::default()).into()], false), None, &ident, ); @@ -2116,20 +2273,19 @@ impl<'ctx> CodeGen<'ctx> { { let bb = self.ctx.append_basic_block(*curr, ""); self.builder.position_at_end(bb); - let first_t = self.ctx.struct_type(&curried_args[..(idx+ 1)], false); + let first_t = self.ctx.struct_type(&curried_args[..(idx + 1)], false); let ret_t = self.ctx.struct_type(&curried_args[..=(idx + 1)], false); let ret = self.builder.build_malloc(ret_t, "ret").unwrap(); - let next_fn_ptr = - next.as_global_value().as_pointer_value(); + let next_fn_ptr = next.as_global_value().as_pointer_value(); let next_ptr = self.builder.build_struct_gep(ret_t, ret, 0, "").unwrap(); self.builder.build_store(next_ptr, next_fn_ptr).unwrap(); let expected = self.ctx.struct_type(&curried_args[..=idx], false); let first_elem = curr.get_first_param().unwrap(); let first_elem = self .builder - .build_bitcast( + .build_bit_cast( first_elem, - expected.ptr_type(AddressSpace::default()), + self.ctx.ptr_type(AddressSpace::default()), "curried", ) .unwrap() @@ -2141,7 +2297,10 @@ impl<'ctx> CodeGen<'ctx> { .builder .build_struct_gep(first_t, first_elem, idx as u32 + 1, "") .unwrap(); - let element = self.builder.build_load(curried_args[idx], element, "").unwrap(); + let element = self + .builder + .build_load(curried_args[idx], element, "") + .unwrap(); let target = self .builder .build_struct_gep(ret_t, ret, idx as u32 + 1, "") @@ -2157,7 +2316,7 @@ impl<'ctx> CodeGen<'ctx> { .unwrap(); let ret = self .builder - .build_bitcast(ret, curry_placeholder, "") + .build_bit_cast(ret, curry_placeholder, "") .unwrap(); self.builder.build_return(Some(&ret)).unwrap(); } @@ -2180,7 +2339,7 @@ impl<'ctx> CodeGen<'ctx> { pub fn compile_module( &mut self, mut ast: compiler::typed_ast::TypedModuleDeclaration, - ) -> (Module<'ctx>,Vec<(TypedTopLevelValue,GlobalValue<'ctx>)>) { + ) -> (Module<'ctx>, Vec<(TypedTopLevelValue, GlobalValue<'ctx>)>) { if self.dibuilder.is_some() { let debug_metadata_version = self.ctx.i32_type().const_int(3, false); self.module.add_basic_value_flag( @@ -2189,13 +2348,12 @@ impl<'ctx> CodeGen<'ctx> { debug_metadata_version, ) } - - ast.declarations.sort_by(|a, b| match (a, b) { - (TypedDeclaration::Value(_), TypedDeclaration::Value(_)) => std::cmp::Ordering::Equal, - (_, TypedDeclaration::Value(_)) => std::cmp::Ordering::Less, - (TypedDeclaration::Value(_), _) => std::cmp::Ordering::Greater, - _ => std::cmp::Ordering::Equal, + let mut ast = dbg!(ast); + ast.declarations.sort_by_key(|it| match it { + TypedDeclaration::TypeDefinition(_) => 0, + TypedDeclaration::Value(_) => 1, + _ => 2, }); for decl in &ast.declarations { @@ -2205,23 +2363,32 @@ impl<'ctx> CodeGen<'ctx> { let _ = self.module.print_to_file("./debug.ll"); let (global_curries, declarations) = { - let mut split = ast.declarations + let mut split = ast + .declarations .into_iter() - .into_group_map_by(|decl| { - match decl { - TypedDeclaration::Value(decl) => decl.args.is_empty(), - TypedDeclaration::TypeDefinition(_) => false, - } + .into_group_map_by(|decl| match decl { + TypedDeclaration::Value(decl) => decl.args.is_empty(), + TypedDeclaration::TypeDefinition(_) => false, }); - let global_curries = if let Some((_,curries)) = split.remove_entry(&true) { curries} else {Vec::new()}; - let others = if let Some((_,others)) = split.remove_entry(&false) { others } else { Vec::new() }; - (global_curries,others) + let global_curries = if let Some((_, curries)) = split.remove_entry(&true) { + curries + } else { + Vec::new() + }; + let others = if let Some((_, others)) = split.remove_entry(&false) { + others + } else { + Vec::new() + }; + (global_curries, others) }; - for decl in declarations.into_iter().filter(|it| match it { TypedDeclaration::Value(TypedTopLevelValue { value, .. }) - if value == &TypedValueType::External =>false, + if value == &TypedValueType::External => + { + false + } _ => true, }) { self.compile_decl(decl); @@ -2250,12 +2417,17 @@ impl<'ctx> CodeGen<'ctx> { if let Some(dibuilder) = &self.dibuilder { dibuilder.finalize() } - let globals = global_curries.into_iter().map(|value|{ - let TypedDeclaration::Value(value) = value else { unreachable!() }; - let gv = self.module.get_global(&value.ident).unwrap(); - (value,gv) - }).collect(); - (self.module.clone(),globals) + let globals = global_curries + .into_iter() + .map(|value| { + let TypedDeclaration::Value(value) = value else { + unreachable!() + }; + let gv = self.module.get_global(&value.ident).unwrap(); + (value, gv) + }) + .collect(); + (self.module.clone(), globals) } pub(crate) fn replace_module(&mut self, new_module: Module<'ctx>) -> Module<'ctx> { @@ -2268,6 +2440,10 @@ impl<'ctx> CodeGen<'ctx> { is_lib: bool, is_debug: bool, ) -> Module<'ctx> { + if self.module.get_global("()").is_none() { + self.module + .add_global(self.ctx.struct_type(&[], false), None, "()"); + } let main_name = ast.iter().find_map(|file| { file.declarations.iter().find_map(|decl| { if let TypedDeclaration::Value(decl) = decl { @@ -2410,7 +2586,7 @@ impl<'ctx> CodeGen<'ctx> { let difile = dibuilder.create_file(&file.name, ""); self.difile = Some(difile); } - let (_,values) = self.compile_module(file); + let (_, values) = self.compile_module(file); globals_to_be_init.extend(values); self.difile = None } @@ -2426,17 +2602,20 @@ impl<'ctx> CodeGen<'ctx> { ); let bb = self.ctx.append_basic_block(entry, ""); self.builder.position_at_end(bb); - for (value,gv) in globals_to_be_init { - - let TypedValueType::Expr(expr) = value.value else { unreachable!() }; - let TypedExpr::FnCall(fun) = &expr else { unreachable!() }; + for (value, gv) in globals_to_be_init { + let TypedValueType::Expr(expr) = value.value else { + unreachable!() + }; + let TypedExpr::FnCall(fun) = &expr else { + unreachable!() + }; let fields = self.fold_arg_ty(fun); - let fields = [self.ctx.i8_type().ptr_type(AddressSpace::default()).into()] - .into_iter() - .chain(fields) - .collect_vec(); - let ty = self.ctx.struct_type(&fields,false); - let ptr_value =self.compile_expr(expr).into_pointer_value(); + let fields = [self.ctx.ptr_type(AddressSpace::default()).into()] + .into_iter() + .chain(fields) + .collect_vec(); + let ty = self.ctx.struct_type(&fields, false); + let ptr_value = self.compile_expr(expr).into_pointer_value(); let value = self.builder.build_load(ty, ptr_value, "").unwrap(); self.builder.build_store(gv.as_pointer_value(), value); self.builder.build_free(ptr_value); @@ -2444,10 +2623,16 @@ impl<'ctx> CodeGen<'ctx> { let gs = self.module.get_global(&main_name).unwrap(); let main = self .builder - .build_load(self.ctx.i8_type().ptr_type(AddressSpace::default()), gs.as_pointer_value(), "main") + .build_load( + self.ctx.ptr_type(AddressSpace::default()), + gs.as_pointer_value(), + "main", + ) .unwrap() .into_pointer_value(); - let main_t = self.type_resolver.resolve_type_as_function(&types::UNIT.fn_ty(&types::UNIT)); + let main_t = self + .type_resolver + .resolve_type_as_function(&types::UNIT.fn_ty(&types::UNIT)); self.builder .build_indirect_call( main_t, @@ -2496,27 +2681,38 @@ impl<'ctx> CodeGen<'ctx> { let on = convert_to_basic_value(self.compile_expr(*on)); let fun = current_block.get_parent().unwrap(); let ret_block = self.ctx.append_basic_block(fun, ""); - let cond_blocks = std::iter::once(current_block).chain(std::iter::repeat_with(|| self.ctx.append_basic_block(fun, ""))).take(arms.len()).collect_vec(); - let values = - arms.into_iter() + let cond_blocks = std::iter::once(current_block) + .chain(std::iter::repeat_with(|| { + self.ctx.append_basic_block(fun, "") + })) + .take(arms.len()) + .collect_vec(); + let values = arms + .into_iter() .zip(&cond_blocks) - .zip(cond_blocks.iter().skip(1).chain(std::iter::once(&ret_block))) - .map(|((arm,cond_block),next_block)| { + .zip( + cond_blocks + .iter() + .skip(1) + .chain(std::iter::once(&ret_block)), + ) + .map(|((arm, cond_block), next_block)| { self.compile_arm(arm, fun, &on, &cond_ty, *cond_block, ret_block, *next_block) - }).collect_vec(); - + }) + .collect_vec(); + self.builder.position_at_end(ret_block); ret_block.move_after(fun.get_last_basic_block().unwrap()); if !rt.is_void_or_unit() { let ty = self.type_resolver.resolve_type_as_basic(rt.clone()); let phi = self.builder.build_phi(ty, "").unwrap(); - for (block,value) in values { + for (block, value) in values { let value = value.unwrap(); let pos = block.get_last_instruction().unwrap(); self.builder.position_before(&pos); let value = self.value_or_load(rt.clone(), value); - - phi.add_incoming(&[(&value,block)]); + + phi.add_incoming(&[(&value, block)]); } self.builder.position_at_end(ret_block); phi.as_any_value_enum() @@ -2534,11 +2730,23 @@ impl<'ctx> CodeGen<'ctx> { fn compile_pattern_simple( &mut self, - pat:TypedPattern, - cond_v : &BasicValueEnum<'ctx>, - cond_ty : &ResolvedType, + pat: TypedPattern, + cond_v: &BasicValueEnum<'ctx>, + cond_ty: &ResolvedType, ) -> IntValue<'ctx> { match pat { + TypedPattern::EnumVariant { variant, .. } if pat.is_simple() => { + let variant_short = if let Some((_,short)) = variant.rsplit_once("::") { + dbg!(short) + } else { + &variant + }; + let ResolvedType::User { name, .. } = cond_ty else { unreachable!() }; + let discrim = dbg!(dbg!(&self.enum_discrims).get(dbg!(name)).unwrap()).iter().position(|it| it==variant_short).unwrap(); + let value = self.builder.build_struct_gep(self.ctx.struct_type(&[self.ctx.i8_type().into()], false), cond_v.into_pointer_value(), 0, "$discrim").unwrap(); + let value = self.builder.build_load(self.ctx.i8_type(),value,"").unwrap(); + self.builder.build_int_compare(IntPredicate::EQ, value.into_int_value(), self.ctx.i8_type().const_int(discrim as _, false), "").unwrap() + } TypedPattern::Default => self.ctx.bool_type().const_int(1, false), TypedPattern::Or(lhs, rhs) => { let lhs = self.compile_pattern_simple(*lhs, cond_v, cond_ty); @@ -2554,7 +2762,7 @@ impl<'ctx> CodeGen<'ctx> { TypedPattern::Const(val, ty) if ty.is_float() => { let cond_v = self.value_or_load(cond_ty.clone(), *cond_v).into_float_value(); let ty = self.type_resolver.resolve_type_as_basic(ty).into_float_type(); - let val = ty.const_float_from_string(&val); + let val = unsafe { ty.const_float_from_string(&val) }; self.builder.build_float_compare(FloatPredicate::UEQ, cond_v, val, "").unwrap() }, TypedPattern::Destructure(TypedDestructure::Tuple(pats)) => { @@ -2575,283 +2783,417 @@ impl<'ctx> CodeGen<'ctx> { .unwrap() } TypedPattern::Destructure(TypedDestructure::Unit) => self.ctx.bool_type().const_int(1, false), - _ => panic!("non simple pattern trying to be evalulated as a simple pattern (eg could be a value read or a non-simple destructure)"), + _ => panic!("non simple pattern trying to be evalulated as a simple pattern (eg could be a value read or a non-simple destructure) {pat:#?}"), } } fn compile_complex_pattern( &mut self, - pat:TypedPattern, - fun : FunctionValue<'ctx>, - cond_v : &BasicValueEnum<'ctx>, - cond_ty : &ResolvedType, - curr_block : BasicBlock<'ctx>, - next_block : BasicBlock<'ctx>, - bindings_block : BasicBlock<'ctx>, - bindings_phi : &mut HashMap>, - bindings_to_make : &mut HashMap>, + pat: TypedPattern, + fun: FunctionValue<'ctx>, + cond_v: &BasicValueEnum<'ctx>, + cond_ty: &ResolvedType, + curr_block: BasicBlock<'ctx>, + next_block: BasicBlock<'ctx>, + bindings_block: BasicBlock<'ctx>, + bindings_phi: &mut HashMap>, + bindings_to_make: &mut HashMap>, ) -> BasicBlock<'ctx> { if pat.is_simple() { let value = self.compile_pattern_simple(pat, cond_v, cond_ty); - for (name,value) in bindings_to_make { + for (name, value) in bindings_to_make { let phi = bindings_phi[name]; - phi.add_incoming(&[(value,curr_block)]); + phi.add_incoming(&[(value, curr_block)]); } - self.builder.build_conditional_branch(value, bindings_block, next_block); + self.builder + .build_conditional_branch(value, bindings_block, next_block); return curr_block; } match pat { + TypedPattern::EnumVariant { variant, pattern:Some(pat), ty, .. } => { + let variant_short = if let Some((_,short)) = variant.rsplit_once("::") { + dbg!(short) + } else { + &variant + }; + let success_block = self.ctx.append_basic_block(fun, dbg!(&variant)); + let _ = success_block.move_after(curr_block); + let ResolvedType::User { name, .. } = cond_ty else { unreachable!() }; + let discrim = dbg!(dbg!(&self.enum_discrims).get(dbg!(name)).unwrap()).iter().position(|it| it==variant_short).unwrap(); + let value = self.builder.build_struct_gep(self.ctx.struct_type(&[self.ctx.i8_type().into()], false), cond_v.into_pointer_value(), 0, "$discrim").unwrap(); + let value = self.builder.build_load(self.ctx.i8_type(),value,"").unwrap(); + let right_variant = self.builder.build_int_compare(IntPredicate::EQ, value.into_int_value(), self.ctx.i8_type().const_int(discrim as _, false), "").unwrap(); + let _ = self.builder.build_conditional_branch(right_variant, success_block, next_block); + self.builder.position_at_end(success_block); + let ResolvedType::Dependent { actual, ident, .. }= ty else { unreachable!() }; + let variant_data_type = self.ctx.get_struct_type(&ident).unwrap(); + let value = self.builder.build_struct_gep(variant_data_type,cond_v.into_pointer_value(),1,"").unwrap(); + self.compile_complex_pattern(*pat, fun, &value.into(), &actual, success_block, next_block, bindings_block, bindings_phi, bindings_to_make) + + }, + TypedPattern::EnumVariant { .. } => unreachable!(), TypedPattern::Destructure(TypedDestructure::Tuple(conds)) => { - let ResolvedType::Tuple { underlining, .. } = cond_ty else { unreachable!() }; + let ResolvedType::Tuple { underlining, .. } = cond_ty else { + unreachable!() + }; let tuple_ty = self.type_resolver.resolve_type_as_basic(cond_ty.clone()); let mut conds = conds .into_iter() .zip(underlining) .enumerate() - .map(|(idx,(cond,ty))| { - (cond,idx,ty) - }) - .into_group_map_by(|(cond,_,_)| cond.is_simple()); - let simple = if let Some((_,simple_conds)) = conds.remove_entry(&true) { - simple_conds.into_iter() - .map(|(pat,idx,ty)| { - let value = self.builder.build_struct_gep(tuple_ty, cond_v.into_pointer_value(), idx as _, "").unwrap(); - self.compile_pattern_simple(pat, &value.as_basic_value_enum(), ty) - }) - .collect_vec() - .into_iter() - .reduce(|accum,next| { - self.builder.build_and(accum,next,"").unwrap() - }).expect("if there is no simple conditions then how did we end up here?") + .map(|(idx, (cond, ty))| (cond, idx, ty)) + .into_group_map_by(|(cond, _, _)| cond.is_simple()); + let simple = if let Some((_, simple_conds)) = conds.remove_entry(&true) { + simple_conds + .into_iter() + .map(|(pat, idx, ty)| { + let value = self + .builder + .build_struct_gep( + tuple_ty, + cond_v.into_pointer_value(), + idx as _, + "", + ) + .unwrap(); + self.compile_pattern_simple(pat, &value.as_basic_value_enum(), ty) + }) + .collect_vec() + .into_iter() + .reduce(|accum, next| self.builder.build_and(accum, next, "").unwrap()) + .expect("if there is no simple conditions then how did we end up here?") } else { self.ctx.bool_type().const_int(1, false) }; - let new_block = self.ctx.append_basic_block(fun, ""); + let new_block = self.ctx.append_basic_block(fun, "complex"); new_block.move_after(curr_block); - self.builder.build_conditional_branch(simple, new_block, next_block); + self.builder + .build_conditional_branch(simple, new_block, next_block); self.builder.position_at_end(new_block); let mut curr_block = new_block; - let mut complex = conds.remove_entry(&false).map(|(_,a)| a).unwrap_or_else(Vec::new); - complex.sort_by_key(|(pat,_,_)| { - match pat { - TypedPattern::Read(_, _, _) => 0, - TypedPattern::Or(_, _) => 2, - // not much should be here as most else will be classed as simple. - _ => 1, + let mut complex = conds + .remove_entry(&false) + .map(|(_, a)| a) + .unwrap_or_else(Vec::new); + complex.retain(|(pat,idx,ty)| { + + let value = self + .builder + .build_struct_gep(tuple_ty, cond_v.into_pointer_value(), *idx as _, "") + .unwrap(); + if let TypedPattern::Read(name,_,_)= pat { + bindings_to_make.insert(name.clone(), value.as_basic_value_enum()); + false + } else { + true } }); - for (pat,idx,ty) in complex { - let value = self.builder.build_struct_gep(tuple_ty, cond_v.into_pointer_value(), idx as _, "").unwrap(); - if let TypedPattern::Read(name, _, _) = pat { - bindings_to_make.insert(name,value.as_basic_value_enum()); - } else { - curr_block = self.compile_complex_pattern( - pat, - fun, - &value.as_basic_value_enum(), - ty, - curr_block, - next_block, - bindings_block, - bindings_phi, - bindings_to_make - ); + // complex.sort_by_key(|(pat, _, _)| { + // match pat { + // TypedPattern::Read(_, _, _) => 0, + // TypedPattern::Or(_, _) => 2, + // // not much should be here as most else will be classed as simple. + // _ => 1, + // } + // }); + if complex.is_empty() { + for (name, value) in bindings_to_make { + let phi = bindings_phi[name]; + phi.add_incoming(&[(value, curr_block)]); + } + self.builder.build_unconditional_branch(bindings_block); + } else { + for (pat, idx, ty) in complex { + let value = self + .builder + .build_struct_gep(tuple_ty, cond_v.into_pointer_value(), idx as _, "") + .unwrap(); + let pat = dbg!(pat); + if let TypedPattern::Read(name, _, _) = pat { + bindings_to_make.insert(name, value.as_basic_value_enum()); + } else { + curr_block = self.compile_complex_pattern( + pat, + fun, + &value.as_basic_value_enum(), + ty, + curr_block, + next_block, + bindings_block, + bindings_phi, + bindings_to_make, + ); + } } } curr_block - }, + } TypedPattern::Destructure(_) => todo!("other kinds of destructure"), TypedPattern::Or(lhs, rhs) => { - let rhs_block = self.ctx.append_basic_block(fun, ""); + let rhs_block = self.ctx.append_basic_block(fun, "or"); rhs_block.move_after(curr_block); let mut lhs_bindings = bindings_to_make.clone(); let curr_block = self.compile_complex_pattern( - *lhs, - fun, - cond_v, - cond_ty, - curr_block, - rhs_block, - bindings_block, - bindings_phi, + *lhs, + fun, + cond_v, + cond_ty, + curr_block, + rhs_block, + bindings_block, + bindings_phi, &mut lhs_bindings, ); - for (name,value) in lhs_bindings { - bindings_phi[&name].add_incoming(&[(&value,curr_block)]); + for (name, value) in lhs_bindings { + bindings_phi[&name].add_incoming(&[(&value, curr_block)]); } self.builder.build_unconditional_branch(bindings_block); self.builder.position_at_end(rhs_block); let curr_block = self.compile_complex_pattern( - *rhs, - fun, - cond_v, - cond_ty, - curr_block, - next_block, - bindings_block, - bindings_phi, - bindings_to_make + *rhs, + fun, + cond_v, + cond_ty, + curr_block, + next_block, + bindings_block, + bindings_phi, + bindings_to_make, ); - for (name,value) in bindings_to_make { - bindings_phi[name].add_incoming(&[(value,curr_block)]); + for (name, value) in bindings_to_make { + bindings_phi[name].add_incoming(&[(value, curr_block)]); } self.builder.build_unconditional_branch(bindings_block); curr_block } TypedPattern::Read(name, _, _) => { - bindings_phi[&name].add_incoming(&[(cond_v,curr_block)]); - for (name,value) in bindings_to_make { - bindings_phi[name].add_incoming(&[(value,curr_block)]); + bindings_phi[&name].add_incoming(&[(cond_v, curr_block)]); + for (name, value) in bindings_to_make { + bindings_phi[name].add_incoming(&[(value, curr_block)]); } self.builder.build_unconditional_branch(next_block); curr_block } TypedPattern::Default => { - for (name,value) in bindings_to_make { - bindings_phi[name].add_incoming(&[(value,curr_block)]); + for (name, value) in bindings_to_make { + bindings_phi[name].add_incoming(&[(value, curr_block)]); } self.builder.build_unconditional_branch(next_block); curr_block - }, + } // handled by the simple case TypedPattern::Const(_, _) => curr_block, - TypedPattern::Err => unreachable!() + TypedPattern::Err => unreachable!(), } } fn compile_pattern( &mut self, - pat : TypedPattern, - fun : FunctionValue<'ctx>, - cond_v : &BasicValueEnum<'ctx>, - cond_ty : &ResolvedType, - curr_block : BasicBlock<'ctx>, - next_block : BasicBlock<'ctx>, - bindings_block : BasicBlock<'ctx>, - bindings_phi : &mut HashMap>, + pat: TypedPattern, + fun: FunctionValue<'ctx>, + cond_v: &BasicValueEnum<'ctx>, + cond_ty: &ResolvedType, + curr_block: BasicBlock<'ctx>, + next_block: BasicBlock<'ctx>, + bindings_block: BasicBlock<'ctx>, + bindings_phi: &mut HashMap>, ) { - match pat { - TypedPattern::Default => { - self.builder.build_unconditional_branch(bindings_block); - }, - TypedPattern::Const(_, _) => { - let cond = self.compile_pattern_simple(pat, cond_v, cond_ty); - self.builder.build_conditional_branch(cond, bindings_block, next_block); - }, - TypedPattern::Read(name, ty, _) => { - //todo debug info - let phi = bindings_phi.entry(name.clone()).or_insert_with(|| { - self.builder.position_at_end(bindings_block); - let phi = self.builder.build_phi(self.ctx.i8_type().ptr_type(AddressSpace::default()), &name).unwrap(); - self.builder.position_at_end(curr_block); - phi - }); - phi.add_incoming(&[(&cond_v.into_pointer_value(),curr_block)]); - }, - TypedPattern::Err => unreachable!(), - TypedPattern::Or(lhs, rhs) => { - let rhs_block = self.ctx.append_basic_block(fun, ""); - rhs_block.move_after(curr_block); - self.compile_pattern(*lhs, fun, cond_v, cond_ty, curr_block, rhs_block, bindings_block, bindings_phi); - self.builder.position_at_end(rhs_block); - self.compile_pattern(*rhs, fun, cond_v, cond_ty, rhs_block, next_block, bindings_block, bindings_phi); - }, - TypedPattern::Destructure(TypedDestructure::Tuple(tuple)) - if tuple.iter().all(|pat| pat.is_simple() || matches!(pat,TypedPattern::Read(_, _, _))) - => { - let mut conds = Vec::with_capacity(tuple.len()); - let ResolvedType::Tuple { underlining, .. } = cond_ty else { unreachable!() }; - let tuple_ty = self.type_resolver.resolve_type_as_basic(cond_ty.clone()); - for (idx,(pat,cond_ty)) in tuple.into_iter().zip(underlining).enumerate() { - let cond_v = self.builder.build_struct_gep(tuple_ty, cond_v.into_pointer_value(), idx as _, "").unwrap(); - if pat.is_simple() { - conds.push(self.compile_pattern_simple(pat, &cond_v.as_basic_value_enum(), cond_ty)) - } else { - self.compile_pattern(pat, fun, &cond_v.as_basic_value_enum(), cond_ty, curr_block, next_block,bindings_block,bindings_phi); - } + match pat { + TypedPattern::Default => { + self.builder.build_unconditional_branch(bindings_block); + } + TypedPattern::Const(_, _) => { + let cond = self.compile_pattern_simple(pat, cond_v, cond_ty); + self.builder + .build_conditional_branch(cond, bindings_block, next_block); + } + TypedPattern::Read(name, ty, _) => { + //todo debug info + let phi = bindings_phi.entry(name.clone()).or_insert_with(|| { + self.builder.position_at_end(bindings_block); + let phi = self + .builder + .build_phi(self.ctx.i8_type().ptr_type(AddressSpace::default()), &name) + .unwrap(); + self.builder.position_at_end(curr_block); + phi + }); + phi.add_incoming(&[(&cond_v.into_pointer_value(), curr_block)]); + } + TypedPattern::Err => unreachable!(), + TypedPattern::Or(lhs, rhs) => { + let rhs_block = self.ctx.append_basic_block(fun, "or"); + rhs_block.move_after(curr_block); + self.compile_pattern( + *lhs, + fun, + cond_v, + cond_ty, + curr_block, + rhs_block, + bindings_block, + bindings_phi, + ); + self.builder.position_at_end(rhs_block); + self.compile_pattern( + *rhs, + fun, + cond_v, + cond_ty, + rhs_block, + next_block, + bindings_block, + bindings_phi, + ); + } + TypedPattern::Destructure(TypedDestructure::Tuple(tuple)) + if tuple + .iter() + .all(|pat| pat.is_simple() || matches!(pat, TypedPattern::Read(_, _, _))) => + { + let mut conds = Vec::with_capacity(tuple.len()); + let ResolvedType::Tuple { underlining, .. } = cond_ty else { + unreachable!() + }; + let tuple_ty = self.type_resolver.resolve_type_as_basic(cond_ty.clone()); + for (idx, (pat, cond_ty)) in tuple.into_iter().zip(underlining).enumerate() { + let cond_v = self + .builder + .build_struct_gep(tuple_ty, cond_v.into_pointer_value(), idx as _, "") + .unwrap(); + if pat.is_simple() { + conds.push(self.compile_pattern_simple( + pat, + &cond_v.as_basic_value_enum(), + cond_ty, + )) + } else { + self.compile_pattern( + pat, + fun, + &cond_v.as_basic_value_enum(), + cond_ty, + curr_block, + next_block, + bindings_block, + bindings_phi, + ); } - match conds.len() { - 0 => self.builder.build_unconditional_branch(bindings_block), - 1 => self.builder.build_conditional_branch(conds.pop().unwrap(), bindings_block, next_block), - _ => { - let fin = conds.into_iter().reduce(|accum,cond| { - self.builder.build_and(accum,cond,"").unwrap() - }).unwrap(); - self.builder.build_conditional_branch(fin, bindings_block, next_block) - } - }.unwrap(); - }, + } + match conds.len() { + 0 => self.builder.build_unconditional_branch(bindings_block), + 1 => self.builder.build_conditional_branch( + conds.pop().unwrap(), + bindings_block, + next_block, + ), + _ => { + let fin = conds + .into_iter() + .reduce(|accum, cond| self.builder.build_and(accum, cond, "").unwrap()) + .unwrap(); + self.builder + .build_conditional_branch(fin, bindings_block, next_block) + } + } + .unwrap(); + } - _ =>{ - let mut bindings = HashMap::new(); - self.compile_complex_pattern( - pat, - fun, - cond_v, - cond_ty, - curr_block, - next_block, - bindings_block, - bindings_phi, - &mut bindings, - ); - }, + _ => { + let mut bindings = HashMap::new(); + self.compile_complex_pattern( + pat, + fun, + cond_v, + cond_ty, + curr_block, + next_block, + bindings_block, + bindings_phi, + &mut bindings, + ); } + } } fn compile_arm( &mut self, - arm:TypedMatchArm, - fun:FunctionValue<'ctx>, - cond_v : &BasicValueEnum<'ctx>, - cond_ty : &ResolvedType, - cond_block : BasicBlock<'ctx>, - ret_block : BasicBlock<'ctx>, - next_block : BasicBlock<'ctx>, + arm: TypedMatchArm, + fun: FunctionValue<'ctx>, + cond_v: &BasicValueEnum<'ctx>, + cond_ty: &ResolvedType, + cond_block: BasicBlock<'ctx>, + ret_block: BasicBlock<'ctx>, + next_block: BasicBlock<'ctx>, ) -> (BasicBlock<'ctx>, Option>) { - let TypedMatchArm { loc, cond, block, ret } = arm; - - let arm_block = self.ctx.append_basic_block(fun, ""); + let TypedMatchArm { + loc, + cond, + block, + ret, + } = arm; + + let arm_block = self.ctx.append_basic_block(fun, "arm"); arm_block.move_after(cond_block); self.builder.position_at_end(cond_block); if cond.is_simple() && cond != TypedPattern::Default { let cond = self.compile_pattern_simple(cond, cond_v, cond_ty); - self.builder.build_conditional_branch(cond, arm_block, next_block); + self.builder + .build_conditional_branch(cond, arm_block, next_block); } else if cond == TypedPattern::Default { self.builder.build_unconditional_branch(arm_block); } else { let bindings_block = self.ctx.append_basic_block(fun, "arm.bindings"); bindings_block.move_after(cond_block); self.builder.position_at_end(bindings_block); - let mut bindings_phi = - cond.get_idents_with_types() + let mut bindings_phi = cond + .get_idents_with_types() .into_iter() - .map(|(name,ty)|{ + .map(|(name, ty)| { let ty = self.type_resolver.resolve_type_as_basic(ty); - let phi = self.builder.build_phi(ty.ptr_type(AddressSpace::default()), &name).unwrap(); - (name,phi) + let phi = self + .builder + .build_phi(ty.ptr_type(AddressSpace::default()), &name) + .unwrap(); + (name, phi) }) .collect(); - self.builder.build_unconditional_branch(arm_block); + self.builder.build_unconditional_branch(arm_block).unwrap(); self.builder.position_at_end(cond_block); - self.compile_pattern(cond, fun, cond_v, cond_ty, cond_block, next_block, bindings_block, &mut bindings_phi); - self.known_values.extend(bindings_phi.into_iter().map(|(name,phi)|(name,phi.as_basic_value()))); + self.compile_pattern( + cond, + fun, + cond_v, + cond_ty, + cond_block, + next_block, + bindings_block, + &mut bindings_phi, + ); + self.known_values.extend( + bindings_phi + .into_iter() + .map(|(name, phi)| (name, phi.as_basic_value())), + ); } self.builder.position_at_end(arm_block); for stmnt in block { self.compile_statement(stmnt); } - let ret = ret.map(|ret| self.compile_expr(*ret)).map(convert_to_basic_value); + let ret = ret + .map(|ret| self.compile_expr(*ret)) + .map(convert_to_basic_value); self.builder.build_unconditional_branch(ret_block); - ( - arm_block, - ret, - ) + (arm_block, ret) } - - fn value_or_load(&mut self, expr_ty: ResolvedType, value:BasicValueEnum<'ctx>) -> BasicValueEnum<'ctx> { + + fn value_or_load( + &mut self, + expr_ty: ResolvedType, + value: BasicValueEnum<'ctx>, + ) -> BasicValueEnum<'ctx> { if value.is_pointer_value() { let ty = self.type_resolver.resolve_type_as_basic(expr_ty); self.builder @@ -2861,8 +3203,10 @@ impl<'ctx> CodeGen<'ctx> { value } } - fn fold_arg_ty(&mut self, fun : &TypedFnCall) -> Vec> { - let TypedFnCall { value, arg, arg_t, .. } = fun; + fn fold_arg_ty(&mut self, fun: &TypedFnCall) -> Vec> { + let TypedFnCall { + value, arg, arg_t, .. + } = fun; let arg_t = self.type_resolver.resolve_type_as_basic(arg_t.clone()); if let TypedExpr::FnCall(fun) = value.as_ref() { let mut out = self.fold_arg_ty(fun); diff --git a/llvm-codegen/src/type_resolver.rs b/llvm-codegen/src/type_resolver.rs index 6d18d0a..c0db63a 100644 --- a/llvm-codegen/src/type_resolver.rs +++ b/llvm-codegen/src/type_resolver.rs @@ -58,12 +58,7 @@ impl<'ctx> TypeResolver<'ctx> { _target_data: target_data, } } - #[allow(unused)] - // TO BE USED IN DU'S TO DETERMINE OVERALL SIZE OF A ENUM TO PROPERLY CREATE THE TYPE. - pub fn get_size_in_bits(&mut self, ty: &ResolvedType) -> u64 { - let ty = self.resolve_type_as_any(ty.clone()); - self._target_data.get_store_size(&ty) - } + pub fn has_type(&self, ty: &ResolvedType) -> bool { self.known.contains_key(ty) @@ -95,9 +90,11 @@ impl<'ctx> TypeResolver<'ctx> { } match dbg!(&ty) { ResolvedType::Array { underlining, size } => { - let result = self.resolve_type_as_basic(underlining.as_ref().clone()).array_type(*size as u32); - self.known.insert(ty,result.as_any_type_enum()); - }, + let result = self + .resolve_type_as_basic(underlining.as_ref().clone()) + .array_type(*size as u32); + self.known.insert(ty, result.as_any_type_enum()); + } ResolvedType::Ref { ref underlining } | ResolvedType::Pointer { ref underlining } => { if let ResolvedType::Function { .. } = underlining.as_ref() { let result = self @@ -125,13 +122,16 @@ impl<'ctx> TypeResolver<'ctx> { .as_any_type_enum(), ); } - ResolvedType::Tuple { underlining, loc:_ } => { - let inners = underlining.iter().map(|ty| self.resolve_type_as_basic(ty.clone())).collect_vec(); - let strct = self.ctx.struct_type(&inners,false); - self.known.insert( - ty, - strct.into() - ); + ResolvedType::Tuple { + underlining, + loc: _, + } => { + let inners = underlining + .iter() + .map(|ty| self.resolve_type_as_basic(ty.clone())) + .collect_vec(); + let strct = self.ctx.struct_type(&inners, false); + self.known.insert(ty, strct.into()); } ResolvedType::Function { .. } => { let r = self @@ -186,7 +186,7 @@ impl<'ctx> TypeResolver<'ctx> { { () } - + ResolvedType::Dependent { actual, .. } => self.resolve_type(actual.as_ref().clone()), _ => unimplemented!(), } } @@ -205,7 +205,10 @@ impl<'ctx> TypeResolver<'ctx> { .struct_type(&[i8_ptr.into()], false) .ptr_type(AddressSpace::default()) .as_basic_type_enum() - } else if ty == &ResolvedType::Str || ty.pass_by_pointer() || matches!(ty, ResolvedType::Tuple { .. }) { + } else if ty == &ResolvedType::Str + || ty.pass_by_pointer() + || matches!(ty, ResolvedType::Tuple { .. }) + { self.resolve_type_as_basic(ty.clone()) .ptr_type(AddressSpace::default()) .as_basic_type_enum() diff --git a/other_sample.fb b/other_sample.fb new file mode 100644 index 0000000..a966d40 --- /dev/null +++ b/other_sample.fb @@ -0,0 +1,9 @@ +enum Testing = | One (int8,int8) | Two +let fun test = match test where +| Testing::One (0,1) -> 0, +| Testing::One (1|0,a) -> a, +| Testing::One _ -> 1, +| Testing::Two -> 2, +| _ -> 3 + +let main () = () \ No newline at end of file diff --git a/sample.fb b/sample.fb index ccb3db2..19364cc 100644 --- a/sample.fb +++ b/sample.fb @@ -6,4 +6,27 @@ let sum2and3_pointfree = sum3 3; let sum1and3and4 = sum2and3_pointfree 4; -let main () = (); \ No newline at end of file +for enum Result = | Ok T | Err E + +for enum Maybe = | None | Some T +for type TestStruct = { + a : T +} +// let use_enum (a:Result) (b:Maybe) = match a where +// | Result::Ok v -> v, +// | Result::Err () -> match b where +// | Maybe::None -> 0, +// | Maybe::Some v -> v, + +let use_struct (a:TestStruct) = (); + +enum Testing = | One (int8,int8) | Two +let fun test = match test where +| Testing::One ((0,1)) -> 0, +| Testing::One ((_,a)) -> a, +| Testing::One _ -> 1, +| Testing::Two -> 2, + +let main () = + let foo = "a\n"; + return ();