diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 6545e4d..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "C_Cpp.intelliSenseEngineFallback": "enabled" -} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 82d3139..713a739 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,91 +3,521 @@ version = 3 [[package]] -name = "bitmaps" -version = "2.1.0" +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "lsp-types" +version = "0.94.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" +dependencies = [ + "bitflags", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ - "typenum", + "pin-project-internal", ] [[package]] -name = "convert_case" -version = "0.6.0" +name = "pin-project-internal" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "unicode-segmentation", + "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] -name = "im-rc" -version = "15.1.0" +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "bitmaps", - "rand_core", - "rand_xoshiro", - "sized-chunks", - "typenum", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", "version_check", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "proc-macro-error-attr" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "signal-hook-registry" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] [[package]] -name = "rand_xoshiro" -version = "0.6.0" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "rand_core", + "autocfg", ] [[package]] -name = "sized-chunks" -version = "0.6.5" +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "socket2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ - "bitmaps", - "typenum", + "libc", + "windows-sys", ] [[package]] name = "syn" -version = "2.0.27" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -95,162 +525,297 @@ dependencies = [ ] [[package]] -name = "typenum" -version = "1.16.0" +name = "syn" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "unicode-ident" -version = "1.0.11" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] [[package]] -name = "unicode-segmentation" -version = "1.10.1" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "version_check" -version = "0.9.4" +name = "tokio" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] [[package]] -name = "vulpi-cli" -version = "0.1.0" +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "vulpi-lexer", - "vulpi-location", - "vulpi-parser", - "vulpi-report", - "vulpi-resolver", - "vulpi-show", - "vulpi-typer", - "vulpi-vfs", + "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] -name = "vulpi-intern" -version = "0.1.0" +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ - "lazy_static", - "vulpi-show", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", ] [[package]] -name = "vulpi-lexer" -version = "0.1.0" +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "vulpi-intern", - "vulpi-location", - "vulpi-report", - "vulpi-syntax", + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", ] [[package]] -name = "vulpi-location" -version = "0.1.0" +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-lsp" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ba052b54a6627628d9b3c34c176e7eda8359b7da9acd497b9f20998d118508" dependencies = [ - "vulpi-show", + "async-trait", + "auto_impl", + "bytes", + "dashmap", + "futures", + "httparse", + "lsp-types", + "memchr", + "serde", + "serde_json", + "tokio", + "tokio-util", + "tower", + "tower-lsp-macros", + "tracing", ] [[package]] -name = "vulpi-macros" -version = "0.1.0" +name = "tower-lsp-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ - "convert_case", "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] -name = "vulpi-parser" -version = "0.1.0" +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "vulpi-intern", - "vulpi-lexer", - "vulpi-location", - "vulpi-report", - "vulpi-syntax", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "vulpi-report" -version = "0.1.0" +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "vulpi-location", - "vulpi-vfs", - "yansi", + "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] -name = "vulpi-resolver" -version = "0.1.0" +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "im-rc", - "vulpi-intern", - "vulpi-location", - "vulpi-macros", - "vulpi-report", - "vulpi-show", - "vulpi-syntax", + "once_cell", ] [[package]] -name = "vulpi-show" -version = "0.1.0" +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] -name = "vulpi-syntax" -version = "0.1.0" +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ - "im-rc", - "vulpi-intern", - "vulpi-location", - "vulpi-macros", - "vulpi-show", + "form_urlencoded", + "idna", + "percent-encoding", + "serde", ] [[package]] -name = "vulpi-tests" +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vulpi-cli" version = "0.1.0" dependencies = [ - "vulpi-lexer", - "vulpi-location", - "vulpi-parser", - "vulpi-report", - "vulpi-resolver", - "vulpi-show", - "vulpi-typer", - "vulpi-vfs", + "tokio", + "vulpi-lsp", ] [[package]] -name = "vulpi-typer" +name = "vulpi-location" +version = "0.1.0" + +[[package]] +name = "vulpi-lsp" version = "0.1.0" dependencies = [ - "im-rc", - "vulpi-intern", - "vulpi-location", - "vulpi-macros", - "vulpi-report", - "vulpi-show", - "vulpi-syntax", + "tokio", + "tower-lsp", ] [[package]] name = "vulpi-vfs" version = "0.1.0" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "vulpi-location", + "windows-targets", ] [[package]] -name = "yansi" -version = "0.5.1" +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index 97a0ae1..a8e3e27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,10 @@ [workspace] members = [ - "crates/vulpi-intern", - "crates/vulpi-lexer", - "crates/vulpi-location", - "crates/vulpi-macros", - "crates/vulpi-parser", - "crates/vulpi-report", - "crates/vulpi-show", - "crates/vulpi-syntax", - "crates/vulpi-tests", - "crates/vulpi-vfs", - "crates/vulpi-resolver", "crates/vulpi-cli", + "crates/vulpi-lsp", + "crates/vulpi-location", + "crates/vulpi-vfs" ] -resolver = "1" +resolver = "2" \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 67a5123..0000000 --- a/README.md +++ /dev/null @@ -1,72 +0,0 @@ -

Vulpi Logo

-

The Vulpi Compiler

- -# Tasks - -- [x] Lexer - - [x] Layout Parsing - - [x] Escape - - [ ] Interpolation -- [ ] Parser - - [x] Types - - [x] Algebraic Data Types - - [x] Declaration - - [ ] Generalized Version - - [X] Kinds - - [x] Records - - [x] Instance - - [x] Update - - [x] Declaration - - [x] Projection - - [x] Effects - - [x] Declaration - - [x] Handler - - [ ] Traits - - [ ] Implementation - - [ ] Constraint Syntax - - [x] Abstract Data Types - - [x] Type Synonyms - - [x] Tuple - - [x] Let declarations - - [x] Let cases - - [x] Patterns - - [ ] Record Pattern - - [x] ADT Pattern - - [x] Guards - - [x] Or Pattern - - [x] Blocks - - [x] Modules - - [x] Public / Private things - - [ ] Deriving Syntax - - [x] Expressions - - [x] Operators - - [ ] Section Patterns - - [ ] Function applications In Half - - [x] Pipe and Composition - - [x] Precedence - - [x] Type ascription - - [x] Function Call - - [x] Let Expression - - [x] Lambda Expression - - [x] Do Expression - - [x] When Expression - - [x] If Expression - - [x] Record Expression - - [x] Tuple Expression - - [ ] List Expression - - [x] Unit expression - - [ ] Attributes - - [x] Import -- [x] Resolution - - [x] Visibility resolution - - [x] Name resolution - - [x] Duplicated pattern name checking - - [x] Or Pattern - - [x] Desugar -- [x] Type checker - - [x] Higher rank polymorphism - - [x] Higher kinded types - - [ ] Entailment - - [ ] Coverage checker -- [ ] Perceus -- [ ] LLVM \ No newline at end of file diff --git a/crates/vulpi-build/Cargo.toml b/crates/vulpi-build/Cargo.toml deleted file mode 100644 index 6509194..0000000 --- a/crates/vulpi-build/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "vulpi-build" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/crates/vulpi-build/src/lib.rs b/crates/vulpi-build/src/lib.rs deleted file mode 100644 index e77916f..0000000 --- a/crates/vulpi-build/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -//! Facilities to build a entire crate of vulpi files. This module is responsible for building the -//! crate from the source files and resolving the modules. diff --git a/crates/vulpi-cli/Cargo.toml b/crates/vulpi-cli/Cargo.toml index f04aea6..32d77c1 100644 --- a/crates/vulpi-cli/Cargo.toml +++ b/crates/vulpi-cli/Cargo.toml @@ -6,14 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] - -vulpi-lexer = { path = "../vulpi-lexer" } -vulpi-location = { path = "../vulpi-location" } -vulpi-parser = { path = "../vulpi-parser" } -vulpi-report = { path = "../vulpi-report" } -vulpi-show = { path = "../vulpi-show" } -vulpi-vfs = { path = "../vulpi-vfs" } -vulpi-resolver = { path = "../vulpi-resolver" } -vulpi-typer = { path = "../vulpi-typer" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-ir = { path = "../vulpi-ir" } +tokio = { version = "1.33.0", features = ["full"] } +vulpi-lsp = {path = "../vulpi-lsp"} diff --git a/crates/vulpi-cli/src/main.rs b/crates/vulpi-cli/src/main.rs index df39595..a62a182 100644 --- a/crates/vulpi-cli/src/main.rs +++ b/crates/vulpi-cli/src/main.rs @@ -1,87 +1,4 @@ -use std::collections::HashSet; -use std::path::PathBuf; - -use vulpi_ir::compiler; -use vulpi_parser::parse; -use vulpi_report::hash_reporter; -use vulpi_report::renderer::classic::Classic; - -use vulpi_report::{hash::HashReporter, Report}; - -use vulpi_resolver::error::ResolverErrorKind; -use vulpi_resolver::io::IO; -use vulpi_resolver::namespaces; -use vulpi_resolver::paths; -use vulpi_resolver::resolver; -use vulpi_resolver::scopes::Symbol; -use vulpi_show::Show; -use vulpi_syntax::concrete::tree::Program; - -use vulpi_typer::type_checker; -use vulpi_vfs::real::RealFileSystem; -use vulpi_vfs::FileSystem; - -pub struct Loader { - pub cwd: PathBuf, - pub reporter: Report, - pub fs: RealFileSystem, - pub loaded: HashSet, -} - -impl Loader { - pub fn new(cwd: PathBuf) -> Self { - Self { - cwd: cwd.clone(), - reporter: Report::new(HashReporter::new()), - fs: RealFileSystem::new(cwd), - loaded: HashSet::new(), - } - } - - #[allow(clippy::result_unit_err)] - pub fn start(&mut self) -> Result { - let Ok(file_id) = self.fs.load(self.cwd.join("main.vp")) else { - return Err(()) - }; - - let Ok(source) = self.fs.read(file_id) else { - return Err(()) - }; - - let program = parse(self.reporter.clone(), file_id, source); - - Ok(program) - } -} - -impl IO for Loader { - fn read_module(&mut self, _id: paths::Path) -> Result { - todo!() - } -} - -fn main() { - let cwd = std::env::current_dir().unwrap(); - let mut loader = Loader::new(cwd.clone()); - let program = loader.start().unwrap(); - - let reporter = hash_reporter(); - let mut namespaces = namespaces(); - - let program = resolver(reporter.clone(), &mut namespaces, &mut loader) - .declare(&program) - .import(&program) - .resolve(program); - - let elaborated = type_checker(reporter.clone()) - .declare(&program) - .define(&program) - .output(); - - if reporter.has_errors() { - let ctx = Classic::new(&loader.fs, cwd); - reporter.to_stderr(ctx) - } else { - let compiler = compiler().first_pass(elaborated); - } +#[tokio::main()] +async fn main() { + vulpi_lsp::start().await; } diff --git a/crates/vulpi-intern/Cargo.toml b/crates/vulpi-intern/Cargo.toml deleted file mode 100644 index b81548a..0000000 --- a/crates/vulpi-intern/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "vulpi-intern" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -vulpi-show = { path = "../vulpi-show" } - -lazy_static = "1.4.0" - -[features] -default = ["single-shot"] -single-shot = [] diff --git a/crates/vulpi-intern/src/lib.rs b/crates/vulpi-intern/src/lib.rs deleted file mode 100644 index 4e4ba72..0000000 --- a/crates/vulpi-intern/src/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! The string interner of the compiler. It is used to store strings in a way that is more efficient -//! than storing them directly. It is also used to make sure that strings are unique. This is -//! important for the compiler because it allows us to compare strings by comparing their ids. None -//! of the implementations implement the [Copy] trait because some of them are heavy to clone. - -#[cfg(feature = "single-shot")] -pub mod no_rc; - -#[cfg(feature = "single-shot")] -pub use no_rc::*; - -use std::marker::PhantomData; - -/// A interned symbol that contains a phantom data to make it unique. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Interned(Symbol, PhantomData); - -impl Interned { - pub fn new(symbol: Symbol) -> Self { - Self(symbol, PhantomData) - } - - pub fn get(&self) -> String { - self.0.get() - } - - pub fn cast(self) -> Interned { - Interned::new(self.0) - } -} - -pub trait Internable: Sized { - fn intern(&self) -> Interned; -} - -impl std::fmt::Debug for Interned { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("Interned") - .field(&self.0) - .field(&self.1) - .finish() - } -} diff --git a/crates/vulpi-intern/src/no_rc.rs b/crates/vulpi-intern/src/no_rc.rs deleted file mode 100644 index 2682bb8..0000000 --- a/crates/vulpi-intern/src/no_rc.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! A simple string interner with no reference counting so it lives until the end of the program. - -use vulpi_show::Show; - -use std::cell::RefCell; -use std::collections::HashMap; -use std::sync::atomic::{AtomicUsize, Ordering}; - -thread_local! { - static INTERNER: Interner = Interner::default(); -} - -/// A symbol is a reference to a string inside the interner. It is used to compare strings by -/// comparing their ids instead of comparing their content because it is more efficient (it makes -/// the comparison an integer comparison instead of a string comparison). -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Symbol { - Generated(usize), - Interned(usize), -} - -impl std::fmt::Debug for Symbol { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.get()) - } -} - -impl Symbol { - pub fn intern(string: &str) -> Self { - INTERNER.with(|i| i.intern(string)) - } - - pub fn get(&self) -> String { - INTERNER.with(|i| i.get(self).unwrap()) - } -} - -impl Show for Symbol { - fn show(&self) -> vulpi_show::TreeDisplay { - vulpi_show::TreeDisplay::label(&format!("Symbol: {}", self.get())) - } -} -#[derive(Default)] -struct Interner { - id_to_string: RefCell>, - string_to_id: RefCell>, - counter: AtomicUsize, -} - -impl Interner { - fn intern(&self, string: &str) -> Symbol { - if let Some(id) = self.string_to_id.borrow().get(string) { - return id.clone(); - } - - let mut id_to_string = self.id_to_string.borrow_mut(); - let mut string_to_id = self.string_to_id.borrow_mut(); - - let id = Symbol::Interned(self.counter.fetch_add(1, Ordering::SeqCst)); - id_to_string.push(string.to_owned()); - string_to_id.insert(string.to_owned(), id.clone()); - - id - } - - fn get(&self, id: &Symbol) -> Option { - match id { - Symbol::Generated(n) => Some(format!("%{n}")), - Symbol::Interned(id) => self.id_to_string.borrow().get(*id).cloned(), - } - } -} diff --git a/crates/vulpi-ir/Cargo.toml b/crates/vulpi-ir/Cargo.toml deleted file mode 100644 index 171b9fd..0000000 --- a/crates/vulpi-ir/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "vulpi-ir" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -vulpi-location = { path = "../vulpi-location" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-intern = { path = "../vulpi-intern" } -vulpi-typer = { path = "../vulpi-typer" } -vulpi-show = { path = "../vulpi-show" } -vulpi-macros = { path = "../vulpi-macros" } diff --git a/crates/vulpi-ir/src/first_pass.rs b/crates/vulpi-ir/src/first_pass.rs deleted file mode 100644 index 616b569..0000000 --- a/crates/vulpi-ir/src/first_pass.rs +++ /dev/null @@ -1,340 +0,0 @@ -use vulpi_syntax::{ - elaborated::{ExprKind, *}, - r#abstract::Qualified, -}; -use vulpi_typer::r#type::TypeKind; - -use crate::{ - ir::{self, FnDecl}, - pattern::{extract_accesors, CaseTree, Problem}, - Context, -}; - -type Type = vulpi_typer::Type; - -pub trait FirstPass { - type Output; - - fn first_pass(self, context: &mut Context) -> Self::Output; -} - -impl FirstPass for Program { - type Output = Vec; - - fn first_pass(self, context: &mut Context) -> Self::Output { - for typ in self.types { - match typ.1 { - TypeDecl::Enum(variants) => { - context.enums.insert(typ.0.clone(), variants.clone()); - for (i, (variant, size)) in variants.iter().enumerate() { - context - .constructors - .insert(variant.clone(), (typ.0.clone(), i, *size)); - } - } - TypeDecl::Record(fields) => { - context.records.insert(typ.0.clone(), fields.clone()); - for (i, field) in fields.iter().enumerate() { - context.fields.insert(field.clone(), (typ.0.clone(), i)); - } - } - _ => (), - } - } - - for effs in self.effects { - context.eff_types.insert(effs.0.clone(), effs.1.clone()); - - for (i, eff) in effs.1.into_iter().enumerate() { - context.effects.insert(eff, (effs.0.clone(), i)); - } - } - - self.lets - .into_iter() - .map(|decl| decl.first_pass(context)) - .collect() - } -} - -impl FirstPass for (Qualified, LetDecl) { - type Output = FnDecl; - - fn first_pass(self, ctx: &mut Context) -> Self::Output { - let (name, decl) = self; - - let mut params = vec![]; - let mut accessors = vec![]; - - for (binder, _) in decl.binders { - match *binder { - PatternKind::Wildcard => params.push(ctx.fresh()), - PatternKind::Variable(x) => params.push(x), - _ => { - let value = ctx.fresh(); - params.push(value.clone()); - let expr = ir::ExprKind::Variable(value); - let new_accessors = extract_accesors(&binder, Box::new(expr)); - accessors.extend(new_accessors); - } - } - } - - let tree = Problem::new(&decl.body); - - let body = tree.compile(); - - let arms: Vec<_> = decl - .body - .into_iter() - .map(|x| (x.patterns, x.expr)) - .collect(); - - let mut bodies = vec![]; - - let arm_params = arms.first().map(|x| x.0.len()).unwrap_or_default(); - let arm_params = (0..arm_params).map(|_| ctx.fresh()).collect::>(); - - for (patterns, body) in arms { - let mut acessors = vec![]; - - for (pattern, param) in patterns.iter().zip(arm_params.iter()) { - let new_accessors = - extract_accesors(pattern, Box::new(ir::ExprKind::Variable(param.clone()))); - acessors.extend(new_accessors); - } - - let body = body.first_pass(ctx); - - let mut accessors: Vec<_> = acessors - .into_iter() - .map(|x| ir::Statement::Let(x.0, x.1)) - .collect(); - - accessors.push(ir::Statement::Expr(body)); - - let block = ir::ExprKind::Block(accessors); - bodies.push(Box::new(block)); - } - - let mut block = accessors - .into_iter() - .map(|(x, y)| ir::Statement::Let(x, y)) - .collect::>(); - - if let CaseTree::Leaf(x) = body { - block.push(ir::Statement::Expr(bodies.swap_remove(x))) - } else { - block.push(ir::Statement::Expr(Box::new(ir::ExprKind::Tree( - body, bodies, - )))); - } - - let body = Box::new(ir::ExprKind::Block(block)); - - FnDecl { name, params, body } - } -} - -impl FirstPass for Literal { - type Output = ir::ExprKind; - - fn first_pass(self, context: &mut Context) -> Self::Output { - match *self { - LiteralKind::String(s) => ir::ExprKind::Literal(ir::Literal::String(s)), - LiteralKind::Integer(i) => ir::ExprKind::Literal(ir::Literal::Integer(i)), - LiteralKind::Float(f) => ir::ExprKind::Literal(ir::Literal::Float(f)), - LiteralKind::Char(c) => ir::ExprKind::Literal(ir::Literal::Char(c)), - LiteralKind::Unit => ir::ExprKind::Tuple(vec![]), - } - } -} - -impl FirstPass for StatementKind { - type Output = Vec; - - fn first_pass(self, context: &mut Context) -> Self::Output { - match self { - StatementKind::Let(l) => match *l.pattern { - PatternKind::Wildcard => vec![ir::Statement::Expr(l.expr.first_pass(context))], - PatternKind::Variable(s) => vec![ir::Statement::Let(s, l.expr.first_pass(context))], - _ => { - let name = context.fresh(); - - let scrutinee = Box::new(ir::ExprKind::Variable(name.clone())); - let accessors = extract_accesors(&l.pattern, scrutinee); - - let first = ir::Statement::Let(name, l.expr.first_pass(context)); - - let accessors = accessors - .into_iter() - .map(|x| ir::Statement::Let(x.0, x.1)) - .collect::>(); - - let mut block = vec![first]; - block.extend(accessors); - - block - } - }, - StatementKind::Expr(expr) => vec![ir::Statement::Expr(expr.first_pass(context))], - StatementKind::Error => unreachable!(), - } - } -} - -impl FirstPass for Expr { - type Output = ir::Expr; - - fn first_pass(self, ctx: &mut Context) -> Self::Output { - match *self { - ExprKind::Lambda(_) => todo!(), - ExprKind::Application(x) => { - let mut args = vec![]; - - for arg in x.args { - args.push(arg.first_pass(ctx)); - } - - let to_add = arrow_spine(x.typ); - - let params = (0..to_add).map(|_| ctx.fresh()).collect::>(); - - for param in params.clone() { - args.push(Box::new(ir::ExprKind::Variable(param.clone()))); - } - - let result = match *x.func { - ExprKind::Constructor(_, name) => { - let (_, i, _) = ctx.constructors.get(&name).unwrap().clone(); - - let tag = Box::new(ir::ExprKind::Tag(name, i)); - - let args = std::iter::once(tag).chain(args.into_iter()).collect(); - - Box::new(ir::ExprKind::Tuple(args)) - } - ExprKind::Function(name, _) => Box::new(ir::ExprKind::Function(name, args)), - _ => { - let func = x.func.first_pass(ctx); - Box::new(ir::ExprKind::Application(func, args)) - } - }; - - if !params.is_empty() { - Box::new(ir::ExprKind::Lambda(params, result)) - } else { - result - } - } - ExprKind::Variable(n) => Box::new(ir::ExprKind::Variable(n)), - ExprKind::Constructor(_, name) => { - let (_, i, size) = ctx.constructors.get(&name).unwrap().clone(); - - let params = (0..size).map(|_| ctx.fresh()).collect::>(); - - let tag = Box::new(ir::ExprKind::Tag(name, i)); - - let args: Vec<_> = params - .iter() - .map(|x| Box::new(ir::ExprKind::Variable(x.clone()))) - .collect(); - - let result: Vec<_> = std::iter::once(tag).chain(args.into_iter()).collect(); - - let result = Box::new(ir::ExprKind::Tuple(result)); - - if !params.is_empty() { - Box::new(ir::ExprKind::Lambda(params, result)) - } else { - result - } - } - ExprKind::Function(name, _) => Box::new(ir::ExprKind::FunPtr(name)), - ExprKind::When(when) => { - let problem = Problem::new(&when.arms); - - let tree = problem.compile(); - - let mut exprs = Vec::new(); - - let scrutinee: Vec<_> = when.scrutinee.iter().map(|_| ctx.fresh()).collect(); - - let mut bodies: Vec<_> = when - .scrutinee - .into_iter() - .zip(scrutinee.iter()) - .map(|(x, name)| ir::Statement::Let(name.clone(), x.first_pass(ctx))) - .collect(); - - for arm in when.arms { - let mut statements = Vec::new(); - - for (i, pat) in arm.patterns.into_iter().enumerate() { - let scrutinee = Box::new(ir::ExprKind::Variable(scrutinee[i].clone())); - - let accessors = extract_accesors(&pat, scrutinee); - - let accessors = accessors - .into_iter() - .map(|x| ir::Statement::Let(x.0, x.1)) - .collect::>(); - - statements.extend(accessors); - } - - statements.push(ir::Statement::Expr(arm.expr.first_pass(ctx))); - - exprs.push(Box::new(ir::ExprKind::Block(statements))) - } - - bodies.push(ir::Statement::Expr(Box::new(ir::ExprKind::Tree( - tree, exprs, - )))); - - Box::new(ir::ExprKind::Block(bodies)) - } - ExprKind::Do(block) => { - let block = block - .into_iter() - .flat_map(|x| x.first_pass(ctx)) - .collect::>(); - - Box::new(ir::ExprKind::Block(block)) - } - ExprKind::Literal(lit) => Box::new(lit.first_pass(ctx)), - ExprKind::Effect(_, _) => todo!(), - ExprKind::Let(_) => todo!(), - ExprKind::Projection(proj) => { - let (name, place) = ctx.fields.get(&proj.field).unwrap(); - todo!() - } - ExprKind::RecordInstance(_) => todo!(), - ExprKind::RecordUpdate(_) => todo!(), - ExprKind::Tuple(_) => todo!(), - ExprKind::Handler(_) => todo!(), - ExprKind::Cases(_) => todo!(), - ExprKind::Error => unreachable!(), - } - } -} - -pub fn arrow_spine(mut typ: Type) -> usize { - let mut count = 0; - - loop { - match typ.as_ref() { - TypeKind::Arrow(l) => { - count += 1; - typ = l.body.clone(); - } - TypeKind::Forall(n) => { - typ = n.body.clone(); - } - TypeKind::Exists(n) => { - typ = n.body.clone(); - } - _ => break count, - } - } -} diff --git a/crates/vulpi-ir/src/ir.rs b/crates/vulpi-ir/src/ir.rs deleted file mode 100644 index e982f44..0000000 --- a/crates/vulpi-ir/src/ir.rs +++ /dev/null @@ -1,48 +0,0 @@ -use vulpi_intern::Symbol; -use vulpi_macros::Show; -use vulpi_syntax::r#abstract::Qualified; - -use crate::pattern::CaseTree; - -#[derive(Clone, Show)] -pub struct FnDecl { - pub name: Qualified, - pub params: Vec, - pub body: Expr, -} - -#[derive(Clone, Show)] -pub enum Literal { - String(Symbol), - Integer(Symbol), - Float(Symbol), - Char(Symbol), -} - -#[derive(Clone, Show)] -pub enum ExprKind { - Variable(Symbol), - Function(Qualified, Vec), - FunPtr(Qualified), - - Lambda(Vec, Expr), - Application(Expr, Vec), - - Projection(Expr, usize), - - Tree(CaseTree, Vec), - - Block(Vec), - - Literal(Literal), - Tuple(Vec), - Tag(Qualified, usize), -} - -#[derive(Clone, Show)] -pub enum Statement { - Let(Symbol, Expr), - Expr(Expr), -} - -pub type Expr = Box; diff --git a/crates/vulpi-ir/src/lib.rs b/crates/vulpi-ir/src/lib.rs deleted file mode 100644 index 9b5adc3..0000000 --- a/crates/vulpi-ir/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Intermediate representation of a Vulpi program. - -use std::collections::HashMap; - -use crate::first_pass::FirstPass; - -use vulpi_intern::Symbol; -use vulpi_show::Show; -use vulpi_syntax::{elaborated::*, r#abstract::Qualified}; -use vulpi_typer::{Real, Type}; - -pub mod first_pass; -pub mod ir; -pub mod pattern; - -#[derive(Default)] -pub struct Context { - pub enums: HashMap>, - pub records: HashMap>, - pub fields: HashMap, - pub constructors: HashMap, - pub eff_types: HashMap>, - pub effects: HashMap, - pub bound: HashMap, - pub counter: usize, -} - -impl Context { - pub fn add_bound(&mut self, name: Symbol) { - let count = self.bound.entry(name).or_insert(0); - *count += 1; - } - - pub fn fresh(&mut self) -> Symbol { - self.counter += 1; - Symbol::Generated(self.counter) - } - - pub fn remove_bound(&mut self, name: Symbol) { - let count = self.bound.entry(name.clone()).or_insert(0); - *count -= 1; - - if *count == 0 { - self.bound.remove(&name); - } - } - - pub fn is_bound(&self, name: Symbol) -> bool { - self.bound.contains_key(&name) - } - - pub fn first_pass(mut self, program: Program>) -> Self { - let result = program.first_pass(&mut self); - println!("{}", result.show()); - self - } -} - -pub fn compiler() -> Context { - Context::default() -} diff --git a/crates/vulpi-ir/src/pattern.rs b/crates/vulpi-ir/src/pattern.rs deleted file mode 100644 index d7395ab..0000000 --- a/crates/vulpi-ir/src/pattern.rs +++ /dev/null @@ -1,244 +0,0 @@ -//! Compilation of patterns - -use std::{ - collections::{HashSet, VecDeque}, - fmt::Display, -}; - -use vulpi_intern::Symbol; -use vulpi_macros::Show; -use vulpi_syntax::{ - elaborated::PatternArm, - elaborated::{Literal, Pattern, PatternKind}, - r#abstract::Qualified, -}; -use vulpi_typer::{Real, Type}; - -use crate::ir::{Expr, ExprKind}; - -#[derive(PartialEq, Hash, Eq, Clone, Show)] -pub enum Case { - Tuple(usize), - Cons(Qualified, usize), - Literal(Literal), - Wildcard, -} - -#[derive(Clone, Debug)] -pub struct Row(usize, VecDeque); - -pub fn head_constructor(pat: &Pattern) -> Option { - match &**pat { - PatternKind::Wildcard => None, - PatternKind::Variable(_) => None, - PatternKind::Literal(pat) => Some(Case::Literal(pat.clone())), - PatternKind::Application(app) => Some(Case::Cons(app.func.clone(), app.args.len())), - PatternKind::Error => unreachable!(), - PatternKind::Tuple(pats) => Some(Case::Tuple(pats.len())), - } -} - -impl Row { - pub fn pop_front(self) -> Self { - let mut pats = self.1; - pats.pop_front(); - Row(self.0, pats) - } - - pub fn preppend(self, patterns: Vec) -> Self { - let mut pats = self.1.clone(); - pats.pop_front(); - let mut vec: VecDeque<_> = patterns.into(); - vec.extend(pats); - Row(self.0, vec) - } - - pub fn first(&self) -> Option<&Pattern> { - self.1.front() - } - - pub fn inline(self) -> Self { - match *self.first().unwrap().clone() { - PatternKind::Wildcard => self.pop_front(), - PatternKind::Variable(_) => self.pop_front(), - PatternKind::Literal(_) => self.pop_front(), - PatternKind::Application(app) => self.preppend(app.args), - PatternKind::Tuple(app) => self.preppend(app), - PatternKind::Error => todo!(), - } - } - - pub fn specialize(self, case: &Case) -> Option { - match (case, &**self.first().unwrap()) { - (Case::Tuple(n), PatternKind::Tuple(pats)) if *n == pats.len() => Some(self.inline()), - (Case::Cons(q, _), PatternKind::Application(a)) if a.func == *q => Some(self.inline()), - (Case::Literal(l), PatternKind::Literal(p)) if l == p => Some(self.inline()), - (Case::Tuple(n), PatternKind::Variable(_) | PatternKind::Wildcard) => { - Some(self.preppend(vec![Box::new(PatternKind::Wildcard); *n])) - } - (Case::Cons(_, n), PatternKind::Variable(_) | PatternKind::Wildcard) => { - Some(self.preppend(vec![Box::new(PatternKind::Wildcard); *n])) - } - (Case::Literal(_), PatternKind::Variable(_) | PatternKind::Wildcard) => { - Some(self.pop_front()) - } - (Case::Wildcard, PatternKind::Variable(_) | PatternKind::Wildcard) => { - Some(self.pop_front()) - } - _ => None, - } - } - - pub fn is_all_wildcards(&self) -> bool { - self.1 - .iter() - .all(|p| matches!(&**p, PatternKind::Wildcard | PatternKind::Variable(_))) - } - - pub fn is_empty(&self) -> bool { - self.1.is_empty() - } - - pub fn len(&self) -> usize { - self.1.len() - } -} - -#[derive(Clone, Show)] -pub enum CaseTree { - Leaf(usize), - Fail, - Select(usize, Vec<(Case, CaseTree)>), -} - -impl Display for Case { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Case::Tuple(n) => write!(f, "tuple({})", n), - Case::Cons(q, n) => write!(f, "cons({}, {})", q.name.get(), n), - Case::Literal(_) => write!(f, "literal"), - Case::Wildcard => write!(f, "wildcard"), - } - } -} - -impl Display for CaseTree { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - CaseTree::Leaf(n) => write!(f, "{}", n), - CaseTree::Fail => write!(f, "fail"), - CaseTree::Select(n, switches) => { - writeln!(f, "select {n} {{")?; - for (case, tree) in switches { - writeln!(f, " {} => {},\n", case, tree)?; - } - write!(f, "}}") - } - } - } -} - -#[derive(Clone)] -pub struct Problem { - pub rows: Vec, - pub place: usize, -} - -impl Problem { - pub fn new(arms: &[PatternArm>]) -> Problem { - let mut rows = vec![]; - - for (i, arm) in arms.iter().enumerate() { - let mut pats = VecDeque::new(); - pats.extend(arm.patterns.clone()); - rows.push(Row(i, pats)); - } - - Problem { rows, place: 0 } - } - - pub fn is_empty(&self) -> bool { - self.rows.is_empty() - } - - pub fn first(&self) -> &Row { - self.rows.first().unwrap() - } - - pub fn specialize(self, place: usize, case: &Case) -> Problem { - Problem { - place, - rows: self - .rows - .into_iter() - .filter_map(|row| row.specialize(case)) - .collect(), - } - } - - pub fn head_constructors(&self) -> HashSet { - self.rows - .iter() - .filter_map(|row| head_constructor(row.first().unwrap())) - .collect() - } - - pub fn compile(self) -> CaseTree { - if self.is_empty() { - CaseTree::Fail - } else if self.first().is_all_wildcards() { - CaseTree::Leaf(self.first().0) - } else { - let head_constructors = self.head_constructors(); - let mut switches = vec![]; - - if head_constructors.is_empty() { - return self - .clone() - .specialize(self.place + 1, &Case::Wildcard) - .compile(); - } - - for (i, constructor) in head_constructors.into_iter().enumerate() { - let subproblem = self.clone().specialize(i, &constructor); - let subswitch = subproblem.compile(); - switches.push((constructor, subswitch)); - } - - CaseTree::Select(self.place, switches) - } - } -} - -pub fn extract_accesors(pat: &Pattern, scrutinee: Expr) -> Vec<(Symbol, Expr)> { - pub fn go(pat: &Pattern, scrutinee: Expr, map: &mut Vec<(Symbol, Expr)>) { - match &**pat { - PatternKind::Wildcard => (), - PatternKind::Variable(s) => map.push((s.clone(), scrutinee)), - PatternKind::Literal(_) => (), - PatternKind::Application(app) => { - for (i, arg) in app.args.iter().enumerate() { - go( - arg, - Box::new(ExprKind::Projection(scrutinee.clone(), i)), - map, - ); - } - } - PatternKind::Tuple(args) => { - for (i, arg) in args.iter().enumerate() { - go( - arg, - Box::new(ExprKind::Projection(scrutinee.clone(), i)), - map, - ); - } - } - PatternKind::Error => unreachable!(), - } - } - - let mut map = vec![]; - go(pat, scrutinee, &mut map); - map -} diff --git a/crates/vulpi-lexer/Cargo.toml b/crates/vulpi-lexer/Cargo.toml deleted file mode 100644 index e85fb32..0000000 --- a/crates/vulpi-lexer/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "vulpi-lexer" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - - -vulpi-intern = { path = "../vulpi-intern" } -vulpi-location = { path = "../vulpi-location" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-report = { path = "../vulpi-report" } diff --git a/crates/vulpi-lexer/src/error.rs b/crates/vulpi-lexer/src/error.rs deleted file mode 100644 index 256f8cf..0000000 --- a/crates/vulpi-lexer/src/error.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Error types for the lexing process. These are converted into [vulpi_report::Diagnostic]. - -use vulpi_location::Span; -use vulpi_report::IntoDiagnostic; - -/// The kind of lexing error. -pub enum ErrorKind { - UnfinishedString, -} - -/// A lexing error. -pub struct Error { - pub location: Span, - pub message: ErrorKind, -} - -impl IntoDiagnostic for Error { - fn message(&self) -> vulpi_report::Text { - match self.message { - ErrorKind::UnfinishedString => vulpi_report::Text::from("unfinished string literal"), - } - } - - fn severity(&self) -> vulpi_report::Severity { - vulpi_report::Severity::Error - } - - fn location(&self) -> Span { - self.location.clone() - } -} diff --git a/crates/vulpi-lexer/src/lib.rs b/crates/vulpi-lexer/src/lib.rs deleted file mode 100644 index b165ccf..0000000 --- a/crates/vulpi-lexer/src/lib.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! The entry point for the Vulpi Lexer. This module contains the first phase o all of the -//! compilers, the lexing phase. This phase splits a source code into [Token]s that are like "words" -//! that contain no connection to other "words". e.g -//! -//! ```hs -//! // If we had a function called lex that given a source code returns a [Vec] then: -//! lex("1 + 2") -//! // Would return -//! vec![Token::Num(1), Token::Plus, Token::Num(2)] -//! ``` -//! -//! This example does not connect tokens it only classify and return a vector of them. The Vulpi -//! lexer, instead, return [Token]s on demand and work with white spaces in order to make -//! *layout parsing* just like haskell. -//! -//! The layout parsing of Vulpi gets whitespace information and turns this information into a set of -//! virtual braces and semicolons. e.g. -//! -//! ```hs -//! do -//! a c -//! b -//! ``` -//! -//! Turns into -//! -//! ```hs -//! do { a c; b; } -//! ``` -//! -//! Following these rules: -//! - Some words are *layout keywords*, these keywords start blocks of indentation and: -//! - We start a new layout block emitting a block start and push the current column to the stack -//! after eating all of the spaces and newlines after the layout keyword. -//! - If it's a newline then we need to run the rule -//! - We get the last layout from the stack and we compare if the current column is: -//! - Greater: We just continue to the next rule -//! - Equal: We emit a semicolon -//! - Less: We emit a block end -//! - -pub mod error; -mod literals; - -use std::{iter::Peekable, str::Chars}; - -use vulpi_intern::Symbol; -use vulpi_location::{Byte, FileId, Span, Spanned}; -use vulpi_report::{Diagnostic, Report}; -use vulpi_syntax::tokens::{Comment, Token, TokenData}; - -/// Checks if a char is a valid identifier part. -fn is_identifier_char(char: &char) -> bool { - char.is_alphanumeric() || matches!(char, |'_'| '!' | '?' | '\'') -} - -/// Checks if a char is a whitespace, tab or something like that. -fn is_whitespace(char: &char) -> bool { - matches!(char, '\t' | '\x0C' | '\r' | ' ') -} - -/// Checks if a char is a whitespace, tab or something like that. -fn is_whitespace_or_line_break(char: &char) -> bool { - matches!(char, '\n') || is_whitespace(char) -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Either { - Left(T), - Right(U), -} - -#[derive(Clone)] -enum LexState { - Common, - PushLayout, -} -/// A state that can be stored and recovered further in the lexing process. -#[derive(Clone)] -pub struct State { - index: usize, - start: usize, - column: usize, - line: usize, - file: FileId, - layout: Vec, - lex_state: LexState, - reporter: Report, -} - -/// The lexer struct that contains the input and the current state. This struct is the entry point -/// for the lexer. -#[derive(Clone)] -pub struct Lexer<'a> { - peekable: Peekable>, - input: &'a str, - state: State, -} - -impl<'a> Lexer<'a> { - pub fn new(input: &'a str, file: FileId, reporter: Report) -> Self { - Self { - peekable: input.chars().peekable(), - input, - state: State { - index: 0, - start: 0, - line: 0, - file, - column: 0, - layout: vec![], - lex_state: LexState::Common, - reporter, - }, - } - } - - pub fn from(state: State, input: &'a str) -> Self { - Self { - peekable: input[state.index..].chars().peekable(), - input, - state, - } - } - - fn advance(&mut self) -> Option { - let char = self.peekable.next()?; - self.state.index += char.len_utf8(); - - self.state.column += 1; - - if char == '\n' { - self.state.column = 0; - self.state.line += 1; - } - - Some(char) - } - - fn save(&mut self) { - self.state.start = self.state.index; - } - - fn span(&self) -> Span { - Span { - file: self.state.file, - start: Byte(self.state.start), - end: Byte(self.state.index), - } - } - - fn report(&mut self, message: error::ErrorKind) { - self.state.reporter.report(Diagnostic::new(error::Error { - location: self.span(), - message, - })); - } - - fn spanned(&self, token: T) -> Spanned { - Spanned::new(token, self.span()) - } - - fn accumulate(&mut self, predicate: fn(&char) -> bool) { - while let Some(char) = self.peekable.peek() { - if predicate(char) { - self.advance(); - } else { - break; - } - } - } - - fn lex_whitespace(&mut self) -> Spanned { - self.save(); - - self.accumulate(is_whitespace_or_line_break); - - let whitespace = &self.input[self.state.start..self.state.index]; - let whitespace = Symbol::intern(whitespace); - - self.spanned(whitespace) - } - - fn lex_comment(&mut self) -> Either> { - let whitespace = self.lex_whitespace(); - - self.save(); - - let mut cloned = self.peekable.clone(); - cloned.next(); - - if let Some(('-', '-')) = self.peekable.peek().zip(cloned.peek()) { - self.accumulate(|char| *char != '\n'); - let symbol = Symbol::intern(&self.input[self.state.start..self.state.index]); - let comment = self.spanned(symbol); - - Either::Left(Comment { - comment, - whitespace, - }) - } else { - Either::Right(whitespace) - } - } - - fn lex_comments(&mut self) -> (Vec, Spanned) { - let mut comments = vec![]; - - loop { - match self.lex_comment() { - Either::Left(comment) => comments.push(comment), - Either::Right(whitespace) => break (comments, whitespace), - } - } - } - - fn classify_identifier(&mut self) -> TokenData { - let data = &self.input[self.state.start..self.state.index]; - match data { - "is" => { - self.state.lex_state = LexState::PushLayout; - TokenData::Is - } - "do" => { - self.state.lex_state = LexState::PushLayout; - TokenData::Do - } - "where" => { - self.state.lex_state = LexState::PushLayout; - TokenData::Where - } - "cases" => { - self.state.lex_state = LexState::PushLayout; - TokenData::Cases - } - "effect" => TokenData::Effect, - "handle" => TokenData::Handle, - "mod" => TokenData::Mod, - "let" => TokenData::Let, - "when" => TokenData::When, - "with" => TokenData::With, - "if" => TokenData::If, - "else" => TokenData::Else, - "then" => TokenData::Then, - "use" => TokenData::Use, - "as" => TokenData::As, - "type" => TokenData::Type, - "pub" => TokenData::Pub, - "in" => TokenData::In, - "forall" => TokenData::Forall, - "_" => TokenData::Wildcard, - "external" => TokenData::External, - _ => TokenData::LowerIdent, - } - } - - fn classify_token(&mut self, line: usize) -> (TokenData, Symbol) { - let last_layout = self.state.layout.last(); - - let cond = last_layout.is_some() && self.state.column < *last_layout.unwrap(); - if line != self.state.line || cond { - let column = self.state.column; - let last = self.state.layout.last(); - - match last { - None => (), - Some(last_column) if column > *last_column => (), - Some(last_column) if column < *last_column => { - self.state.layout.pop(); - return (TokenData::End, Symbol::intern("end")); - } - Some(_) => return (TokenData::Sep, Symbol::intern("sep")), - } - } - - let result = if let Some(char) = self.advance() { - match char { - '{' => TokenData::LBrace, - '}' => TokenData::RBrace, - '(' => { - if let Some(')') = self.peekable.peek() { - self.advance(); - TokenData::Unit - } else { - TokenData::LPar - } - } - ')' => TokenData::RPar, - '[' => TokenData::LBracket, - ']' => TokenData::RBracket, - '<' => { - if let Some('-') = self.peekable.peek() { - self.advance(); - TokenData::LeftArrow - } else { - TokenData::Less - } - } - '>' => { - if let Some('=') = self.peekable.peek() { - self.advance(); - TokenData::GreaterEqual - } else { - TokenData::Greater - } - } - '-' => { - if let Some('>') = self.peekable.peek() { - self.advance(); - TokenData::RightArrow - } else { - TokenData::Minus - } - } - '+' => TokenData::Plus, - '*' => TokenData::Star, - '/' => TokenData::Slash, - '\\' => TokenData::BackSlash, - '%' => TokenData::Percent, - '^' => TokenData::Caret, - '&' => { - if let Some('&') = self.peekable.peek() { - self.advance(); - TokenData::And - } else { - TokenData::Ampersand - } - } - '|' => { - if let Some('|') = self.peekable.peek() { - self.advance(); - TokenData::Or - } else if let Some('>') = self.peekable.peek() { - self.advance(); - TokenData::PipeRight - } else { - TokenData::Bar - } - } - '~' => TokenData::Tilde, - '!' => { - if let Some('=') = self.peekable.peek() { - self.advance(); - TokenData::NotEqual - } else { - TokenData::Exclamation - } - } - '=' => { - if let Some('=') = self.peekable.peek() { - self.advance(); - TokenData::DoubleEqual - } else if let Some('>') = self.peekable.peek() { - self.advance(); - TokenData::FatArrow - } else { - TokenData::Equal - } - } - ':' => TokenData::Colon, - ';' => TokenData::Semicolon, - ',' => TokenData::Comma, - '.' => TokenData::Dot, - '0'..='9' => { - self.accumulate(|char| char.is_ascii_digit()); - if let Some('.') = self.peekable.peek() { - self.advance(); - self.accumulate(|char| char.is_ascii_digit()); - TokenData::Float - } else { - TokenData::Int - } - } - '"' => return self.string(), - 'A'..='Z' => { - self.accumulate(is_identifier_char); - TokenData::UpperIdent - } - c if is_identifier_char(&c) => { - self.accumulate(is_identifier_char); - self.classify_identifier() - } - _ => TokenData::Error, - } - } else if self.state.layout.pop().is_some() { - TokenData::End - } else { - TokenData::Eof - }; - - let symbol = Symbol::intern(&self.input[self.state.start..self.state.index]); - (result, symbol) - } - - pub fn pop_layout(&mut self) { - self.state.layout.pop(); - } - - /// Lexes a single token from the input. - pub fn bump(&mut self) -> Token { - let line = self.state.line; - - let (comments, whitespace) = self.lex_comments(); - self.save(); - - let (kind, value) = match self.state.lex_state { - LexState::Common => self.classify_token(line), - - LexState::PushLayout => { - self.state.lex_state = LexState::Common; - - let last = self.state.layout.last().copied().unwrap_or_default(); - - if self.state.column <= last { - self.classify_token(line) - } else { - self.state.layout.push(self.state.column); - (TokenData::Begin, Symbol::intern("begin")) - } - } - }; - - Token { - comments, - whitespace, - kind, - value: self.spanned(value), - } - } -} - -impl<'a> Iterator for Lexer<'a> { - type Item = Token; - - fn next(&mut self) -> Option { - if self.state.index >= self.input.len() { - None - } else { - Some(self.bump()) - } - } -} - -#[cfg(test)] -mod tests { - use vulpi_report::hash::HashReporter; - - use super::*; - - #[test] - fn test_lex() { - let mut lexer = Lexer::new( - " - let x = - \"a\\\"ta\" - ", - FileId(0), - Report::new(HashReporter::new()), - ); - - let mut token = lexer.bump(); - - while token.kind != TokenData::Eof { - token = lexer.bump(); - assert!(token.kind != TokenData::Error); - } - } -} diff --git a/crates/vulpi-lexer/src/literals.rs b/crates/vulpi-lexer/src/literals.rs deleted file mode 100644 index 71ad25c..0000000 --- a/crates/vulpi-lexer/src/literals.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Lexing of literals like strings, integers, floats, etc. - -use vulpi_intern::Symbol; -use vulpi_syntax::tokens::TokenData; - -use crate::{error::ErrorKind, Lexer}; - -impl<'a> Lexer<'a> { - /// Parses a character of a char literal - pub fn char(&mut self) -> Option { - match self.peekable.peek() { - Some('\\') => self.escape(), - Some(_) => self.advance(), - None => None, - } - } - - /// Parses escaped characters - pub(crate) fn escape(&mut self) -> Option { - self.advance(); - - let result = match self.peekable.peek() { - Some('n') => '\n', - Some('r') => '\r', - Some('t') => '\t', - Some('0') => '\0', - Some('\\') => '\\', - Some('\'') => '\'', - Some('"') => '"', - _ => return None, - }; - - self.advance(); - - Some(result) - } - - pub(crate) fn string(&mut self) -> (TokenData, Symbol) { - let mut string = String::new(); - - while let Some(c) = self.peekable.peek() { - match c { - '\\' => { - if let Some(res) = self.escape() { - string.push(res); - } else { - self.accumulate(|x| *x != '"'); - return (TokenData::Error, Symbol::intern(&string)); - } - } - '"' => break, - _ => { - string.push(self.advance().unwrap()); - } - } - } - - if let Some('"') = self.peekable.peek() { - self.advance(); - (TokenData::String, Symbol::intern(&string)) - } else { - self.report(ErrorKind::UnfinishedString); - (TokenData::Error, Symbol::intern(&string)) - } - } -} diff --git a/crates/vulpi-location/Cargo.toml b/crates/vulpi-location/Cargo.toml index 7bafbbc..58cc76c 100644 --- a/crates/vulpi-location/Cargo.toml +++ b/crates/vulpi-location/Cargo.toml @@ -6,4 +6,3 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vulpi-show = { path = "../vulpi-show" } diff --git a/crates/vulpi-location/src/lib.rs b/crates/vulpi-location/src/lib.rs index a874ffd..03efef0 100644 --- a/crates/vulpi-location/src/lib.rs +++ b/crates/vulpi-location/src/lib.rs @@ -1,98 +1,10 @@ -//! This module exposes a lot of structures that locate things inside a source code. It's really -//! useful to generate error messages. - -use std::fmt::Debug; - -use vulpi_show::{Show, TreeDisplay}; - -/// A new-type for a usize. It's used to locate a byte inside a source code. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] -pub struct Byte(pub usize); - -/// A span that locates a piece of data inside a source code. -#[derive(Clone, Default)] pub struct Span { - pub file: FileId, - pub start: Byte, - pub end: Byte, -} - -impl Show for Span { - fn show(&self) -> vulpi_show::TreeDisplay { - TreeDisplay::label("Span").with(TreeDisplay::label(&format!( - "{}~{}", - self.start.0, self.end.0 - ))) - } -} - -impl Debug for Span { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}~{:?}", self.start.0, self.end.0) - } + pub start: usize, + pub end: usize, } impl Span { - pub fn new(file: FileId, start: Byte, end: Byte) -> Self { - Self { file, start, end } - } - - pub fn from_usize(file: FileId, start: usize, end: usize) -> Self { - Self { - file, - start: Byte(start), - end: Byte(end), - } - } - - pub fn mix(self, other: Self) -> Self { - Self { - file: self.file, - start: std::cmp::min(self.start, other.start), - end: std::cmp::max(self.end, other.end), - } - } -} - -/// A span that locates a piece of data inside a source code. -#[derive(Clone)] -pub struct Spanned { - pub data: T, - pub span: Span, -} - -impl Show for Spanned { - fn show(&self) -> vulpi_show::TreeDisplay { - TreeDisplay::label("Spanned") - .with(TreeDisplay::label(&format!( - "{}~{}", - self.span.start.0, self.span.end.0 - ))) - .with(self.data.show()) + pub fn new(start: usize, end: usize) -> Self { + Self { start, end } } -} - -impl Spanned { - pub fn map(&self, f: impl FnOnce(&T) -> U) -> Spanned { - Spanned { - data: f(&self.data), - span: self.span.clone(), - } - } -} - -impl Debug for Spanned { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("Spanned").field(&self.data).finish() - } -} - -impl Spanned { - pub fn new(data: T, range: Span) -> Self { - Self { data, span: range } - } -} - -/// The identifier of a file. -#[derive(Clone, Default, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct FileId(pub usize); +} \ No newline at end of file diff --git a/crates/vulpi-show/Cargo.toml b/crates/vulpi-lsp/Cargo.toml similarity index 73% rename from crates/vulpi-show/Cargo.toml rename to crates/vulpi-lsp/Cargo.toml index cfb32f1..579ea95 100644 --- a/crates/vulpi-show/Cargo.toml +++ b/crates/vulpi-lsp/Cargo.toml @@ -1,8 +1,10 @@ [package] -name = "vulpi-show" +name = "vulpi-lsp" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +tokio = "1.33.0" +tower-lsp = "0.20.0" diff --git a/crates/vulpi-lsp/src/lib.rs b/crates/vulpi-lsp/src/lib.rs new file mode 100644 index 0000000..7149614 --- /dev/null +++ b/crates/vulpi-lsp/src/lib.rs @@ -0,0 +1,58 @@ +use tower_lsp::jsonrpc::Result; +use tower_lsp::lsp_types::*; +use tower_lsp::{Client, LanguageServer, LspService, Server}; + +#[derive(Debug)] +struct Backend { + client: Client, +} + +#[tower_lsp::async_trait] +impl LanguageServer for Backend { + async fn initialize(&self, _: InitializeParams) -> Result { + Ok(InitializeResult { + capabilities: ServerCapabilities { + hover_provider: Some(HoverProviderCapability::Simple(true)), + completion_provider: Some(CompletionOptions::default()), + ..Default::default() + }, + ..Default::default() + }) + } + + async fn initialized(&self, _: InitializedParams) { + self.client + .log_message(MessageType::INFO, "server initialized!") + .await; + } + + async fn shutdown(&self) -> Result<()> { + Ok(()) + } + + async fn completion(&self, _: CompletionParams) -> Result> { + Ok(Some(CompletionResponse::Array(vec![ + CompletionItem::new_simple("Hello".to_string(), "Some detail".to_string()), + CompletionItem::new_simple("Bye".to_string(), "More detail".to_string()) + ]))) + } + + async fn hover(&self, _: HoverParams) -> Result> { + Ok(Some(Hover { + contents: HoverContents::Scalar( + MarkedString::String("You're hovering!".to_string()) + ), + range: None + })) + } +} + + +pub async fn start() { + let stdin = tokio::io::stdin(); + let stdout = tokio::io::stdout(); + + let (service, socket) = LspService::new(|client| Backend { client }); + Server::new(stdin, stdout, socket).serve(service).await; +} + diff --git a/crates/vulpi-macros/Cargo.toml b/crates/vulpi-macros/Cargo.toml deleted file mode 100644 index 4cf6d06..0000000 --- a/crates/vulpi-macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "vulpi-macros" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -proc-macro = true - -[dependencies] -convert_case = "0.6.0" -proc-macro2 = "1.0.60" -quote = "1.0.28" -syn = { version = "2.0", features = ["full"] } diff --git a/crates/vulpi-macros/src/lib.rs b/crates/vulpi-macros/src/lib.rs deleted file mode 100644 index 136e1ea..0000000 --- a/crates/vulpi-macros/src/lib.rs +++ /dev/null @@ -1,122 +0,0 @@ -#![allow(clippy::redundant_clone)] - -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::Item; - -#[proc_macro_derive(Show, attributes(helper))] -pub fn derive_helper_attr(item: TokenStream) -> TokenStream { - let parsed = syn::parse::(item).unwrap(); - - let name; - let mut sttms = vec![quote! { - use vulpi_show::{TreeDisplay}; - }]; - - let gen; - - match parsed { - Item::Enum(enum_) => { - name = enum_.ident; - - gen = enum_.generics; - - let mut variants = vec![]; - - for variant in &enum_.variants { - let mut counter = 0; - - let name_str = variant.ident.to_string(); - let mut variant_fields = vec![quote! { let res = TreeDisplay::label(#name_str); }]; - let mut names = Vec::new(); - - for field in &variant.fields { - if let Some(ident) = &field.ident { - names.push(ident.clone()); - let name_str = ident.to_string(); - variant_fields.push(quote! { - let res = res.with(TreeDisplay::label(#name_str).with(#name.show())); - }); - } else { - let name = syn::Ident::new( - &format!("field{}", counter), - proc_macro2::Span::call_site(), - ); - names.push(name.clone()); - counter += 1; - variant_fields.push(quote! { - let res = res.with(#name.show()); - }); - }; - } - - let variant = variant.ident.clone(); - - if names.is_empty() { - variants.push(quote! { - #name::#variant => { - #(#variant_fields)* - res - } - }); - } else { - variants.push(quote! { - #name::#variant(#(#names),*) => { - #(#variant_fields)* - res - } - }); - } - } - - sttms.push(quote! { - let res = match self { - #(#variants)* - }; - }); - } - Item::Struct(struct_) => { - name = struct_.ident; - - gen = struct_.generics; - - for (i, field) in struct_.fields.iter().enumerate() { - if let Some(ident) = &field.ident { - let ident_str = ident.to_string(); - sttms.push(quote! { - let res = res.with(TreeDisplay::label(#ident_str).with(self.#ident.show())); - }); - } else { - let num = syn::Index::from(i); - sttms.push(quote! { - let res = res.with(self.#num.show()); - }); - } - } - - let name_str = name.to_string(); - sttms.insert(1, quote! { let res = TreeDisplay::label(#name_str); }); - } - _ => panic!("Only structs and enums are supported"), - } - - let mut gen_changed = gen.clone(); - - for gen in &mut gen_changed.params { - if let syn::GenericParam::Type(type_) = gen { - type_.bounds.push(syn::parse_quote!(vulpi_show::Show)); - } - } - - quote! { - impl #gen_changed vulpi_show::Show for #name #gen { - fn show(&self) -> vulpi_show::TreeDisplay { - #(#sttms)* - res - } - } - } - .into() -} diff --git a/crates/vulpi-parser/Cargo.toml b/crates/vulpi-parser/Cargo.toml deleted file mode 100644 index 0a6679d..0000000 --- a/crates/vulpi-parser/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "vulpi-parser" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -vulpi-report = { path = "../vulpi-report" } -vulpi-location = { path = "../vulpi-location" } -vulpi-intern = { path = "../vulpi-intern" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-lexer = { path = "../vulpi-lexer" } diff --git a/crates/vulpi-parser/src/error.rs b/crates/vulpi-parser/src/error.rs deleted file mode 100644 index a8b8553..0000000 --- a/crates/vulpi-parser/src/error.rs +++ /dev/null @@ -1,28 +0,0 @@ -use vulpi_location::Span; -use vulpi_report::IntoDiagnostic; -use vulpi_syntax::tokens::Token; - -#[derive(Debug)] -pub enum ParserError { - UnexpectedToken(Box, Span), -} - -impl IntoDiagnostic for ParserError { - fn message(&self) -> vulpi_report::Text { - match self { - ParserError::UnexpectedToken(token, _) => { - format!("unexpected token '{:?}'", token.kind).into() - } - } - } - - fn severity(&self) -> vulpi_report::Severity { - vulpi_report::Severity::Error - } - - fn location(&self) -> Span { - match self { - ParserError::UnexpectedToken(_, span) => span.clone(), - } - } -} diff --git a/crates/vulpi-parser/src/expr.rs b/crates/vulpi-parser/src/expr.rs deleted file mode 100644 index eef44e6..0000000 --- a/crates/vulpi-parser/src/expr.rs +++ /dev/null @@ -1,407 +0,0 @@ -use crate::{Parser, Result}; - -use vulpi_location::Spanned; -use vulpi_syntax::{ - concrete::{tree::*, Either, Path, Upper}, - tokens::TokenData, -}; - -impl<'a> Parser<'a> { - pub fn record_field(&mut self) -> Result { - let name = self.lower()?; - let eq = self.expect(TokenData::Equal)?; - let expr = self.expr()?; - Ok(RecordField { name, eq, expr }) - } - - pub fn record_instance(&mut self, name: Path) -> Result { - let left_brace = self.expect(TokenData::LBrace)?; - let fields = self.sep_by(TokenData::Comma, Self::record_field)?; - let right_brace = self.expect(TokenData::RBrace)?; - Ok(RecordInstance { - name, - left_brace, - fields, - right_brace, - }) - } - - pub fn record_update(&mut self, expr: Box) -> Result { - let left_brace = self.expect(TokenData::LBrace)?; - let fields = self.sep_by(TokenData::Comma, Self::record_field)?; - let right_brace = self.expect(TokenData::RBrace)?; - Ok(RecordUpdate { - expr, - left_brace, - fields, - right_brace, - }) - } - - pub fn let_sttm(&mut self) -> Result { - let let_ = self.expect(TokenData::Let)?; - let pattern = self.pattern()?; - let eq = self.expect(TokenData::Equal)?; - let expr = self.expr()?; - Ok(LetSttm { - let_, - pattern, - eq, - expr, - }) - } - - pub fn statement_kind(&mut self) -> Result { - match self.token() { - TokenData::Let => self.let_sttm().map(StatementKind::Let), - _ => self.expr().map(StatementKind::Expr), - } - } - - pub fn statement(&mut self) -> Result { - self.spanned(Self::statement_kind) - } - - pub fn block(&mut self, parse: impl Fn(&mut Self) -> Result) -> Result> { - if !self.at(TokenData::Begin) { - return Ok(vec![]); - } - - self.expect(TokenData::Begin)?; - let mut statements = Vec::new(); - - while !self.at(TokenData::End) { - let stmt = parse(self)?; - - if self.at(TokenData::Sep) { - self.bump(); - } - - statements.push(stmt); - } - - self.expect_or_pop_layout(TokenData::End)?; - - Ok(statements) - } - - pub fn expr_atom_kind(&mut self) -> Result { - match self.token() { - TokenData::UpperIdent | TokenData::LowerIdent => { - let path = self.path_ident()?; - - match path.diferentiate() { - Either::Left(upper) => { - if self.at(TokenData::LBrace) { - return Ok(ExprKind::RecordInstance(self.record_instance(upper)?)); - } - Ok(ExprKind::Constructor(upper)) - } - Either::Right(lower) => { - if lower.segments.is_empty() { - return Ok(ExprKind::Variable(lower.last)); - } - Ok(ExprKind::Function(lower)) - } - } - } - TokenData::LPar => { - let exprs = self.parenthesis(|this| this.sep_by(TokenData::Comma, Self::expr))?; - - if exprs.data.is_empty() { - todo!() - } else if exprs.data.len() == 1 { - Ok(ExprKind::Parenthesis( - exprs.map(|x| x.into_iter().next().unwrap()), - )) - } else { - Ok(ExprKind::Tuple(exprs)) - } - } - _ => self.literal().map(ExprKind::Literal), - } - } - - pub fn expr_atom(&mut self) -> Result> { - self.spanned(Self::expr_atom_kind).map(Box::new) - } - - pub fn expr_application(&mut self) -> Result> { - let func = self.acessor()?; - let args = self.many(Self::acessor)?; - if args.is_empty() { - Ok(func) - } else { - let range = func.span.clone().mix(args.last().unwrap().span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Application(ApplicationExpr { func, args }), - })) - } - } - - pub fn expr_binary(&mut self, precedence: u8) -> Result> { - let mut left = self.expr_application()?; - - while let Some((lower, upper, op)) = self.expr_precedence() { - if lower < precedence { - break; - } - - // Cloned peek inside the expr_precedence - self.bump(); - - let right = self.expr_binary(upper)?; - - let range = left.span.clone().mix(right.span.clone()); - - left = Box::new(Spanned { - span: range, - data: ExprKind::Binary(BinaryExpr { left, op, right }), - }); - } - - Ok(left) - } - - pub fn expr_precedence(&mut self) -> Option<(u8, u8, Operator)> { - match self.token() { - TokenData::Plus => Some((1, 2, Operator::Add(self.peek().clone()))), - TokenData::Minus => Some((1, 2, Operator::Sub(self.peek().clone()))), - TokenData::Star => Some((3, 4, Operator::Mul(self.peek().clone()))), - TokenData::Slash => Some((3, 4, Operator::Div(self.peek().clone()))), - TokenData::Percent => Some((3, 4, Operator::Rem(self.peek().clone()))), - TokenData::DoubleEqual => Some((5, 6, Operator::Eq(self.peek().clone()))), - TokenData::NotEqual => Some((5, 6, Operator::Neq(self.peek().clone()))), - TokenData::Less => Some((7, 8, Operator::Lt(self.peek().clone()))), - TokenData::LessEqual => Some((7, 8, Operator::Le(self.peek().clone()))), - TokenData::Greater => Some((7, 8, Operator::Gt(self.peek().clone()))), - TokenData::GreaterEqual => Some((7, 8, Operator::Ge(self.peek().clone()))), - TokenData::Or => Some((9, 1, Operator::Or(self.peek().clone()))), - TokenData::And => Some((9, 1, Operator::And(self.peek().clone()))), - _ => None, - } - } - - pub fn expr_annotation(&mut self) -> Result> { - let left = self.expr_binary(0)?; - if self.at(TokenData::Colon) { - let colon = self.bump(); - let right = self.typ()?; - Ok(Box::new(Spanned { - span: left.span.clone().mix(right.span.clone()), - data: ExprKind::Annotation(AnnotationExpr { - expr: left, - colon, - ty: right, - }), - })) - } else if self.at(TokenData::LBrace) { - let left_range = left.span.clone(); - let right = self.spanned(|this| this.record_update(left))?; - Ok(Box::new(Spanned { - span: left_range.mix(right.span.clone()), - data: ExprKind::RecordUpdate(right.data), - })) - } else { - Ok(left) - } - } - - pub fn expr_do(&mut self) -> Result> { - let do_ = self.expect(TokenData::Do)?; - let statements = self.block(Self::statement)?; - let range = self.with_span(do_.value.span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Do(DoExpr { - do_, - block: Block { statements }, - }), - })) - } - - pub fn lambda_expr(&mut self) -> Result> { - let lambda = self.expect(TokenData::BackSlash)?; - let pattern = self.many(Self::pattern)?; - let arrow = self.expect(TokenData::FatArrow)?; - let expr = self.expr()?; - let range = self.with_span(lambda.value.span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Lambda(LambdaExpr { - lambda, - patterns: pattern, - arrow, - expr, - }), - })) - } - - pub fn acessor(&mut self) -> Result> { - let left = self.expr_atom()?; - if self.at(TokenData::Dot) { - let dot = self.bump(); - let field = self.lower()?; - let range = self.with_span(left.span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Acessor(ProjectionExpr { - expr: left, - dot, - field, - }), - })) - } else { - Ok(left) - } - } - - pub fn let_expr(&mut self) -> Result> { - let let_ = self.expect(TokenData::Let)?; - let pattern = self.pattern()?; - let eq = self.expect(TokenData::Equal)?; - let value = self.expr()?; - let in_ = self.expect(TokenData::In)?; - let body = self.expr()?; - - let range = self.with_span(let_.value.span.clone()); - - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Let(LetExpr { - let_, - pattern, - eq, - body: value, - in_, - value: body, - }), - })) - } - - pub fn pattern_arm(&mut self) -> Result { - let patterns = self.sep_by(TokenData::Comma, Self::pattern)?; - - let guard = if self.at(TokenData::If) { - let if_ = self.bump(); - let cond = self.expr()?; - Some((if_, cond)) - } else { - None - }; - - let arrow = self.expect(TokenData::FatArrow)?; - let expr = self.expr()?; - Ok(PatternArm { - patterns, - arrow, - expr, - guard, - }) - } - - pub fn when_expr(&mut self) -> Result> { - let when = self.expect(TokenData::When)?; - let scrutinee = self.sep_by(TokenData::Comma, Self::expr)?; - let is = self.expect(TokenData::Is)?; - - let cases = self.block(Self::pattern_arm)?.into_iter().collect(); - - let range = self.with_span(when.value.span.clone()); - - Ok(Box::new(Spanned { - span: range, - data: ExprKind::When(WhenExpr { - when, - scrutinee, - is, - arms: cases, - }), - })) - } - - pub fn if_expr(&mut self) -> Result> { - let if_ = self.expect(TokenData::If)?; - let cond = self.expr()?; - let then = self.expect(TokenData::Then)?; - let then_expr = self.expr()?; - let else_ = self.expect(TokenData::Else)?; - let else_expr = self.expr()?; - - let range = self.with_span(if_.value.span.clone()); - - Ok(Box::new(Spanned { - span: range, - data: ExprKind::If(IfExpr { - if_, - cond, - then, - then_expr, - else_, - else_expr, - }), - })) - } - - pub fn cases_expr(&mut self) -> Result> { - let cases = self.expect(TokenData::Cases)?; - let arms = self.block(Self::pattern_arm)?; - let range = self.with_span(cases.value.span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Cases(CasesExpr { cases, arms }), - })) - } - - pub fn handler_expr(&mut self) -> Result> { - let handle = self.expect(TokenData::Handle)?; - let expr = self.expr()?; - let with = self.expect(TokenData::With)?; - let handler = self.expr()?; - - let range = self.with_span(handle.value.span.clone()); - - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Handler(HandlerExpr { - handle, - expr, - with, - handler, - }), - })) - } - - pub fn expr_part(&mut self) -> Result> { - match self.token() { - TokenData::BackSlash => self.lambda_expr(), - TokenData::Let => self.let_expr(), - TokenData::Do => self.expr_do(), - TokenData::When => self.when_expr(), - TokenData::If => self.if_expr(), - TokenData::Cases => self.cases_expr(), - TokenData::Handle => self.handler_expr(), - _ => self.expr_annotation(), - } - } - - pub fn expr(&mut self) -> Result> { - let left = self.expr_part()?; - if self.at(TokenData::PipeRight) { - let pipe_right = self.bump(); - let right = self.expr()?; - let range = self.with_span(left.span.clone()); - Ok(Box::new(Spanned { - span: range, - data: ExprKind::Binary(BinaryExpr { - left, - op: Operator::Pipe(pipe_right), - right, - }), - })) - } else { - Ok(left) - } - } -} diff --git a/crates/vulpi-parser/src/identifier.rs b/crates/vulpi-parser/src/identifier.rs deleted file mode 100644 index da0af66..0000000 --- a/crates/vulpi-parser/src/identifier.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Parses multiple types of identifiers and paths - -use vulpi_syntax::{ - concrete::{Ident, Lower, Path, Upper}, - tokens::TokenData, -}; - -use crate::{Parser, Result}; - -impl<'a> Parser<'a> { - /// Parses a path from the current token. - pub fn path(&mut self, parse: impl Fn(&mut Self) -> Result) -> Result> { - let start = self.span(); - let mut segments = Vec::new(); - - while self.at(TokenData::UpperIdent) && self.then(TokenData::Dot) { - let ident = self.bump(); - let dot = self.bump(); - segments.push((Upper(ident), dot)); - } - - let last = parse(self)?; - - Ok(Path { - segments, - last, - span: self.with_span(start), - }) - } - - pub fn path_ident(&mut self) -> Result> { - self.path(|parser| match parser.peek().kind { - TokenData::LowerIdent => Ok(Ident::Lower(parser.lower()?)), - TokenData::UpperIdent => Ok(Ident::Upper(parser.upper()?)), - _ => parser.unexpected(), - }) - } - - pub fn path_upper(&mut self) -> Result> { - self.path(|parser| parser.upper()) - } - - pub fn path_lower(&mut self) -> Result> { - self.path(|parser| parser.lower()) - } - - pub fn lower(&mut self) -> Result { - // TODO: Handle case error - let ident = self.expect(TokenData::LowerIdent)?; - Ok(Lower(ident)) - } - - pub fn upper(&mut self) -> Result { - // TODO: Handle case error - let ident = self.expect(TokenData::UpperIdent)?; - Ok(Upper(ident)) - } -} diff --git a/crates/vulpi-parser/src/lib.rs b/crates/vulpi-parser/src/lib.rs deleted file mode 100644 index df26786..0000000 --- a/crates/vulpi-parser/src/lib.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! This is the parser of the vulpi language. It takes a stream of tokens and produces a tree of -//! nodes. It's a classical LL(1) parser with a recursive descent and pratt parsing. - -use error::ParserError; -use vulpi_lexer::Lexer; -use vulpi_location::{Byte, FileId, Span, Spanned}; -use vulpi_report::{Diagnostic, Report}; - -use vulpi_syntax::concrete::tree::Program; -use vulpi_syntax::concrete::Parenthesis; -use vulpi_syntax::tokens::{Token, TokenData}; - -pub mod error; -pub mod expr; -pub mod identifier; -pub mod literal; -pub mod pattern; -pub mod top_level; -pub mod r#type; - -pub type Result = std::result::Result; - -/// The parser main structure. -pub struct Parser<'a> { - pub lexer: Lexer<'a>, - - pub last_pos: Span, - - pub current: Token, - pub next: Token, - - pub eaten: bool, - pub file: FileId, - - pub reporter: Report, -} - -impl<'a> Parser<'a> { - pub fn new(mut lexer: Lexer<'a>, file: FileId, report: Report) -> Self { - let current = lexer.bump(); - let next = lexer.bump(); - - Self { - lexer, - current, - next, - last_pos: Span { - file, - start: Byte(0), - end: Byte(0), - }, - eaten: false, - file, - reporter: report, - } - } - - /// Advances a single token in the stream. - pub fn bump(&mut self) -> Token { - self.eaten = true; - - let mut ret = self.lexer.bump(); - std::mem::swap(&mut self.current, &mut self.next); - std::mem::swap(&mut ret, &mut self.next); - - self.last_pos = ret.value.span.clone(); - - ret - } - - /// Returns the current token. - pub fn peek(&self) -> &Token { - &self.current - } - - /// Removes a token if it matches the given one. - pub fn expect(&mut self, token: TokenData) -> Result { - if self.peek().kind == token { - Ok(self.bump()) - } else { - self.unexpected() - } - } - - /// Removes a token if it matches the given one but does not finishes the parsing process if - /// it doesn't. - pub fn eat(&mut self, token: TokenData) -> Token { - if self.peek().kind != token { - let unexpected_err = self.unexpected_err(); - self.report(unexpected_err); - } - self.bump() - } - - /// Reports an error and advances a token. - pub fn report(&mut self, err: ParserError) { - self.reporter.report(Diagnostic::new(err)); - self.bump(); - } - - /// Removes a token if it matches the given one but does not finishes the parsing process if - /// it doesn't, instead it pops the current layout in order to continue parsing. - pub fn expect_or_pop_layout(&mut self, token: TokenData) -> Result<()> { - if self.peek().kind == token { - self.bump(); - } else { - self.lexer.pop_layout(); - } - Ok(()) - } - - fn unexpected(&mut self) -> Result { - Err(self.unexpected_err()) - } - - fn unexpected_err(&mut self) -> ParserError { - error::ParserError::UnexpectedToken( - Box::new(self.peek().clone()), - self.peek().value.span.clone(), - ) - } - - /// Returns true if the current token matches the given one. - pub fn at(&self, token: TokenData) -> bool { - self.peek().kind == token - } - - /// Returns true if the next token matches the given one. - pub fn then(&self, token: TokenData) -> bool { - self.next.kind == token - } - - /// Returns true if the current token matches any of the given ones. - pub fn at_any(&self, tokens: &[TokenData]) -> bool { - tokens.iter().any(|token| self.at(*token)) - } - - /// Returns a list of tokens until the next one matches any of the given ones. - pub fn recover(&mut self, at_any: &[TokenData]) -> Vec { - let mut tokens = Vec::new(); - - while !self.at_any(at_any) && !self.at(TokenData::Eof) { - tokens.push(self.bump()); - } - - tokens - } - - /// It tries to parse the given function and returns the result if it succeeds. Otherwise, if - /// it doesnt have consumed any token, it returns [None]. If it has consumed a token, it - /// returns an error. - pub fn test(&mut self, fun: impl FnOnce(&mut Self) -> Result) -> Result> { - self.eaten = false; - let result = fun(self); - - match result { - Ok(value) => Ok(Some(value)), - Err(error) if self.eaten => Err(error), - Err(_) => Ok(None), - } - } - - /// Returns the current span. - pub fn span(&self) -> Span { - self.peek().value.span.clone() - } - - /// Returns the current token kind. - pub fn token(&self) -> TokenData { - self.peek().kind - } - - /// Creates a span around a function call. - pub fn spanned(&mut self, fun: impl FnOnce(&mut Self) -> Result) -> Result> { - let start = self.span(); - let value = fun(self)?; - let end = self.last_pos.clone(); - - Ok(Spanned::new(value, start.mix(end))) - } - - /// Parses a list of elements separated by a given token. - pub fn sep_by( - &mut self, - sep: TokenData, - mut fun: impl FnMut(&mut Self) -> Result, - ) -> Result)>> { - let mut values = Vec::new(); - - while let Some(res) = self.test(&mut fun)? { - let sep = if self.at(sep) { - Some(self.bump()) - } else { - None - }; - - let at_end = sep.is_none(); - - values.push((res, sep)); - - if at_end { - break; - } - } - - if self.at(sep) && !values.is_empty() { - values.last_mut().unwrap().1 = Some(self.bump()); - } - - Ok(values) - } - - /// Parses a list of elements. - pub fn many(&mut self, mut fun: impl FnMut(&mut Self) -> Result) -> Result> { - let mut values = Vec::new(); - - while let Some(result) = self.test(&mut fun)? { - values.push(result); - } - - Ok(values) - } - - pub fn with_span(&mut self, start: Span) -> Span { - let end = self.last_pos.clone(); - start.mix(end) - } -} - -impl<'a> Parser<'a> { - pub fn parenthesis( - &mut self, - parse: impl Fn(&mut Self) -> Result, - ) -> Result> { - let left = self.expect(TokenData::LPar)?; - let data = parse(self)?; - let right = self.expect(TokenData::RPar)?; - - Ok(Parenthesis { left, data, right }) - } -} - -/// The entrypoint of the parsing, it parses a string into a Program. -pub fn parse(reporter: Report, file_id: FileId, source: &str) -> Program { - let lexer = Lexer::new(source, file_id, reporter.clone()); - let mut parser = Parser::new(lexer, file_id, reporter); - parser.program() -} diff --git a/crates/vulpi-parser/src/literal.rs b/crates/vulpi-parser/src/literal.rs deleted file mode 100644 index 8f2d0e8..0000000 --- a/crates/vulpi-parser/src/literal.rs +++ /dev/null @@ -1,38 +0,0 @@ -use vulpi_syntax::{ - concrete::tree::{Literal, LiteralKind}, - tokens::TokenData, -}; - -use crate::{Parser, Result}; - -impl<'a> Parser<'a> { - pub fn literal_kind(&mut self) -> Result { - match self.token() { - TokenData::Int => { - let int = self.bump(); - Ok(LiteralKind::Integer(int)) - } - TokenData::Float => { - let float = self.bump(); - Ok(LiteralKind::Float(float)) - } - TokenData::String => { - let string = self.bump(); - Ok(LiteralKind::String(string)) - } - TokenData::Char => { - let char = self.bump(); - Ok(LiteralKind::Char(char)) - } - TokenData::Unit => { - let unit = self.bump(); - Ok(LiteralKind::Unit(unit)) - } - _ => self.unexpected(), - } - } - - pub fn literal(&mut self) -> Result { - self.spanned(Self::literal_kind) - } -} diff --git a/crates/vulpi-parser/src/pattern.rs b/crates/vulpi-parser/src/pattern.rs deleted file mode 100644 index 5a27066..0000000 --- a/crates/vulpi-parser/src/pattern.rs +++ /dev/null @@ -1,88 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_syntax::{ - concrete::{pattern::*, Either}, - tokens::TokenData, -}; - -use crate::{Parser, Result}; - -impl<'a> Parser<'a> { - pub fn pattern_atom_kind(&mut self) -> Result { - match self.token() { - TokenData::Wildcard => Ok(PatternKind::Wildcard(self.bump())), - TokenData::LowerIdent => self.lower().map(PatternKind::Variable), - TokenData::UpperIdent => { - let path = self.path_ident()?; - match path.diferentiate() { - Either::Left(upper) => Ok(PatternKind::Constructor(upper)), - Either::Right(_) => todo!(), - } - } - TokenData::LPar => self - .parenthesis(Self::pattern) - .map(PatternKind::Parenthesis), - _ => self.literal().map(PatternKind::Literal), - } - } - - pub fn pattern_atom(&mut self) -> Result> { - self.spanned(Self::pattern_atom_kind).map(Box::new) - } - - pub fn pattern_application_kind(&mut self) -> Result { - let func = self.path_upper()?; - let args = self.many(Self::pattern_atom)?; - Ok(PatApplication { func, args }) - } - - pub fn pattern_application(&mut self) -> Result> { - if self.at(TokenData::UpperIdent) { - self.spanned(|this| { - let result = this.pattern_application_kind()?; - if result.args.is_empty() { - Ok(PatternKind::Constructor(result.func)) - } else { - Ok(PatternKind::Application(result)) - } - }) - .map(Box::new) - } else if self.at(TokenData::LBrace) { - self.spanned(|this| { - let left_brace = this.bump(); - let func = this.path_lower()?; - let args = this.many(Self::pattern_atom)?; - - let arrow = if this.at(TokenData::RightArrow) { - Some((this.bump(), this.lower()?)) - } else { - None - }; - let right_brace = this.expect(TokenData::RBrace)?; - Ok(PatternKind::EffectApp(PatEffectApp { - left_brace, - func, - args, - right_brace, - arrow, - })) - }) - .map(Box::new) - } else { - self.pattern_atom() - } - } - - pub fn pattern(&mut self) -> Result> { - let left = self.pattern_application()?; - if self.at(TokenData::Bar) { - let pipe = self.bump(); - let right = self.pattern()?; - Ok(Box::new(Spanned { - span: left.span.clone().mix(right.span.clone()), - data: PatternKind::Or(PatOr { left, pipe, right }), - })) - } else { - Ok(left) - } - } -} diff --git a/crates/vulpi-parser/src/top_level.rs b/crates/vulpi-parser/src/top_level.rs deleted file mode 100644 index 4e23149..0000000 --- a/crates/vulpi-parser/src/top_level.rs +++ /dev/null @@ -1,306 +0,0 @@ -use vulpi_syntax::{concrete::top_level::*, tokens::TokenData}; - -use crate::{Parser, Result}; - -impl<'a> Parser<'a> { - pub fn binder(&mut self) -> Result { - let left_paren = self.expect(TokenData::LPar)?; - let pattern = self.pattern()?; - let colon = self.expect(TokenData::Colon)?; - let typ = self.typ()?; - let right_paren = self.expect(TokenData::RPar)?; - Ok(Binder { - left_paren, - pattern, - colon, - typ, - right_paren, - }) - } - - pub fn explicit_type_binder(&mut self) -> Result { - let name = self.lower()?; - let colon = self.expect(TokenData::Colon)?; - let kind = self.kind()?; - Ok(ExplicitTypeBinder { name, colon, kind }) - } - - pub fn type_binder(&mut self) -> Result { - if self.at(TokenData::LowerIdent) { - let lower = self.lower()?; - Ok(TypeBinder::Implicit(lower)) - } else { - Ok(TypeBinder::Explicit( - self.parenthesis(Self::explicit_type_binder)?, - )) - } - } - - pub fn let_case(&mut self) -> Result { - let pipe = self.expect(TokenData::Bar)?; - let arm = self.pattern_arm()?; - Ok(LetCase { pipe, arm }) - } - - pub fn let_decl(&mut self, visibility: Visibility) -> Result { - let let_ = self.expect(TokenData::Let)?; - let name = self.lower()?; - let binders = self.many(Self::binder)?; - - let ret = if self.at(TokenData::Colon) { - let colon = self.bump(); - let effects = if self.at(TokenData::LBrace) { - Some(self.type_effects()?) - } else { - None - }; - let typ = self.typ()?; - Some((colon, effects, typ)) - } else { - None - }; - - let body = if self.at(TokenData::Equal) { - let eq = self.expect(TokenData::Equal)?; - let expr = self.expr()?; - LetMode::Body(eq, expr) - } else { - LetMode::Cases(self.many(Self::let_case)?) - }; - - Ok(LetDecl { - let_, - name, - binders, - body, - visibility, - ret, - }) - } - - pub fn constructor_decl(&mut self) -> Result { - let pipe = self.expect(TokenData::Bar)?; - let name = self.upper()?; - let args = self.many(Self::type_atom)?; - - let typ = if self.at(TokenData::Colon) { - let colon = self.bump(); - let typ = self.typ()?; - Some((colon, typ)) - } else { - None - }; - - Ok(Constructor { - pipe, - name, - args, - typ, - }) - } - - pub fn sum_decl(&mut self) -> Result { - let constructors = self.many(Self::constructor_decl)?; - Ok(SumDecl { constructors }) - } - - pub fn field(&mut self) -> Result { - let visibility = self.visibility()?; - let name = self.lower()?; - let colon = self.expect(TokenData::Colon)?; - let typ = self.typ()?; - Ok(Field { - name, - colon, - ty: typ, - visibility, - }) - } - - pub fn record_decl(&mut self) -> Result { - let left_brace = self.expect(TokenData::LBrace)?; - let fields = self.sep_by(TokenData::Comma, Self::field)?; - let right_brace = self.expect(TokenData::RBrace)?; - - Ok(RecordDecl { - left_brace, - fields, - right_brace, - }) - } - - pub fn type_def(&mut self) -> Result { - match self.token() { - TokenData::Bar => self.sum_decl().map(TypeDef::Sum), - TokenData::LBrace => self.record_decl().map(TypeDef::Record), - _ => self.type_atom().map(TypeDef::Synonym), - } - } - - pub fn type_decl(&mut self, visibility: Visibility) -> Result { - let type_ = self.expect(TokenData::Type)?; - let name = self.upper()?; - let binders = self.many(Self::type_binder)?; - - let def = if self.at(TokenData::Equal) { - let eq = self.expect(TokenData::Equal)?; - let def = self.type_def()?; - Some((eq, def)) - } else { - None - }; - - Ok(TypeDecl { - type_, - name, - binders, - def, - visibility, - }) - } - - pub fn use_alias(&mut self) -> Result { - let as_ = self.expect(TokenData::As)?; - let alias = self.upper()?; - Ok(UseAlias { as_, alias }) - } - - pub fn visibility(&mut self) -> Result { - if self.at(TokenData::Pub) { - Ok(Visibility::Public(self.bump())) - } else { - Ok(Visibility::Private) - } - } - - pub fn use_decl(&mut self, visibility: Visibility) -> Result { - let use_ = self.expect(TokenData::Use)?; - let path = self.path_upper()?; - - let alias = if self.at(TokenData::As) { - Some(self.use_alias()?) - } else { - None - }; - - Ok(UseDecl { - use_, - path, - alias, - visibility, - }) - } - - pub fn effect_field(&mut self) -> Result { - let visibility = self.visibility()?; - let name = self.lower()?; - let args = self.many(Self::type_atom)?; - let colon = self.expect(TokenData::Colon)?; - let ret = self.typ()?; - Ok(EffectField { - visibility, - name, - args, - colon, - ret, - }) - } - - pub fn effect_decl(&mut self, visibility: Visibility) -> Result { - let effect = self.expect(TokenData::Effect)?; - let name = self.upper()?; - let binders = self.many(Self::type_binder)?; - - let (where_, fields) = if self.at(TokenData::Where) { - ( - Some(self.expect(TokenData::Where)?), - self.block(Self::effect_field)?, - ) - } else { - (None, vec![]) - }; - - Ok(EffectDecl { - visibility, - effect, - name, - binders, - where_, - fields, - }) - } - - pub fn mod_decl(&mut self, visibility: Visibility) -> Result { - let mod_ = self.expect(TokenData::Mod)?; - let name = self.upper()?; - - let part = if self.at(TokenData::Where) { - let where_ = self.expect(TokenData::Where)?; - let top_levels = self.block(Self::top_level)?; - - Some(ModuleInline { where_, top_levels }) - } else { - None - }; - - Ok(ModuleDecl { - visibility, - mod_, - name, - part, - }) - } - - pub fn external_decl(&mut self, visibility: Visibility) -> Result { - let external = self.expect(TokenData::External)?; - let name = self.lower()?; - let colon = self.expect(TokenData::Colon)?; - let typ = self.typ()?; - let equal = self.expect(TokenData::Equal)?; - let str = self.expect(TokenData::String)?; - - Ok(ExternalDecl { - visibility, - external, - name, - colon, - typ, - equal, - str, - }) - } - - pub fn top_level(&mut self) -> Result { - let vis = self.visibility()?; - match self.token() { - TokenData::Let => self.let_decl(vis).map(Box::new).map(TopLevel::Let), - TokenData::Type => self.type_decl(vis).map(Box::new).map(TopLevel::Type), - TokenData::Use => self.use_decl(vis).map(Box::new).map(TopLevel::Use), - TokenData::Effect => self.effect_decl(vis).map(Box::new).map(TopLevel::Effect), - TokenData::Mod => self.mod_decl(vis).map(Box::new).map(TopLevel::Module), - TokenData::External => self - .external_decl(vis) - .map(Box::new) - .map(TopLevel::External), - _ => self.unexpected(), - } - } - - pub fn program(&mut self) -> Program { - let mut top_levels = vec![]; - - while !self.at(TokenData::Eof) { - match self.top_level() { - Ok(top_level) => top_levels.push(top_level), - Err(err) => { - self.report(err); - let errs = self.recover(&[TokenData::Let, TokenData::Type, TokenData::Use]); - top_levels.push(TopLevel::Error(errs)) - } - } - } - - let eof = self.eat(TokenData::Eof); - Program { top_levels, eof } - } -} diff --git a/crates/vulpi-parser/src/type.rs b/crates/vulpi-parser/src/type.rs deleted file mode 100644 index 4e87296..0000000 --- a/crates/vulpi-parser/src/type.rs +++ /dev/null @@ -1,169 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_syntax::concrete::{ - r#type::*, - tree::{Kind, KindType}, - Lower, -}; -use vulpi_syntax::tokens::TokenData; - -use crate::{Parser, Result}; - -impl<'a> Parser<'a> { - fn kind_atom_raw(&mut self) -> Result { - match self.token() { - TokenData::Star => Ok(KindType::Star(self.bump())), - TokenData::LPar => Ok(KindType::Parenthesis(self.parenthesis(Self::kind)?)), - TokenData::UpperIdent => Ok(KindType::Variable(self.upper()?)), - _ => self.unexpected(), - } - } - - fn kind_atom(&mut self) -> Result> { - self.spanned(Self::kind_atom_raw).map(Box::new) - } - - fn kind_arrow(&mut self) -> Result> { - let left = self.kind_atom()?; - - if self.at(TokenData::RightArrow) { - let arrow = self.bump(); - let right = self.kind()?; - - Ok(Box::new(Spanned { - span: left.span.clone().mix(right.span.clone()), - data: KindType::Arrow(left, arrow, right), - })) - } else { - Ok(left) - } - } - - pub fn kind(&mut self) -> Result> { - self.kind_arrow() - } - - fn type_variable(&mut self) -> Result { - self.lower() - } - - fn type_forall(&mut self) -> Result { - let forall = self.expect(TokenData::Forall)?; - let left = self.many(Self::type_binder)?; - let dot = self.expect(TokenData::Dot)?; - let right = self.typ()?; - - Ok(TypeForall { - forall, - params: left, - dot, - body: right, - }) - } - - pub fn effect(&mut self) -> Result { - if self.at(TokenData::LowerIdent) { - let var = self.lower()?; - Ok(Effect::Variable(var)) - } else { - let var = self.path_upper()?; - let args = self.many(Self::type_atom)?; - - Ok(Effect::Application(var, args)) - } - } - - pub fn type_effects(&mut self) -> Result { - let left_brace = self.expect(TokenData::LBrace)?; - let effects = self.sep_by(TokenData::Comma, |this| this.spanned(Self::effect))?; - let right_brace = self.expect(TokenData::RBrace)?; - - Ok(Effects { - left_brace, - right_brace, - effects, - }) - } - - fn type_atom_raw(&mut self) -> Result { - match self.token() { - TokenData::LowerIdent => self.type_variable().map(TypeKind::TypeVariable), - TokenData::UpperIdent => self.path(Self::upper).map(TypeKind::Type), - TokenData::Unit => Ok(TypeKind::Unit(self.bump())), - TokenData::LPar => { - let exprs = self.parenthesis(|this| this.sep_by(TokenData::Comma, Self::typ))?; - - if exprs.data.is_empty() { - todo!() - } else if exprs.data.len() == 1 { - Ok(TypeKind::Parenthesis( - exprs.map(|x| x.into_iter().next().unwrap()), - )) - } else { - Ok(TypeKind::Tuple(exprs)) - } - } - - _ => self.unexpected(), - } - } - - pub fn type_atom(&mut self) -> Result> { - self.spanned(Self::type_atom_raw).map(Box::new) - } - - fn type_application(&mut self) -> Result> { - let func = self.type_atom()?; - - let args = self.many(Self::type_atom)?; - - if args.is_empty() { - Ok(func) - } else { - let start = func.span.clone(); - let end = args.last().unwrap().span.clone(); - - Ok(Box::new(Spanned { - span: start.mix(end), - data: TypeKind::Application(TypeApplication { func, args }), - })) - } - } - - fn type_arrow(&mut self) -> Result> { - let left = self.type_application()?; - - if self.at(TokenData::RightArrow) { - let arrow = self.bump(); - - let effects = if self.at(TokenData::LBrace) { - Some(self.type_effects()?) - } else { - None - }; - - let right = self.type_arrow()?; - - Ok(Box::new(Spanned { - span: left.span.clone().mix(right.span.clone()), - data: TypeKind::Arrow(TypeArrow { - left, - arrow, - effects, - right, - }), - })) - } else { - Ok(left) - } - } - - /// Parses types - pub fn typ(&mut self) -> Result> { - match self.token() { - TokenData::Forall => self - .spanned(|x| x.type_forall().map(TypeKind::Forall)) - .map(Box::new), - _ => self.type_arrow(), - } - } -} diff --git a/crates/vulpi-report/Cargo.toml b/crates/vulpi-report/Cargo.toml deleted file mode 100644 index 01616b0..0000000 --- a/crates/vulpi-report/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "vulpi-report" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -vulpi-location = { path = "../vulpi-location" } -vulpi-vfs = { path = "../vulpi-vfs" } - -yansi = "0.5.1" diff --git a/crates/vulpi-report/src/hash.rs b/crates/vulpi-report/src/hash.rs deleted file mode 100644 index 4f20e9f..0000000 --- a/crates/vulpi-report/src/hash.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Simple reporter for diagnostics using a hashmap to store things. - -use crate::{Diagnostic, Reporter}; -use std::collections::HashMap; -use vulpi_location::FileId; - -#[derive(Default)] -pub struct HashReporter { - map: HashMap>, - errored: bool, -} - -impl HashReporter { - pub fn new() -> Self { - Self::default() - } -} - -impl Reporter for HashReporter { - fn report(&mut self, diagnostic: Diagnostic) { - self.errored = true; - self.map - .entry(diagnostic.location().file) - .or_default() - .push(diagnostic); - } - - fn diagnostics(&self, file: FileId) -> &[Diagnostic] { - self.map.get(&file).map_or(&[], |v| v) - } - - fn clear(&mut self, file: FileId) { - self.map.remove(&file); - } - - fn all_diagnostics(&self) -> Vec { - self.map.values().flatten().cloned().collect() - } - - fn has_errors(&self) -> bool { - self.errored - } -} diff --git a/crates/vulpi-report/src/lib.rs b/crates/vulpi-report/src/lib.rs deleted file mode 100644 index ff26441..0000000 --- a/crates/vulpi-report/src/lib.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Module for handling errors that can occur during the compilation process. It's used to report -//! errors to the user. - -use std::{cell::RefCell, rc::Rc}; - -use renderer::{classic::Classic, Renderer}; -use vulpi_location::{FileId, Span}; - -pub mod hash; -pub mod renderer; - -/// A type for representing the severity of a [Diagnostic]. -pub enum Severity { - Error, - Warning, - Info, -} - -/// A type for representing the color of a [Word]. It's all numerated because it's easier to change -/// the color of a word according to what the user wants. -pub enum Color { - Fst, - Snd, - Trd, - Fth, -} - -/// A type for representing the style of a [Word]. -pub enum Style { - Bold, - Dimmed, - Normal, -} - -/// A type for representing a word in a [Text]. -pub struct Word(Style, Color, String); - -/// A type for representing a text. It's used to generate error messages. -pub enum Text { - Phrase(Vec), - Styled(Style, String), - Colored(Color, String), - Text(String), - Break, -} - -impl From<&str> for Text { - fn from(s: &str) -> Self { - Text::Text(s.to_owned()) - } -} - -impl From for Text { - fn from(s: String) -> Self { - Text::Text(s) - } -} - -/// A position in the source code that has or not a message. It's used to generate underlined parts -/// with messages. -pub struct Marker { - pub position: Span, - pub subtitle: Option, -} - -/// Errors that can occur during the compilation process. -pub trait IntoDiagnostic { - fn code(&self) -> Option { - None - } - - fn hint(&self) -> Option { - None - } - - fn message(&self) -> Text; - - fn severity(&self) -> Severity; - - fn location(&self) -> Span; -} - -/// A diagnostic with reference counting. It is a wrapper around a [IntoDiagnostic] trait object. -#[derive(Clone)] -pub struct Diagnostic(Rc); - -impl Diagnostic { - pub fn new(diagnostic: impl IntoDiagnostic + 'static) -> Self { - Self(Rc::new(diagnostic)) - } - - pub fn code(&self) -> Option { - self.0.code() - } - - pub fn hint(&self) -> Option { - self.0.hint() - } - - pub fn message(&self) -> Text { - self.0.message() - } - - pub fn severity(&self) -> Severity { - self.0.severity() - } - - pub fn location(&self) -> Span { - self.0.location() - } -} - -/// A reporter is a structure that gets and record errors. It's used to store and report errors to -/// the user. -pub trait Reporter { - /// Reports a new error to the reporter. - fn report(&mut self, diagnostic: Diagnostic); - - /// Gets all the diagnostics of a file. - fn diagnostics(&self, file: FileId) -> &[Diagnostic]; - - /// Get all diagnostics - fn all_diagnostics(&self) -> Vec; - - /// Clears all the diagnostics of a file. It's used for LSP. - fn clear(&mut self, file: FileId); - - /// Check if has errors - fn has_errors(&self) -> bool; -} - -/// A structure that stores and reports errors to the user. It's inside a Rc or Arc because it -/// needs to be shared between all steps of the compiler -#[derive(Clone)] -pub struct Report(Rc>); - -impl Report { - pub fn new(reporter: impl Reporter + 'static) -> Self { - Self(Rc::new(RefCell::new(reporter))) - } - - pub fn report(&self, diagnostic: Diagnostic) { - self.0.borrow_mut().report(diagnostic); - } - - pub fn diagnostics(&self, file: FileId) -> Vec { - self.0.borrow().diagnostics(file).to_vec() - } - - pub fn all_diagnostics(&self) -> Vec { - self.0.borrow().all_diagnostics() - } - - pub fn clear(&self, file: FileId) { - self.0.borrow_mut().clear(file); - } - - pub fn has_errors(&self) -> bool { - self.0.borrow().has_errors() - } - - pub fn to_stderr(&self, ctx: Classic) { - if self.has_errors() { - eprintln!(); - - for diagnostic in self.all_diagnostics().iter().rev() { - diagnostic.render(&ctx, &mut std::io::stderr()).unwrap(); - } - } - } -} - -pub fn hash_reporter() -> Report { - Report::new(hash::HashReporter::new()) -} diff --git a/crates/vulpi-report/src/renderer/classic.rs b/crates/vulpi-report/src/renderer/classic.rs deleted file mode 100644 index 5168cf9..0000000 --- a/crates/vulpi-report/src/renderer/classic.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::path::PathBuf; - -use vulpi_vfs::FileSystem; -use yansi::Paint; - -use crate::{renderer::LineGuide, Color, Diagnostic, Style, Text, Word}; - -use super::Renderer; - -pub struct Classic<'a> { - fs: &'a dyn FileSystem, - cwd: PathBuf, -} - -impl<'a> Classic<'a> { - pub fn new(fs: &'a (dyn FileSystem + 'static), cwd: PathBuf) -> Self { - Self { fs, cwd } - } -} - -fn get_paint(color: &Color) -> fn(String) -> yansi::Paint { - match color { - Color::Fst => Paint::red, - Color::Snd => Paint::yellow, - Color::Trd => Paint::blue, - Color::Fth => Paint::green, - } -} - -impl<'a> Renderer> for (&Color, &str) { - fn render(&self, _: &Classic<'a>, writer: &mut impl std::io::Write) -> std::io::Result<()> { - let paint = get_paint(self.0); - write!(writer, "{}", paint(self.1.to_string())) - } -} - -impl<'a> Renderer> for (&Style, &str) { - fn render(&self, _: &Classic<'a>, writer: &mut impl std::io::Write) -> std::io::Result<()> { - match self.0 { - Style::Bold => write!(writer, "{}", Paint::new(self.1).bold()), - Style::Dimmed => write!(writer, "{}", Paint::new(self.1).dimmed()), - Style::Normal => write!(writer, "{}", self.1), - } - } -} - -impl<'a> Renderer> for Word { - fn render(&self, _: &Classic<'a>, writer: &mut impl std::io::Write) -> std::io::Result<()> { - let Word(style, color, text) = self; - - let paint = get_paint(color)(text.to_string()); - - let paint = match style { - Style::Bold => paint.bold(), - Style::Dimmed => paint.dimmed(), - Style::Normal => paint, - }; - - write!(writer, "{}", paint) - } -} - -impl<'a> Renderer> for Text { - fn render(&self, ctx: &Classic<'a>, writer: &mut impl std::io::Write) -> std::io::Result<()> { - match self { - Text::Phrase(words) => { - for (i, word) in words.iter().enumerate() { - word.render(ctx, writer)?; - - if i != words.len() - 1 { - write!(writer, " ")?; - } - } - - Ok(()) - } - Text::Styled(style, t) => (style, t.as_str()).render(ctx, writer), - Text::Colored(color, t) => (color, t.as_str()).render(ctx, writer), - Text::Text(text) => write!(writer, "{}", Paint::new(text).bold()), - Text::Break => writeln!(writer), - } - } -} - -impl<'a> Renderer> for Diagnostic { - fn render(&self, ctx: &Classic<'a>, writer: &mut impl std::io::Write) -> std::io::Result<()> { - // At this point we are probably sure that the file exists, so we can unwrap. - let path = ctx.fs.path(self.location().file).unwrap(); - let relative = path.strip_prefix(&ctx.cwd).unwrap(); - - let content = ctx.fs.read(self.location().file).unwrap(); - - let range = self.location(); - - let line_guide = LineGuide::new(content); - - let start = line_guide.to_line_and_column(range.start).unwrap(); - let end = line_guide.to_line_and_column(range.end).unwrap(); - - write!( - writer, - " {} ", - yansi::Color::White - .style() - .bg(yansi::Color::Red) - .paint(" ERROR ") - )?; - - self.message().render(ctx, writer)?; - - let guide = Paint::new("┌─>").fg(yansi::Color::Cyan).dimmed(); - - writeln!(writer)?; - writeln!(writer)?; - writeln!( - writer, - " {guide} {}:{}:{} ", - relative.display(), - start.0 + 1, - start.1 + 1 - )?; - - let vbar = Paint::new("│").fg(yansi::Color::Cyan).dimmed(); - - writeln!(writer, " {vbar} ")?; - - let is_inline = start.0 == end.0; - - let lines = content.lines().collect::>(); - - let minimum = start.0.saturating_sub(2); - let maximum = (end.0 + 2).min(lines.len()); - - for (i, line) in lines[minimum..maximum].iter().enumerate() { - let line_number = minimum + i + 1; - - write!(writer, " {:>3} {vbar} ", line_number)?; - - if is_inline && line_number == start.0 + 1 { - let line = line.to_string(); - - writeln!(writer, "{}", line)?; - - writeln!( - writer, - " {vbar} {}{}", - " ".repeat(start.1), - Paint::new("^".repeat(end.1 - start.1)) - .bold() - .fg(yansi::Color::Red) - )?; - } else if is_inline && line_number == end.0 + 1 { - let mut line = line.to_string(); - - line.insert(end.1 + 1, '^'); - - writeln!(writer, "{}", line)?; - } else { - writeln!(writer, "{}", line)?; - } - } - - writeln!(writer) - } -} diff --git a/crates/vulpi-report/src/renderer/mod.rs b/crates/vulpi-report/src/renderer/mod.rs deleted file mode 100644 index f70346c..0000000 --- a/crates/vulpi-report/src/renderer/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Simple renderer for diagnostics. - -pub mod classic; - -use vulpi_location::Byte; - -/// Trait for rendering diagnostics. -pub trait Renderer { - fn render(&self, ctx: &T, writer: &mut impl std::io::Write) -> std::io::Result<()>; -} - -/// A guide for lines and columns. -#[derive(Debug)] -pub struct LineGuide { - line_bytes: Vec<(usize, usize)>, -} - -impl LineGuide { - pub fn new(content: &str) -> Self { - let mut line_bytes = Vec::new(); - - let mut line_start = 0; - let mut line_end = 0; - - for (i, c) in content.char_indices() { - if c == '\n' { - line_bytes.push((line_start, line_end)); - line_start = i + 1; - } - - line_end = i + 1; - } - - line_bytes.push((line_start, line_end)); - - Self { line_bytes } - } - - pub fn to_line_and_column(&self, place: Byte) -> Option<(usize, usize)> { - let place = place.0; - - for (i, (start, end)) in self.line_bytes.iter().enumerate() { - if place >= *start && place <= *end { - return Some((i, place - start)); - } - } - - None - } -} - -/// A reader is just a wrapper around a string for [std::io::Write]. -#[derive(Default)] -pub struct Reader(String); - -impl ToString for Reader { - fn to_string(&self) -> String { - self.0.clone() - } -} - -impl std::io::Write for Reader { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.push_str(std::str::from_utf8(buf).unwrap()); - Ok(buf.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} diff --git a/crates/vulpi-resolver/Cargo.toml b/crates/vulpi-resolver/Cargo.toml deleted file mode 100644 index 225e18b..0000000 --- a/crates/vulpi-resolver/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "vulpi-resolver" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -vulpi-intern = { path = "../vulpi-intern" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-location = { path = "../vulpi-location" } -vulpi-report = { path = "../vulpi-report" } -vulpi-show = { path = "../vulpi-show" } -vulpi-macros = { path = "../vulpi-macros" } - -im-rc = "15.1.0" diff --git a/crates/vulpi-resolver/src/declare.rs b/crates/vulpi-resolver/src/declare.rs deleted file mode 100644 index 25be362..0000000 --- a/crates/vulpi-resolver/src/declare.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! This is the first phase of the resolution process. It takes a syntax tree and then checks for -//! each of the modules inside of it creating an ID for each of them. - -use vulpi_intern::Symbol; -use vulpi_location::Span; -use vulpi_syntax::concrete::top_level::Visibility; -use vulpi_syntax::concrete::tree::*; - -use crate::error::ResolverError; -use crate::{namespace, Context}; - -use crate::{ - namespace::{Item, Namespace, TypeValue, Value}, - paths, -}; - -use vulpi_syntax::r#abstract::Qualified; - -impl<'a> Context<'a> { - pub fn derive(&mut self, name: Symbol, function: impl FnOnce(&mut Context) -> T) -> T { - self.path.push(name); - self.namespaces.add(self.path.clone()); - let res = function(self); - self.path.pop(); - res - } - - pub fn add_value(&mut self, span: Span, path: Symbol, item: Item) { - let namespace = self.namespaces.get_mut(self.path.clone()).unwrap(); - let old = namespace.values.insert(path.clone(), item); - if old.is_some() { - self.report_redeclareted(span, path); - } - } - - pub fn add_type(&mut self, span: Span, path: Symbol, item: Item) { - let namespace = self.namespaces.get_mut(self.path.clone()).unwrap(); - let old = namespace.types.insert(path.clone(), item); - if old.is_some() { - self.report_redeclareted(span, path); - } - } - - pub fn add_module(&mut self, span: Span, path: Symbol, item: Item) { - let namespace = self.namespaces.get_mut(self.path.clone()).unwrap(); - let old = namespace.modules.insert(path.clone(), item); - if old.is_some() { - self.report_redeclareted(span, path); - } - } - - pub fn register_namespace(&mut self, span: Span, path: paths::Path, namespace: Namespace) { - let namespace = self.namespaces.add_with(path.clone(), namespace); - if namespace.is_some() { - self.report_redeclareted(span, path.symbol()); - } - } - - pub fn merge(&mut self, namespace: Namespace) { - for (key, value) in namespace.values { - self.add_value(value.span.clone(), key, value); - } - - for (key, value) in namespace.types { - self.add_type(value.span.clone(), key, value); - } - - for (key, value) in namespace.modules { - self.add_module(value.span.clone(), key, value); - } - } - - pub fn qualify(&self, name: Symbol) -> Qualified { - self.path.qualify(name).into() - } -} - -pub trait Declare { - fn declare(&self, ctx: &mut Context); -} - -impl From for namespace::Visibility { - fn from(value: Visibility) -> Self { - match value { - Visibility::Public(_) => namespace::Visibility::Public, - Visibility::Private => namespace::Visibility::Private, - } - } -} - -impl Declare for EffectDecl { - fn declare(&self, ctx: &mut Context) { - let name = self.name.symbol(); - - ctx.add_type( - self.name.0.value.span.clone(), - name, - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: TypeValue::Effect(ctx.qualify(self.name.symbol())), - parent: Some(ctx.path.symbol()), - }, - ); - - ctx.add_module( - self.name.0.value.span.clone(), - self.name.symbol(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: ctx.path.with(self.name.symbol()).symbol(), - parent: Some(ctx.path.symbol()), - }, - ); - - ctx.derive(self.name.symbol(), |ctx| { - for field in &self.fields { - ctx.add_value( - field.name.0.value.span.clone(), - field.name.symbol(), - Item { - visibility: field.visibility.clone().into(), - span: field.name.0.value.span.clone(), - item: Value::Effect(ctx.qualify(field.name.symbol())), - parent: Some(ctx.path.symbol()), - }, - ); - } - }); - } -} - -impl Declare for SumDecl { - fn declare(&self, ctx: &mut Context) { - for constructor in self.constructors.iter() { - ctx.add_value( - constructor.name.0.value.span.clone(), - constructor.name.symbol(), - Item { - visibility: namespace::Visibility::Public, - span: constructor.name.0.value.span.clone(), - item: Value::Constructor(ctx.qualify(constructor.name.symbol())), - parent: None, - }, - ); - } - } -} - -impl Declare for RecordDecl { - fn declare(&self, ctx: &mut Context) { - for (field, _) in self.fields.iter() { - ctx.add_value( - field.name.0.value.span.clone(), - field.name.symbol(), - Item { - visibility: namespace::Visibility::Public, - span: field.name.0.value.span.clone(), - item: Value::Field(ctx.qualify(field.name.symbol())), - parent: None, - }, - ); - } - } -} - -impl Declare for TypeDef { - fn declare(&self, ctx: &mut Context) { - match self { - TypeDef::Sum(s) => s.declare(ctx), - TypeDef::Record(s) => s.declare(ctx), - TypeDef::Synonym(_) => (), - } - } -} - -impl Declare for TypeDecl { - fn declare(&self, ctx: &mut Context) { - let name = self.name.symbol(); - - ctx.add_type( - self.name.0.value.span.clone(), - name.clone(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: match self.def { - Some((_, TypeDef::Sum(_))) => TypeValue::Enum(ctx.qualify(name)), - Some((_, TypeDef::Record(_))) => TypeValue::Record(ctx.qualify(name)), - Some((_, TypeDef::Synonym(_))) => todo!("Synonym types are not implemented"), - _ => TypeValue::Abstract(ctx.qualify(name)), - }, - parent: Some(ctx.path.symbol()), - }, - ); - - ctx.add_module( - self.name.0.value.span.clone(), - self.name.symbol(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: ctx.path.with(self.name.symbol()).symbol(), - parent: Some(ctx.path.symbol()), - }, - ); - - ctx.derive(self.name.symbol(), |ctx| { - if let Some(some) = &self.def { - some.1.declare(ctx); - } - }) - } -} - -impl Declare for LetDecl { - fn declare(&self, ctx: &mut Context) { - ctx.add_value( - self.name.0.value.span.clone(), - self.name.symbol(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: Value::Function(ctx.qualify(self.name.symbol())), - parent: Some(ctx.path.symbol()), - }, - ); - } -} - -impl Declare for ModuleDecl { - fn declare(&self, ctx: &mut Context) { - ctx.add_module( - self.name.0.value.span.clone(), - self.name.symbol(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: ctx.path.with(self.name.symbol()).symbol(), - parent: None, - }, - ); - - ctx.derive(self.name.symbol(), |ctx| { - if let Some(module) = &self.part { - for top_level in &module.top_levels { - top_level.declare(ctx); - } - } else { - let namespaces = ctx.io.read_module(ctx.path.clone()); - - match namespaces { - Ok(res) => res.declare(ctx), - Err(err) => { - ctx.report(ResolverError { - span: self.name.0.value.span.clone(), - kind: err, - }); - } - } - } - }); - } -} - -impl Declare for ExternalDecl { - fn declare(&self, ctx: &mut Context) { - ctx.add_value( - self.name.0.value.span.clone(), - self.name.symbol(), - Item { - visibility: self.visibility.clone().into(), - span: self.name.0.value.span.clone(), - item: Value::Function(ctx.qualify(self.name.symbol())), - parent: Some(ctx.path.symbol()), - }, - ); - } -} - -impl Declare for TopLevel { - fn declare(&self, ctx: &mut Context) { - match self { - TopLevel::Use(_) => (), - TopLevel::Type(typ) => { - typ.declare(ctx); - } - TopLevel::Module(module) => { - module.declare(ctx); - } - TopLevel::Effect(effect) => { - effect.declare(ctx); - } - TopLevel::Let(decl) => { - decl.declare(ctx); - } - TopLevel::External(external) => external.declare(ctx), - TopLevel::Error(_) => (), - } - } -} - -impl Declare for Program { - fn declare(&self, ctx: &mut Context) { - for top_level in &self.top_levels { - top_level.declare(ctx); - } - } -} - -pub trait ImportResolve { - fn resolve_imports(&self, ctx: &mut Context); -} - -impl ImportResolve for UseDecl { - fn resolve_imports(&self, ctx: &mut Context) { - let path = paths::Path { - path: self - .path - .segments - .iter() - .map(|x| x.0.symbol()) - .chain(Some(self.path.last.symbol())) - .collect(), - }; - - let Some(name) = ctx.resolve_module(self.path.span.clone(), path.clone(), path.symbol()) else { - return; - }; - - if let Some(alias) = &self.alias { - ctx.add_value( - alias.alias.0.value.span.clone(), - alias.alias.symbol(), - Item { - visibility: namespace::Visibility::Public, - span: alias.alias.0.value.span.clone(), - item: Value::Module(name), - parent: None, - }, - ) - } else { - let namespace = ctx.namespaces.find(name).cloned().unwrap(); - ctx.merge(namespace); - } - } -} - -impl ImportResolve for TopLevel { - fn resolve_imports(&self, ctx: &mut Context) { - if let TopLevel::Use(use_) = self { - use_.resolve_imports(ctx); - } - } -} - -impl ImportResolve for ModuleDecl { - fn resolve_imports(&self, ctx: &mut Context) { - ctx.derive(self.name.symbol(), |ctx| { - if let Some(module) = &self.part { - for top_level in module.modules() { - top_level.resolve_imports(ctx); - } - - for top_level in module.uses() { - top_level.resolve_imports(ctx); - } - } - }); - } -} - -impl ImportResolve for Program { - fn resolve_imports(&self, ctx: &mut Context) { - for top_level in self.modules() { - top_level.resolve_imports(ctx); - } - - for top_level in self.uses() { - top_level.resolve_imports(ctx); - } - } -} diff --git a/crates/vulpi-resolver/src/error.rs b/crates/vulpi-resolver/src/error.rs deleted file mode 100644 index 7814a7e..0000000 --- a/crates/vulpi-resolver/src/error.rs +++ /dev/null @@ -1,62 +0,0 @@ -use vulpi_intern::Symbol; -use vulpi_location::Span; -use vulpi_report::IntoDiagnostic; - -pub enum ResolverErrorKind { - Redeclarated(Symbol), - NotFound(Symbol), - InvalidPath(Vec), - IsAModule, - ExpectedConstructor, - ExpectedRecordType, - ExpectedEffect, - ExpectedFunction, - VariableNotBoundOnBothSides(Symbol), - DuplicatePattern(Symbol), - CannotHavePolymorphiEffectInTheMiddle, - PrivateDefinition, -} - -pub struct ResolverError { - pub span: Span, - pub kind: ResolverErrorKind, -} - -impl IntoDiagnostic for ResolverError { - fn message(&self) -> vulpi_report::Text { - match &self.kind { - ResolverErrorKind::Redeclarated(name) => { - format!("redeclarated name: {}", name.get()).into() - } - ResolverErrorKind::NotFound(name) => format!("name not found: {}", name.get()).into(), - ResolverErrorKind::InvalidPath(name) => format!( - "invalid path: {}", - name.iter().map(|s| s.get()).collect::>().join(".") - ) - .into(), - ResolverErrorKind::IsAModule => "is a module".into(), - ResolverErrorKind::ExpectedConstructor => "expected constructor".into(), - ResolverErrorKind::ExpectedEffect => "expected effect".into(), - ResolverErrorKind::ExpectedFunction => "expected function".into(), - ResolverErrorKind::ExpectedRecordType => "expected record type".into(), - ResolverErrorKind::VariableNotBoundOnBothSides(name) => { - format!("variable not bound on both sides: {}", name.get()).into() - } - ResolverErrorKind::DuplicatePattern(name) => { - format!("duplicate pattern: {}", name.get()).into() - } - ResolverErrorKind::PrivateDefinition => "private definition".into(), - ResolverErrorKind::CannotHavePolymorphiEffectInTheMiddle => { - "cannot have polymorphic effect in the middle".into() - } - } - } - - fn severity(&self) -> vulpi_report::Severity { - vulpi_report::Severity::Error - } - - fn location(&self) -> Span { - self.span.clone() - } -} diff --git a/crates/vulpi-resolver/src/io.rs b/crates/vulpi-resolver/src/io.rs deleted file mode 100644 index 64f54f9..0000000 --- a/crates/vulpi-resolver/src/io.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Module for resolution of modules that are out of the current crate. This module is responsible -//! for loading the modules from the disk or other places to resolve them. - -use vulpi_syntax::concrete::tree::Program; - -use crate::{error::ResolverErrorKind, paths}; - -/// Trait for IO operations. -pub trait IO { - fn read_module(&mut self, id: paths::Path) -> Result; -} diff --git a/crates/vulpi-resolver/src/lib.rs b/crates/vulpi-resolver/src/lib.rs deleted file mode 100644 index 31f3e12..0000000 --- a/crates/vulpi-resolver/src/lib.rs +++ /dev/null @@ -1,1378 +0,0 @@ -#![feature(specialization)] -#![allow(incomplete_features)] - -use std::collections::{HashMap, HashSet}; - -use declare::{Declare, ImportResolve}; -use error::{ResolverError, ResolverErrorKind}; -use module_tree::Tree; -use namespace::{Item, ModuleId, Namespace, Namespaces, Resolve as ResolveObj, TypeValue, Value}; -use scopes::scopable::TypeVariable; -use scopes::{scopable::Variable, Scopable}; - -use vulpi_intern::Symbol; -use vulpi_location::{Span, Spanned}; -use vulpi_report::{Diagnostic, Report}; -use vulpi_syntax::concrete::{tree::*, Lower, Path}; -use vulpi_syntax::r#abstract as abs; -use vulpi_syntax::r#abstract::Qualified; - -pub mod declare; -pub mod error; -pub mod io; -pub mod module_tree; -pub mod namespace; -pub mod paths; -pub mod scopes; - -fn from_symbol(name: &[Symbol]) -> paths::Qualified { - let module = &name[0..name.len() - 1]; - let name = name[name.len() - 1].clone(); - - paths::Qualified { - path: paths::Path { - path: module.to_vec(), - }, - name, - } -} - -pub struct Context<'a> { - pub reporter: Report, - pub namespaces: &'a mut Namespaces, - pub path: paths::Path, - pub scopes: scopes::Kaleidoscope, - pub patterns: Vec>, - pub prelude: HashMap, - pub io: &'a mut dyn io::IO, -} - -impl<'a> Context<'a> { - pub fn new(reporter: Report, namespaces: &'a mut Namespaces, io: &'a mut dyn io::IO) -> Self { - Self { - reporter, - namespaces, - path: paths::Path::default(), - scopes: scopes::Kaleidoscope::default(), - patterns: Vec::new(), - prelude: HashMap::new(), - io, - } - } - - pub fn scope_namespace(&mut self, name: Symbol, fun: impl FnOnce(&mut Context) -> T) -> T { - self.path.push(name); - let res = fun(self); - self.path.pop(); - res - } - - pub fn scope(&mut self, fun: impl FnOnce(&mut Self) -> T) -> T { - self.scopes.push::(); - let result = fun(self); - self.scopes.pop::(); - result - } - - pub fn current(&self) -> Symbol { - self.path.symbol() - } - - pub fn report(&self, error: crate::error::ResolverError) { - self.reporter.report(Diagnostic::new(error)); - } - - fn report_redeclareted(&self, span: Span, name: Symbol) { - self.report(ResolverError { - span, - kind: ResolverErrorKind::Redeclarated(name), - }) - } - - fn report_not_found(&self, span: Span, name: Symbol) { - self.report(ResolverError { - span, - kind: ResolverErrorKind::NotFound(name), - }); - } - - pub fn resolve_module(&self, span: Span, name: paths::Path, entire: Symbol) -> Option { - let resolved = self.namespaces.resolve(self.path.clone(), name); - match resolved { - ResolveObj::ModuleNotFound(_) => { - self.report_not_found(span, entire); - None - } - ResolveObj::PrivateModule(_) => { - self.report_private(span); - None - } - ResolveObj::ModuleFound(name) => Some(name), - } - } - - fn report_private(&self, span: Span) { - self.report(ResolverError { - span, - kind: ResolverErrorKind::PrivateDefinition, - }) - } - - fn find( - &self, - span: Span, - module: &ModuleId, - name: paths::Qualified, - fun: F, - ) -> Option> - where - F: FnOnce(&Namespace) -> &HashMap>, - { - let Some(resolved) = self.resolve_module(span.clone(), name.path.clone(), name.symbol()) else { - return None - }; - - let namespace = self.namespaces.find(resolved).unwrap(); - - let Some(item) = fun(namespace).get(&name.name) else { - self.report_not_found(span, name.symbol()); - return None - }; - - if item.visibility == namespace::Visibility::Private && Some(module.clone()) != item.parent - { - self.report_private(span); - return None; - } - - Some(item.clone()) - } - - fn find_value(&self, span: Span, name: &[Symbol]) -> Option> { - let qualified = from_symbol(name); - let module = &self.current(); - self.find(span, module, qualified, |namespace| &namespace.values) - } - - fn find_type(&self, span: Span, name: &[Symbol]) -> Option> { - let qualified = from_symbol(name); - let module = &self.current(); - - self.find(span, module, qualified, |namespace| &namespace.types) - } - - pub fn add_pattern(&mut self, name: Symbol, span: Span) -> bool { - let hash_map = &mut self.patterns.last_mut().unwrap(); - if hash_map.insert(name.clone(), span.clone()).is_some() { - self.report(ResolverError { - span, - kind: ResolverErrorKind::DuplicatePattern(name), - }); - false - } else { - true - } - } - - fn scope_pattern(&mut self, fun: impl FnOnce(&mut Context) -> U) -> U { - if self.patterns.is_empty() { - self.patterns.push(Default::default()); - let output = fun(self); - let result = self.patterns.pop(); - - for key in result.unwrap().keys() { - self.scopes.add::(key.clone()); - } - - output - } else { - fun(self) - } - } - - fn scope_or_pattern( - &mut self, - left: impl FnOnce(&mut Context) -> U, - right: impl FnOnce(&mut Context) -> U, - ) -> Option<(U, U)> { - self.patterns.push(Default::default()); - let left_output = left(self); - let left_pop = self.patterns.pop().unwrap(); - self.patterns.push(Default::default()); - let right_output = right(self); - let right_pop = self.patterns.pop().unwrap(); - - let diff: HashSet = left_pop - .keys() - .cloned() - .collect::>() - .symmetric_difference(&right_pop.keys().cloned().collect::>()) - .cloned() - .collect(); - - let mut errored = false; - - for key in diff { - errored = true; - - let range = right_pop - .get(&key) - .unwrap_or_else(|| left_pop.get(&key).unwrap()) - .clone(); - - self.report(ResolverError { - span: range, - kind: ResolverErrorKind::VariableNotBoundOnBothSides(key), - }); - } - - self.patterns.last_mut().unwrap().extend(left_pop); - - if errored { - None - } else { - Some((left_output, right_output)) - } - } - - pub fn find_prelude_func(&mut self, span: Span, name: &str) -> Option { - if let Some(item) = self.prelude.get(&Symbol::intern(name)) { - Some(item.clone()) - } else { - let find = find_constructor_raw( - span, - &[ - Symbol::intern("Self"), - Symbol::intern("Prelude"), - Symbol::intern(name), - ], - self, - Some, - None, - ); - - if let Some(item) = find { - self.prelude.insert(Symbol::intern(name), item.clone()); - Some(item) - } else { - None - } - } - } - - pub fn find_prelude_type(&mut self, span: Span, name: &str) -> Option { - if let Some(item) = self.prelude.get(&Symbol::intern(name)) { - Some(item.clone()) - } else { - let find = find_type_raw( - span, - &[ - Symbol::intern("Self"), - Symbol::intern("Prelude"), - Symbol::intern(name), - ], - self, - Some, - None, - ); - - if let Some(item) = find { - self.prelude.insert(Symbol::intern(name), item.clone()); - Some(item) - } else { - None - } - } - } - - pub fn declare(&mut self, program: &Program) -> &mut Self { - program.declare(self); - self - } - - pub fn import(&mut self, program: &Program) -> &mut Self { - program.resolve_imports(self); - self - } - - pub fn resolve(&mut self, program: Program) -> abs::Program { - program.resolve(self) - } -} - -pub trait Resolve { - type Output; - - fn resolve(self, ctx: &mut Context) -> Self::Output; -} - -impl Resolve for Vec { - type Output = Vec; - - default fn resolve(self, ctx: &mut Context) -> Self::Output { - self.into_iter().map(|x| x.resolve(ctx)).collect() - } -} - -impl Resolve for Spanned { - type Output = Spanned; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - Spanned::new(self.data.resolve(ctx), self.span) - } -} - -impl Resolve for Box { - type Output = Box; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - Box::new((*self).resolve(ctx)) - } -} - -impl Resolve for Option { - type Output = Option; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - self.map(|x| x.resolve(ctx)) - } -} - -impl Resolve for KindType { - type Output = abs::KindType; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - KindType::Star(_) => abs::KindType::Star, - KindType::Parenthesis(n) => n.data.resolve(ctx).data, - KindType::Arrow(left, _, right) => { - abs::KindType::Arrow(left.resolve(ctx), right.resolve(ctx)) - } - KindType::Variable(name) => match name.0.symbol().get().as_str() { - "Effect" => abs::KindType::Effect, - "Constraint" => abs::KindType::Constraint, - _ => { - ctx.report(ResolverError { - span: name.0.value.span.clone(), - kind: ResolverErrorKind::NotFound(name.symbol()), - }); - abs::KindType::Error - } - }, - } - } -} - -impl Resolve for Effect { - type Output = abs::TypeKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - Effect::Application(upper, args) => { - let vec: Vec<_> = (&upper).into(); - let args = args.resolve(ctx); - - match ctx.find_type(upper.span.clone(), &vec) { - Some(Item { - item: TypeValue::Effect(qual), - .. - }) => abs::TypeKind::Application(abs::TypeApplication { - func: Box::new(Spanned { - data: abs::TypeKind::Type(qual), - span: upper.span, - }), - args, - }), - _ => abs::TypeKind::Error, - } - } - Effect::Variable(name) => abs::TypeKind::TypeVariable(name.symbol()), - } - } -} - -impl Resolve for Effects { - type Output = abs::Effects; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let mut rest = None; - let mut effects = Vec::new(); - - let len = self.effects.len(); - for (i, (effect, _)) in self.effects.into_iter().enumerate() { - let is_last = i == len - 1; - match &effect.data { - Effect::Application(_, _) => effects.push(Box::new(effect.resolve(ctx))), - Effect::Variable(l) => { - if is_last { - rest = Some(Box::new(effect.resolve(ctx))); - } else { - ctx.report(ResolverError { - span: l.0.value.span.clone(), - kind: ResolverErrorKind::CannotHavePolymorphiEffectInTheMiddle, - }) - } - } - } - } - - abs::Effects { effects, rest } - } -} - -impl Resolve for TypeArrow { - type Output = abs::PiType; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::PiType { - left: self.left.resolve(ctx), - effects: self.effects.resolve(ctx), - right: self.right.resolve(ctx), - } - } -} - -impl Resolve for TypeApplication { - type Output = abs::TypeApplication; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::TypeApplication { - func: self.func.resolve(ctx), - args: self.args.resolve(ctx), - } - } -} - -impl Resolve for TypeForall { - type Output = abs::TypeForall; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::TypeForall { - params: self.params.resolve(ctx), - body: self.body.resolve(ctx), - } - } -} - -impl Resolve for TypeKind { - type Output = abs::TypeKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - TypeKind::Type(n) => { - let vec: Vec<_> = (&n).into(); - match ctx.find_type(n.span, &vec) { - Some(Item { item, .. }) => abs::TypeKind::Type(item.qualified().clone()), - None => abs::TypeKind::Error, - } - } - TypeKind::TypeVariable(n) => abs::TypeKind::TypeVariable(n.symbol()), - TypeKind::Parenthesis(n) => n.data.0.resolve(ctx).data, - TypeKind::Arrow(n) => abs::TypeKind::Arrow(n.resolve(ctx)), - TypeKind::Application(n) => abs::TypeKind::Application(n.resolve(ctx)), - TypeKind::Forall(n) => abs::TypeKind::Forall(n.resolve(ctx)), - TypeKind::Unit(_) => abs::TypeKind::Unit, - TypeKind::Tuple(n) => { - abs::TypeKind::Tuple(n.data.into_iter().map(|x| x.0.resolve(ctx)).collect()) - } - } - } -} - -impl Resolve for LiteralKind { - type Output = abs::LiteralKind; - - fn resolve(self, _ctx: &mut Context) -> Self::Output { - match self { - LiteralKind::String(n) => abs::LiteralKind::String(n.symbol()), - LiteralKind::Integer(n) => abs::LiteralKind::Integer(n.symbol()), - LiteralKind::Float(n) => abs::LiteralKind::Float(n.symbol()), - LiteralKind::Char(n) => abs::LiteralKind::Char(n.symbol()), - LiteralKind::Unit(_) => abs::LiteralKind::Unit, - } - } -} - -impl Resolve for Vec { - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope_pattern(|ctx| self.into_iter().map(|x| x.resolve(ctx)).collect()) - } -} - -impl Resolve for PatternKind { - type Output = abs::PatternKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope_pattern(|ctx| match self { - PatternKind::Variable(n) => { - if ctx.add_pattern(n.symbol(), n.0.value.span.clone()) { - abs::PatternKind::Variable(n.symbol()) - } else { - abs::PatternKind::Error - } - } - PatternKind::Constructor(n) => PatternKind::Application(PatApplication { - func: n, - args: vec![], - }) - .resolve(ctx), - PatternKind::Wildcard(_) => abs::PatternKind::Wildcard, - PatternKind::Literal(n) => abs::PatternKind::Literal(Box::new(n.resolve(ctx))), - PatternKind::Annotation(n) => abs::PatternKind::Ascription(n.resolve(ctx)), - PatternKind::Or(n) => n.resolve(ctx), - PatternKind::Application(n) => n.resolve(ctx), - PatternKind::EffectApp(n) => n.resolve(ctx), - PatternKind::Parenthesis(n) => n.data.resolve(ctx).data, - PatternKind::Tuple(tuple) => abs::PatternKind::Tuple( - tuple - .into_iter() - .map(|x| Box::new(x.0.resolve(ctx))) - .collect(), - ), - }) - } -} - -impl Resolve for PatAscription { - type Output = abs::PatAscription; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::PatAscription { - pat: self.left.resolve(ctx), - typ: self.right.resolve(ctx), - } - } -} - -impl Resolve for PatOr { - type Output = abs::PatternKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let scopes = - ctx.scope_or_pattern(|ctx| self.left.resolve(ctx), |ctx| self.right.resolve(ctx)); - - if let Some((left, right)) = scopes { - abs::PatternKind::Or(abs::PatOr { left, right }) - } else { - abs::PatternKind::Error - } - } -} - -impl Resolve for PatApplication { - type Output = abs::PatternKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let func: Vec<_> = (&self.func).into(); - let func = match ctx.find_value(self.func.span.clone(), &func) { - Some(Item { - item: Value::Constructor(qual), - .. - }) => qual, - Some(_) => { - ctx.report(ResolverError { - span: self.func.span, - kind: ResolverErrorKind::ExpectedConstructor, - }); - return abs::PatternKind::Error; - } - None => { - return abs::PatternKind::Error; - } - }; - - abs::PatternKind::Application(abs::PatApplication { - func, - args: self.args.resolve(ctx), - }) - } -} - -impl Resolve for PatEffectApp { - type Output = abs::PatternKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let args = self.args.resolve(ctx); - - let func: Vec<_> = (&self.func).into(); - - let cont = self.arrow.map(|(_, name)| { - ctx.scopes.add::(name.symbol()); - name.symbol() - }); - - let func = match ctx.find_value(self.func.span.clone(), &func) { - Some(Item { - item: Value::Effect(qual), - .. - }) => qual, - Some(_) => { - ctx.report(ResolverError { - span: self.func.span, - kind: ResolverErrorKind::ExpectedEffect, - }); - return abs::PatternKind::Error; - } - None => { - return abs::PatternKind::Error; - } - }; - - abs::PatternKind::Effect(abs::PatEffect { func, args, cont }) - } -} - -impl Resolve for LambdaExpr { - type Output = abs::Expr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope::(|ctx| { - let params = self.patterns.resolve(ctx); - let body = self.expr.resolve(ctx); - - params.into_iter().rfold(body, |body, param| { - Box::new(Spanned { - span: param.span.clone().mix(body.span.clone()), - data: abs::ExprKind::Lambda(abs::LambdaExpr { param, body }), - }) - }) - }) - } -} - -impl Resolve for ApplicationExpr { - type Output = abs::ApplicationExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::ApplicationExpr { - app: abs::AppKind::Normal, - func: self.func.resolve(ctx), - args: self.args.resolve(ctx), - } - } -} - -impl Resolve for ProjectionExpr { - type Output = abs::ProjectionExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::ProjectionExpr { - expr: self.expr.resolve(ctx), - field: self.field.symbol(), - } - } -} - -impl Resolve for Operator { - type Output = abs::Expr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (span, name) = match self { - Operator::Add(token) => (token.value.span, "add"), - Operator::Sub(token) => (token.value.span, "sub"), - Operator::Mul(token) => (token.value.span, "mul"), - Operator::Div(token) => (token.value.span, "div"), - Operator::Rem(token) => (token.value.span, "rem"), - Operator::And(token) => (token.value.span, "and"), - Operator::Or(token) => (token.value.span, "or"), - Operator::Xor(token) => (token.value.span, "xor"), - Operator::Not(token) => (token.value.span, "not"), - Operator::Eq(token) => (token.value.span, "eq"), - Operator::Neq(token) => (token.value.span, "neq"), - Operator::Lt(token) => (token.value.span, "lt"), - Operator::Gt(token) => (token.value.span, "gt"), - Operator::Le(token) => (token.value.span, "le"), - Operator::Ge(token) => (token.value.span, "ge"), - Operator::Shl(token) => (token.value.span, "shl"), - Operator::Shr(token) => (token.value.span, "shr"), - Operator::Pipe(token) => (token.value.span, "pipe"), - }; - - let x = &[Symbol::intern("Operator"), Symbol::intern(name)]; - - let kind = match ctx.find_value(span.clone(), x) { - Some(Item { - item: Value::Function(qual), - .. - }) => abs::ExprKind::Function(qual), - Some(_) => { - ctx.report(ResolverError { - span: span.clone(), - kind: ResolverErrorKind::ExpectedConstructor, - }); - abs::ExprKind::Error - } - None => abs::ExprKind::Error, - }; - - Box::new(Spanned::new(kind, span)) - } -} - -impl Resolve for BinaryExpr { - type Output = abs::ExprKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::ExprKind::Application(abs::ApplicationExpr { - func: self.op.resolve(ctx), - args: vec![self.left.resolve(ctx), self.right.resolve(ctx)], - app: abs::AppKind::Infix, - }) - } -} - -impl Resolve for IfExpr { - type Output = abs::ExprKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let true_cons = ctx - .find_prelude_func(self.if_.value.span.clone(), "True") - .map(|func| abs::PatternKind::Application(abs::PatApplication { func, args: vec![] })) - .unwrap_or(abs::PatternKind::Error); - - let false_cons = ctx - .find_prelude_func(self.if_.value.span.clone(), "False") - .map(|func| abs::PatternKind::Application(abs::PatApplication { func, args: vec![] })) - .unwrap_or(abs::PatternKind::Error); - - abs::ExprKind::When(abs::WhenExpr { - scrutinee: vec![self.cond.resolve(ctx)], - arms: vec![ - abs::PatternArm { - patterns: vec![Box::new(Spanned::new( - true_cons, - self.if_.value.span.clone(), - ))], - expr: self.then_expr.resolve(ctx), - guard: None, - }, - abs::PatternArm { - patterns: vec![Box::new(Spanned::new( - false_cons, - self.if_.value.span.clone(), - ))], - expr: self.else_expr.resolve(ctx), - guard: None, - }, - ], - }) - } -} - -impl Resolve for PatternArm { - type Output = abs::PatternArm; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope::(|ctx| { - let patterns = ctx.scope_pattern(|ctx| { - self.patterns - .into_iter() - .map(|x| x.0.resolve(ctx)) - .collect() - }); - abs::PatternArm { - patterns, - expr: self.expr.resolve(ctx), - guard: self.guard.map(|x| x.1).resolve(ctx), - } - }) - } -} - -impl Resolve for WhenExpr { - type Output = abs::WhenExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::WhenExpr { - scrutinee: self - .scrutinee - .into_iter() - .map(|x| x.0.resolve(ctx)) - .collect(), - arms: self.arms.resolve(ctx), - } - } -} - -impl Resolve for AnnotationExpr { - type Output = abs::AnnotationExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::AnnotationExpr { - expr: self.expr.resolve(ctx), - ty: self.ty.resolve(ctx), - } - } -} - -impl Resolve for LetExpr { - type Output = abs::LetExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (pattern, value) = - ctx.scope::(|ctx| (self.pattern.resolve(ctx), self.value.resolve(ctx))); - - abs::LetExpr { - body: self.body.resolve(ctx), - pattern, - value, - } - } -} - -impl Resolve for RecordField { - type Output = (Symbol, abs::Expr); - - fn resolve(self, ctx: &mut Context) -> Self::Output { - (self.name.symbol(), self.expr.resolve(ctx)) - } -} - -impl Resolve for RecordInstance { - type Output = abs::ExprKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let vec: Vec<_> = (&self.name).into(); - - let name = match ctx.find_type(self.name.span.clone(), &vec) { - Some(Item { - item: TypeValue::Record(n), - .. - }) => n, - Some(_) => { - ctx.report(ResolverError { - span: self.name.span, - kind: ResolverErrorKind::ExpectedRecordType, - }); - return abs::ExprKind::Error; - } - None => return abs::ExprKind::Error, - }; - - abs::ExprKind::RecordInstance(abs::RecordInstance { - name, - fields: self - .fields - .into_iter() - .map(|x| { - let span = x.0.name.0.value.span.clone(); - let (y, z) = x.0.resolve(ctx); - (span, y, z) - }) - .collect(), - }) - } -} - -impl Resolve for RecordUpdate { - type Output = abs::RecordUpdate; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::RecordUpdate { - expr: self.expr.resolve(ctx), - fields: self - .fields - .into_iter() - .map(|x| { - let span = x.0.name.0.value.span.clone(); - let (y, z) = x.0.resolve(ctx); - (span, y, z) - }) - .collect(), - } - } -} - -impl Resolve for HandlerExpr { - type Output = abs::HandlerExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::HandlerExpr { - expr: self.expr.resolve(ctx), - with: self.handler.resolve(ctx), - } - } -} - -impl Resolve for CasesExpr { - type Output = abs::CasesExpr; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::CasesExpr { - arms: self.arms.resolve(ctx), - } - } -} - -impl Resolve for Tuple { - type Output = abs::Tuple; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::Tuple { - exprs: self.data.into_iter().map(|x| x.0.resolve(ctx)).collect(), - } - } -} - -impl Resolve for LetSttm { - type Output = abs::LetStatement; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::LetStatement { - pattern: self.pattern.resolve(ctx), - expr: self.expr.resolve(ctx), - } - } -} - -impl Resolve for StatementKind { - type Output = abs::StatementKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - StatementKind::Let(x) => abs::StatementKind::Let(x.resolve(ctx)), - StatementKind::Expr(x) => abs::StatementKind::Expr(x.resolve(ctx)), - StatementKind::Error(_) => abs::StatementKind::Error, - } - } -} - -impl Resolve for DoExpr { - type Output = abs::Block; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope::(|ctx| abs::Block { - statements: self.block.statements.resolve(ctx), - }) - } -} - -impl Resolve for ExprKind { - type Output = abs::ExprKind; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - ExprKind::Constructor(x) => { - let vec: Vec<_> = (&x).into(); - find_constructor_raw( - x.span, - &vec, - ctx, - abs::ExprKind::Constructor, - abs::ExprKind::Error, - ) - } - ExprKind::Variable(x) => { - if ctx.scopes.contains::(&x.symbol()) { - abs::ExprKind::Variable(x.symbol()) - } else if let Some(val) = ctx.find_value(x.0.value.span.clone(), &[x.symbol()]) { - match val.item { - Value::Module(_) => todo!(), - Value::Field(_) => todo!(), - Value::Function(qual) => abs::ExprKind::Function(qual), - Value::Effect(eff) => abs::ExprKind::Effect(eff), - Value::Constructor(qual) => abs::ExprKind::Constructor(qual), - } - } else { - abs::ExprKind::Error - } - } - ExprKind::Function(x) => expect_function_or_effect(x, ctx), - ExprKind::Do(x) => abs::ExprKind::Do(x.resolve(ctx)), - ExprKind::Lambda(x) => x.resolve(ctx).data, - ExprKind::Application(x) => accumulate(abs::ExprKind::Application(x.resolve(ctx))), - ExprKind::Acessor(x) => abs::ExprKind::Projection(x.resolve(ctx)), - ExprKind::Binary(x) => x.resolve(ctx), - ExprKind::Let(x) => abs::ExprKind::Let(x.resolve(ctx)), - ExprKind::If(x) => x.resolve(ctx), - ExprKind::When(x) => abs::ExprKind::When(x.resolve(ctx)), - ExprKind::Literal(x) => abs::ExprKind::Literal(Box::new(x.resolve(ctx))), - ExprKind::Handler(x) => abs::ExprKind::Handler(x.resolve(ctx)), - ExprKind::Cases(x) => abs::ExprKind::Cases(x.resolve(ctx)), - ExprKind::Annotation(x) => abs::ExprKind::Annotation(x.resolve(ctx)), - ExprKind::RecordInstance(x) => x.resolve(ctx), - ExprKind::RecordUpdate(x) => abs::ExprKind::RecordUpdate(x.resolve(ctx)), - ExprKind::Parenthesis(x) => x.data.0.resolve(ctx).data, - ExprKind::Tuple(x) => abs::ExprKind::Tuple(x.resolve(ctx)), - } - } -} - -fn expect_function_or_effect(x: Path, ctx: &Context) -> abs::ExprKind { - let vec: Vec<_> = (&x).into(); - - match ctx.find_value(x.span.clone(), &vec) { - Some(Item { - item: Value::Function(qual), - .. - }) => abs::ExprKind::Function(qual), - Some(Item { - item: Value::Effect(qual), - .. - }) => abs::ExprKind::Effect(qual), - Some(_) => { - ctx.report(ResolverError { - span: x.span, - kind: ResolverErrorKind::ExpectedFunction, - }); - abs::ExprKind::Error - } - None => abs::ExprKind::Error, - } -} - -impl Resolve for Binder { - type Output = abs::Binder; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::Binder { - pattern: self.pattern.resolve(ctx), - ty: self.typ.resolve(ctx), - } - } -} - -impl Resolve for LetCase { - type Output = abs::PatternArm; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - self.arm.resolve(ctx) - } -} - -impl Resolve for LetMode { - type Output = Vec; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - LetMode::Body(_, expr) => vec![abs::PatternArm { - patterns: vec![], - expr: expr.resolve(ctx), - guard: None, - }], - LetMode::Cases(cases) => cases.resolve(ctx), - } - } -} - -impl Resolve for LetDecl { - type Output = abs::LetDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope::(|ctx| abs::LetDecl { - visibility: self.visibility.resolve(ctx), - name: Qualified { - path: ctx.current(), - name: self.name.symbol(), - }, - binders: ctx.scope_pattern(|ctx| self.binders.resolve(ctx)), - ret: self.ret.map(|x| (x.1.resolve(ctx), x.2.resolve(ctx))), - body: self.body.resolve(ctx), - }) - } -} - -impl Resolve for (Symbol, Constructor) { - type Output = abs::Constructor; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::Constructor { - name: ctx.path.with(self.0).qualify(self.1.name.symbol()).into(), - args: self.1.args.resolve(ctx), - typ: self.1.typ.map(|x| x.1.resolve(ctx)), - } - } -} - -impl Resolve for (Symbol, SumDecl) { - type Output = abs::SumDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (symbol, cons) = self; - abs::SumDecl { - constructors: cons - .constructors - .into_iter() - .map(|x| (symbol.clone(), x).resolve(ctx)) - .collect(), - } - } -} - -impl Resolve for (Symbol, Field) { - type Output = (Qualified, abs::Type); - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ( - ctx.path.with(self.0).qualify(self.1.name.symbol()).into(), - self.1.ty.resolve(ctx), - ) - } -} - -impl Resolve for (Symbol, RecordDecl) { - type Output = abs::RecordDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (symbol, rec) = self; - abs::RecordDecl { - fields: rec - .fields - .into_iter() - .map(|x| (symbol.clone(), x.0).resolve(ctx)) - .collect(), - } - } -} - -impl Resolve for (Symbol, TypeDef) { - type Output = abs::TypeDef; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (symbol, def) = self; - match def { - TypeDef::Sum(sum) => abs::TypeDef::Sum((symbol, sum).resolve(ctx)), - TypeDef::Record(rec) => abs::TypeDef::Record((symbol, rec).resolve(ctx)), - TypeDef::Synonym(sym) => abs::TypeDef::Synonym(sym.resolve(ctx)), - } - } -} - -impl Resolve for TypeDecl { - type Output = abs::TypeDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let path = ctx.current(); - ctx.scope::(|ctx| abs::TypeDecl { - namespace: ctx.path.with(self.name.symbol()).symbol(), - visibility: self.visibility.resolve(ctx), - name: Qualified { - path, - name: self.name.symbol(), - }, - binders: self.binders.resolve(ctx), - def: if let Some(res) = self.def { - (self.name.symbol(), res.1).resolve(ctx) - } else { - abs::TypeDef::Abstract - }, - }) - } -} - -impl Resolve for ModuleInline { - type Output = abs::Program; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let mut module = abs::Program::default(); - - self.top_levels - .into_iter() - .for_each(|x| (&mut module, x).resolve(ctx)); - - module - } -} - -impl Resolve for ModuleDecl { - type Output = abs::ModuleDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - ctx.scope_namespace(self.name.symbol(), |ctx| abs::ModuleDecl { - namespace: ctx.current(), - visibility: self.visibility.resolve(ctx), - name: self.name.symbol(), - decls: self.part.resolve(ctx), - }) - } -} - -impl Resolve for Visibility { - type Output = abs::Visibility; - - fn resolve(self, _: &mut Context) -> Self::Output { - match self { - Visibility::Public(_) => abs::Visibility::Public, - Visibility::Private => abs::Visibility::Private, - } - } -} - -impl Resolve for TypeBinder { - type Output = abs::TypeBinder; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - match self { - TypeBinder::Implicit(name) => { - ctx.scopes.add::(name.symbol()); - abs::TypeBinder::Implicit(name.symbol()) - } - TypeBinder::Explicit(binder) => { - ctx.scopes.add::(binder.data.name.symbol()); - abs::TypeBinder::Explicit(binder.data.name.symbol(), binder.data.kind.resolve(ctx)) - } - } - } -} - -impl Resolve for (Qualified, EffectField) { - type Output = abs::EffectField; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (name, effect) = self; - abs::EffectField { - visibility: effect.visibility.resolve(ctx), - name: ctx - .path - .with(name.name) - .qualify(effect.name.symbol()) - .into(), - args: effect.args.resolve(ctx), - ty: effect.ret.resolve(ctx), - } - } -} - -impl Resolve for EffectDecl { - type Output = abs::EffectDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let path = ctx.current(); - let name = Qualified { - path, - name: self.name.symbol(), - }; - abs::EffectDecl { - namespace: ctx.current(), - name: name.clone(), - visibility: self.visibility.resolve(ctx), - binders: self.binders.resolve(ctx), - effects: self - .fields - .into_iter() - .map(|x| (name.clone(), x).resolve(ctx)) - .collect(), - } - } -} - -impl Resolve for ExternalDecl { - type Output = abs::ExternalDecl; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - abs::ExternalDecl { - namespace: ctx.current(), - visibility: self.visibility.resolve(ctx), - name: Qualified { - path: ctx.current(), - name: self.name.symbol(), - }, - ty: self.typ.resolve(ctx), - ret: self.str.symbol(), - } - } -} - -impl Resolve for (&'_ mut abs::Program, TopLevel) { - type Output = (); - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let (module, top_level) = self; - - match top_level { - TopLevel::Let(let_) => module.lets.push(*let_.resolve(ctx)), - TopLevel::Type(typ) => module.types.push(*typ.resolve(ctx)), - TopLevel::Module(modul) => module.modules.push(*modul.resolve(ctx)), - TopLevel::Effect(effect) => module.effects.push(*effect.resolve(ctx)), - TopLevel::External(external) => module.externals.push(*external.resolve(ctx)), - TopLevel::Error(_) => (), - TopLevel::Use(_) => (), - } - } -} - -impl Resolve for Program { - type Output = abs::Program; - - fn resolve(self, ctx: &mut Context) -> Self::Output { - let mut module = abs::Program::default(); - - self.top_levels - .into_iter() - .for_each(|x| (&mut module, x).resolve(ctx)); - - module - } -} - -fn find_type_raw( - span: Span, - x: &[Symbol], - ctx: &Context, - ok: fn(Qualified) -> T, - error: T, -) -> T { - match ctx.find_type(span, x) { - Some(Item { item, .. }) => ok(item.qualified().clone()), - None => error, - } -} - -fn find_constructor_raw( - span: Span, - x: &[Symbol], - ctx: &Context, - ok: fn(Qualified) -> T, - error: T, -) -> T { - match ctx.find_value(span.clone(), x) { - Some(Item { - item: Value::Constructor(qual), - .. - }) => ok(qual), - Some(_) => { - ctx.report(ResolverError { - span, - kind: ResolverErrorKind::ExpectedConstructor, - }); - error - } - None => error, - } -} - -pub fn namespaces() -> Namespaces { - let tree = Tree::new(Symbol::intern("")); - let mut namespaces = HashMap::new(); - - namespaces.insert(Symbol::intern(""), Namespace::new(paths::Path::default())); - - Namespaces { tree, namespaces } -} - -pub fn resolver<'a>( - reporter: Report, - namespaces: &'a mut Namespaces, - io: &'a mut dyn io::IO, -) -> Context<'a> { - Context::new(reporter, namespaces, io) -} - -pub fn accumulate(app: abs::ExprKind) -> abs::ExprKind { - match app { - abs::ExprKind::Application(app1) => match app1.func.data { - abs::ExprKind::Application(app2) => { - let mut args = app2.args; - args.extend(app1.args); - - abs::ExprKind::Application(abs::ApplicationExpr { - func: app2.func, - args, - app: abs::AppKind::Normal, - }) - } - _ => vulpi_syntax::r#abstract::ExprKind::Application(app1), - }, - _ => app, - } -} diff --git a/crates/vulpi-resolver/src/module_tree.rs b/crates/vulpi-resolver/src/module_tree.rs deleted file mode 100644 index 2a1ad46..0000000 --- a/crates/vulpi-resolver/src/module_tree.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! This module declares a [Tree] that is responsible for declaring the modules and their -//! child. - -use std::collections::HashMap; - -use vulpi_intern::Symbol; -use vulpi_show::{Show, TreeDisplay}; - -use crate::namespace::ModuleId; - -/// A tree for modules. It starts with a single root module and then it can have multiple children -/// modules. -pub struct Tree { - pub id: ModuleId, - pub modules: HashMap, -} - -impl Show for Tree { - fn show(&self) -> vulpi_show::TreeDisplay { - let mut display = vulpi_show::TreeDisplay::label(&format!("ModuleTree: {}", self.id.get())); - let child = TreeDisplay::label("child"); - - for (name, module) in &self.modules { - display = display.with(TreeDisplay::label(&name.get()).with(module.show())); - } - - display.with(child) - } -} - -impl Tree { - pub fn new(id: ModuleId) -> Self { - Self { - id, - modules: HashMap::new(), - } - } - - /// Adds a new entry to the tree (It only adds the entry if the last symbol is not present - /// in the tree). - pub fn add(&mut self, name: &[Symbol], id: ModuleId) -> Option<&mut Self> { - if name.is_empty() { - return None; - } - - let (head, tail) = name.split_first().unwrap(); - - if tail.is_empty() { - Some( - self.modules - .entry(head.clone()) - .or_insert_with(|| Tree::new(id)), - ) - } else { - let module = self.modules.get_mut(head).unwrap(); - module.add(tail, id) - } - } - - /// Finds a mutable subtree in the tree. - pub fn find_mut(&mut self, name: &[Symbol]) -> Option<&mut Tree> { - let mut current = self; - - for symbol in name { - current = current.modules.get_mut(symbol)?; - } - - Some(current) - } - - /// Finds a subtree in the tree. - pub fn find(&self, name: &[Symbol]) -> Option<&Tree> { - let mut current = self; - - for symbol in name { - current = current.modules.get(symbol)?; - } - - Some(current) - } -} diff --git a/crates/vulpi-resolver/src/namespace.rs b/crates/vulpi-resolver/src/namespace.rs deleted file mode 100644 index 3589db8..0000000 --- a/crates/vulpi-resolver/src/namespace.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! This module contains the definition of the [Namespace] struct and all the types that are used -//! to represent the definitions inside of it. - -use std::collections::HashMap; - -use vulpi_intern::Symbol; -use vulpi_location::Span; -use vulpi_macros::Show; -use vulpi_show::TreeDisplay; -use vulpi_syntax::r#abstract::Qualified; - -use crate::{module_tree::Tree, paths}; - -/// An identifier for a module. -pub type ModuleId = Symbol; - -/// The visibility of a definition. It's used to distinguish between public and private definitions. -#[derive(Show, Clone, Debug, PartialEq, Eq)] -pub enum Visibility { - Public, - Private, -} - -/// A [Value] is a definition in a [Namespace] that is in the value namespace. -#[derive(Clone)] -pub enum Value { - Module(ModuleId), - Function(Qualified), - Effect(Qualified), - Constructor(Qualified), - Field(Qualified), -} - -/// A [TypeValue] is a definition in a [Namespace] that is in the type namespace. -#[derive(Clone, Debug)] -pub enum TypeValue { - Enum(Qualified), - Effect(Qualified), - Record(Qualified), - Abstract(Qualified), -} - -impl TypeValue { - pub fn qualified(&self) -> &Qualified { - match self { - TypeValue::Enum(qualified) => qualified, - TypeValue::Effect(qualified) => qualified, - TypeValue::Record(qualified) => qualified, - TypeValue::Abstract(qualified) => qualified, - } - } -} - -impl vulpi_show::Show for TypeValue { - fn show(&self) -> TreeDisplay { - match self { - TypeValue::Enum(q) => TreeDisplay::label(&format!("Enum: {:?}", q)), - TypeValue::Effect(q) => TreeDisplay::label(&format!("Effect: {:?}", q)), - TypeValue::Record(q) => TreeDisplay::label(&format!("Record: {:?}", q)), - TypeValue::Abstract(q) => TreeDisplay::label(&format!("Abstract: {:?}", q)), - } - } -} - -impl vulpi_show::Show for Value { - fn show(&self) -> TreeDisplay { - match self { - Value::Module(id) => TreeDisplay::label(&format!("Module: {}", id.get())), - Value::Function(q) => TreeDisplay::label(&format!("Function: {:?}", q)), - Value::Effect(q) => TreeDisplay::label(&format!("Effect: {:?}", q)), - Value::Constructor(q) => TreeDisplay::label(&format!("Constructor: {:?}", q)), - Value::Field(q) => TreeDisplay::label(&format!("Field: {:?}", q)), - } - } -} - -/// An [Item] is a definition in a [Namespace]. It's used to map a [Name] to a [Qualified] definition. -#[derive(Clone, Debug)] -pub struct Item { - pub parent: Option, - pub visibility: Visibility, - pub span: Span, - pub item: Kind, -} - -impl vulpi_show::Show for Item { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(&format!("{:?} ", self.visibility)).with(self.item.show()) - } -} - -/// A [Namespace] is a bunch of [Name] mapped to [Qualified] definitions. It's used in the first -/// step of the resolution process to map all the names to their definitions. After that, it's -/// thrown away and a [] is created. -#[derive(Clone)] -pub struct Namespace { - pub name: paths::Path, - pub values: HashMap>, - pub types: HashMap>, - pub modules: HashMap>, -} - -impl Namespace { - pub fn new(name: paths::Path) -> Self { - Self { - name, - values: HashMap::new(), - types: HashMap::new(), - modules: HashMap::new(), - } - } -} - -impl Namespace { - pub fn merge(&mut self, other: Namespace) { - self.values.extend(other.values); - self.types.extend(other.types); - self.modules.extend(other.modules); - } -} - -pub enum Resolve { - ModuleNotFound(Symbol), - ModuleFound(Symbol), - PrivateModule(Symbol), -} - -pub struct Namespaces { - pub tree: Tree, - pub namespaces: HashMap, -} - -impl Namespaces { - pub fn get(&self, name: paths::Path) -> Option<&Namespace> { - self.namespaces.get(&name.symbol()) - } - - pub fn get_mut(&mut self, name: paths::Path) -> Option<&mut Namespace> { - self.namespaces.get_mut(&name.symbol()) - } - - pub fn find(&self, name: Symbol) -> Option<&Namespace> { - self.namespaces.get(&name) - } - - pub fn add(&mut self, name: paths::Path) -> Option<&mut Tree> { - let symbol = name.symbol(); - - self.namespaces - .entry(symbol.clone()) - .or_insert_with(|| Namespace::new(name.clone())); - - self.tree.add(name.slice(), symbol) - } - - pub fn add_with(&mut self, name: paths::Path, namespace: Namespace) -> Option<&mut Tree> { - let symbol = name.symbol(); - - self.namespaces - .entry(symbol.clone()) - .or_insert_with(|| namespace); - - self.tree.add(name.slice(), symbol) - } - - pub fn resolve(&self, current: paths::Path, mut name: paths::Path) -> Resolve { - let module = self.tree.find(current.slice()).unwrap(); - let mut id = module.id.clone(); - let mut namespace = self.namespaces.get(&module.id).unwrap(); - - if let Some((head, tail)) = name.split_first() { - if head.get() == "Self" { - namespace = self.namespaces.get(&self.tree.id).unwrap(); - id = self.tree.id.clone(); - name = tail; - } - } - - while let Some((head, tail)) = name.split_first() { - name = tail; - if let Some(item) = namespace.modules.get(&head) { - if item.visibility == Visibility::Private && Some(module.id.clone()) != item.parent - { - return Resolve::PrivateModule(head); - } else { - namespace = self.namespaces.get(&item.item).unwrap(); - id = item.item.clone(); - } - } else { - return Resolve::ModuleNotFound(head); - } - } - - Resolve::ModuleFound(id) - } -} diff --git a/crates/vulpi-resolver/src/paths.rs b/crates/vulpi-resolver/src/paths.rs deleted file mode 100644 index e64f8b9..0000000 --- a/crates/vulpi-resolver/src/paths.rs +++ /dev/null @@ -1,79 +0,0 @@ -use vulpi_intern::Symbol; -use vulpi_syntax::r#abstract; - -#[derive(Clone, Default, Debug)] -pub struct Path { - pub path: Vec, -} - -impl Path { - pub fn split_first(&self) -> Option<(Symbol, Path)> { - if self.path.is_empty() { - None - } else { - let (head, tail) = self.path.split_first().unwrap(); - Some(( - head.clone(), - Path { - path: tail.to_vec(), - }, - )) - } - } - - pub fn push(&mut self, name: Symbol) { - self.path.push(name); - } - - pub fn pop(&mut self) -> Option { - self.path.pop() - } - - pub fn slice(&self) -> &[Symbol] { - &self.path - } - - pub fn symbol(&self) -> Symbol { - Symbol::intern( - &self - .path - .iter() - .map(|x| x.get()) - .collect::>() - .join("."), - ) - } - - pub fn with(&self, name: Symbol) -> Path { - let mut path = self.clone(); - path.push(name); - path - } - - pub fn qualify(&self, name: Symbol) -> Qualified { - Qualified { - path: self.clone(), - name, - } - } -} - -impl From for r#abstract::Qualified { - fn from(value: Qualified) -> Self { - r#abstract::Qualified { - path: value.path.symbol(), - name: value.name, - } - } -} - -pub struct Qualified { - pub path: Path, - pub name: Symbol, -} - -impl Qualified { - pub fn symbol(&self) -> Symbol { - self.path.with(self.name.clone()).symbol() - } -} diff --git a/crates/vulpi-resolver/src/scopes.rs b/crates/vulpi-resolver/src/scopes.rs deleted file mode 100644 index c0cca04..0000000 --- a/crates/vulpi-resolver/src/scopes.rs +++ /dev/null @@ -1,87 +0,0 @@ -pub mod scopable { - pub enum Variable {} - pub enum TypeVariable {} -} - -pub use vulpi_intern::Symbol; - -#[derive(Clone)] -pub struct Scope { - pub map: Vec>, -} - -impl Default for Scope { - fn default() -> Self { - Self { - map: vec![Default::default()], - } - } -} - -impl Scope { - pub fn push(&mut self) { - self.map.push(Default::default()); - } - - pub fn pop(&mut self) { - self.map.pop(); - } -} - -/// Just a fun name for a structure that contains a bunch of scopes. It's used to resolve the -/// symbols. - -#[derive(Clone, Default)] -pub struct Kaleidoscope { - pub variables: Scope, - pub type_variables: Scope, -} - -pub trait Scoped { - fn push(kaleidoscope: &mut Kaleidoscope); - fn pop(kaleidoscope: &mut Kaleidoscope); -} - -pub trait Scopable { - fn scope(kaleidoscope: &mut Kaleidoscope) -> &mut Scope; -} - -impl Scopable for scopable::Variable { - fn scope(kaleidoscope: &mut Kaleidoscope) -> &mut Scope { - &mut kaleidoscope.variables - } -} - -impl Scopable for scopable::TypeVariable { - fn scope(kaleidoscope: &mut Kaleidoscope) -> &mut Scope { - &mut kaleidoscope.type_variables - } -} - -impl Kaleidoscope { - pub fn push(&mut self) { - T::scope(self).push(); - } - - pub fn pop(&mut self) { - T::scope(self).pop(); - } - - pub fn scope(&mut self, fun: impl FnOnce(&mut Self)) { - self.push::(); - fun(self); - self.pop::(); - } - - pub fn add(&mut self, name: Symbol) { - T::scope(self).map.last_mut().unwrap().insert(name); - } - - pub fn contains(&mut self, name: &Symbol) -> bool { - T::scope(self) - .map - .iter() - .rev() - .any(|scope| scope.contains(name)) - } -} diff --git a/crates/vulpi-show/src/lib.rs b/crates/vulpi-show/src/lib.rs deleted file mode 100644 index 382d80a..0000000 --- a/crates/vulpi-show/src/lib.rs +++ /dev/null @@ -1,167 +0,0 @@ -use std::{ - collections::{HashMap, HashSet}, - fmt::Display, - ops::Range, -}; - -#[derive(Debug)] -pub struct TreeDisplay { - pub label: String, - pub children: Vec, -} - -impl TreeDisplay { - pub fn pretty_print( - &self, - fmt: &mut std::fmt::Formatter, - indent: String, - last: bool, - ) -> std::fmt::Result { - let indent_now = format!("{}{}", indent, if last { "└" } else { "├" }); - writeln!(fmt, "{}{}", indent_now, self.label)?; - let indent = format!("{}{} ", indent, if last { " " } else { "│" }); - for (index, child) in self.children.iter().enumerate() { - child.pretty_print(fmt, indent.clone(), index == self.children.len() - 1)?; - } - Ok(()) - } - - pub fn label(label: &str) -> Self { - Self { - label: label.to_string(), - children: vec![], - } - } - - pub fn with(mut self, child: TreeDisplay) -> Self { - self.children.push(child); - self - } -} - -impl Display for TreeDisplay { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - self.pretty_print(fmt, "".to_string(), true) - } -} - -pub trait Show { - fn show(&self) -> TreeDisplay; -} - -impl Show for &T { - fn show(&self) -> TreeDisplay { - (*self).show() - } -} - -impl Show for usize { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(&self.to_string()) - } -} - -impl Show for String { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(self) - } -} - -impl Show for &str { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(self) - } -} - -impl Show for Box { - fn show(&self) -> TreeDisplay { - self.as_ref().show() - } -} - -impl Show for Vec { - fn show(&self) -> TreeDisplay { - let mut node = TreeDisplay::label("Vec"); - for child in self { - node = node.with(child.show()); - } - node - } -} - -impl Show for HashMap { - fn show(&self) -> TreeDisplay { - let mut node = TreeDisplay::label("HashMap"); - for (key, value) in self { - node = node.with( - TreeDisplay::label("Entry") - .with(key.show()) - .with(value.show()), - ); - } - node - } -} - -impl Show for HashSet { - fn show(&self) -> TreeDisplay { - let mut node = TreeDisplay::label("HashSet"); - for child in self { - node = node.with(child.show()); - } - node - } -} - -impl Show for (T, U) { - fn show(&self) -> TreeDisplay { - let mut node = TreeDisplay::label("Tuple"); - node = node.with(self.0.show()); - node = node.with(self.1.show()); - node - } -} - -impl Show for (T, U, V) { - fn show(&self) -> TreeDisplay { - let mut node = TreeDisplay::label("Tuple"); - node = node.with(self.0.show()); - node = node.with(self.1.show()); - node = node.with(self.2.show()); - node - } -} - -impl Show for Range { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(&format!("Range({:?}..{:?})", self.start, self.end)) - } -} - -impl Show for bool { - fn show(&self) -> TreeDisplay { - TreeDisplay::label(&self.to_string()) - } -} - -impl Show for Option { - fn show(&self) -> TreeDisplay { - match self { - Some(value) => value.show(), - None => TreeDisplay::label("None"), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test() { - let node = TreeDisplay::label("root") - .with(TreeDisplay::label("child1")) - .with(TreeDisplay::label("child2").with(TreeDisplay::label("child3"))); - println!("{}", node); - } -} diff --git a/crates/vulpi-syntax/Cargo.toml b/crates/vulpi-syntax/Cargo.toml deleted file mode 100644 index 6fdf359..0000000 --- a/crates/vulpi-syntax/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "vulpi-syntax" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -vulpi-location = { path = "../vulpi-location" } -vulpi-intern = { path = "../vulpi-intern" } - -vulpi-show = { path = "../vulpi-show" } -vulpi-macros = { path = "../vulpi-macros" } - -im-rc = "15.1.0" diff --git a/crates/vulpi-syntax/src/abstract.rs b/crates/vulpi-syntax/src/abstract.rs deleted file mode 100644 index ce5d423..0000000 --- a/crates/vulpi-syntax/src/abstract.rs +++ /dev/null @@ -1,473 +0,0 @@ -use std::collections::HashSet; - -use vulpi_intern::Symbol; -use vulpi_location::{Span, Spanned}; -use vulpi_macros::Show; - -use vulpi_show::{Show, TreeDisplay}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Qualified { - pub path: Symbol, - pub name: Symbol, -} - -impl Show for Qualified { - fn show(&self) -> TreeDisplay { - TreeDisplay::label("Qualified") - .with(TreeDisplay::label(&self.path.get())) - .with(TreeDisplay::label(&self.name.get())) - } -} - -#[derive(Show)] -pub enum KindType { - Star, - Effect, - Constraint, - Arrow(Kind, Kind), - Error, -} - -pub type Kind = Box>; - -// Types - -#[derive(Show)] -pub struct Effects { - pub effects: Vec, - pub rest: Option, -} - -#[derive(Show)] -pub struct PiType { - pub left: Type, - pub effects: Option, - pub right: Type, -} - -#[derive(Show)] -pub struct TypeApplication { - pub func: Type, - pub args: Vec, -} - -#[derive(Show)] -pub enum TypeBinder { - Implicit(Symbol), - Explicit(Symbol, Kind), -} - -#[derive(Show)] -pub struct TypeForall { - pub params: Vec, - pub body: Type, -} - -#[derive(Show)] -pub enum TypeKind { - Arrow(PiType), - Tuple(Vec), - Application(TypeApplication), - Forall(TypeForall), - TypeVariable(Symbol), - Type(Qualified), - Unit, - - Error, -} - -pub type Type = Box>; - -impl TypeKind { - pub fn free_variables(&self) -> HashSet { - match self { - TypeKind::Arrow(pi) => { - let mut set = pi.left.data.free_variables(); - set.extend(pi.right.data.free_variables()); - - if let Some(effs) = &pi.effects { - for eff in &effs.effects { - set.extend(eff.data.free_variables()); - } - } - - set - } - TypeKind::Tuple(t) => { - let mut set = HashSet::new(); - - for ty in t { - set.extend(ty.data.free_variables()); - } - - set - } - TypeKind::Application(app) => { - let mut set = app.func.data.free_variables(); - - for arg in &app.args { - set.extend(arg.data.free_variables()); - } - - set - } - TypeKind::Forall(f) => { - let mut set = HashSet::new(); - - set.extend(f.body.data.free_variables()); - - for binder in &f.params { - match binder { - TypeBinder::Implicit(p) => set.remove(p), - TypeBinder::Explicit(p, _) => set.remove(p), - }; - } - - set - } - TypeKind::TypeVariable(v) => { - let mut set = HashSet::new(); - set.insert(v.clone()); - set - } - _ => HashSet::new(), - } - } - - pub fn free_effects(&self) -> HashSet { - match self { - TypeKind::Arrow(pi) => { - let mut set = pi.left.data.free_effects(); - set.extend(pi.right.data.free_effects()); - - if let Some(effs) = &pi.effects { - for eff in &effs.effects { - set.extend(eff.data.free_effects()); - } - if let Some(rest) = &effs.rest { - set.extend(rest.data.free_variables()); - } - } - - set - } - TypeKind::Tuple(t) => { - let mut set = HashSet::new(); - - for ty in t { - set.extend(ty.data.free_effects()); - } - - set - } - TypeKind::Application(app) => { - let mut set = app.func.data.free_effects(); - - for arg in &app.args { - set.extend(arg.data.free_effects()); - } - - set - } - TypeKind::Forall(f) => { - let mut set = HashSet::new(); - - set.extend(f.body.data.free_effects()); - - for binder in &f.params { - match binder { - TypeBinder::Implicit(p) => set.remove(p), - TypeBinder::Explicit(p, _) => set.remove(p), - }; - } - - set - } - _ => HashSet::new(), - } - } -} - -// Literal - -#[derive(Show)] -pub enum LiteralKind { - String(Symbol), - Integer(Symbol), - Float(Symbol), - Char(Symbol), - Unit, -} - -pub type Literal = Box>; - -// Statements - -#[derive(Show)] -pub struct LetStatement { - pub pattern: Pattern, - pub expr: Expr, -} - -#[derive(Show)] -pub enum StatementKind { - Let(LetStatement), - Expr(Expr), - Error, -} - -pub type Statement = Spanned; - -#[derive(Show)] -pub struct Block { - pub statements: Vec, -} - -// Patterns - -#[derive(Show)] -pub struct PatAscription { - pub pat: Pattern, - pub typ: Type, -} - -#[derive(Show)] -pub struct PatOr { - pub left: Pattern, - pub right: Pattern, -} - -#[derive(Show)] -pub struct PatApplication { - pub func: Qualified, - pub args: Vec, -} - -#[derive(Show)] -pub struct PatEffect { - pub func: Qualified, - pub args: Vec, - pub cont: Option, -} - -#[derive(Show)] -pub enum PatternKind { - Wildcard, - Variable(Symbol), - Literal(Literal), - Tuple(Vec), - Ascription(PatAscription), - Or(PatOr), - Application(PatApplication), - Effect(PatEffect), - - Error, -} - -pub type Pattern = Box>; - -#[derive(Show)] -pub struct LambdaExpr { - pub param: Pattern, - pub body: Expr, -} - -#[derive(Show)] -pub enum AppKind { - Infix, - Normal, -} - -#[derive(Show)] -pub struct ApplicationExpr { - pub app: AppKind, - pub func: Expr, - pub args: Vec, -} - -#[derive(Show)] -pub struct ProjectionExpr { - pub expr: Expr, - pub field: Symbol, -} - -#[derive(Show)] -pub struct PatternArm { - pub patterns: Vec, - pub expr: Expr, - pub guard: Option, -} - -#[derive(Show)] -pub struct WhenExpr { - pub scrutinee: Vec, - pub arms: Vec, -} - -#[derive(Show)] -pub struct AnnotationExpr { - pub expr: Expr, - pub ty: Type, -} - -#[derive(Show)] -pub struct LetExpr { - pub pattern: Pattern, - pub body: Expr, - pub value: Expr, -} - -#[derive(Show)] -pub struct RecordInstance { - pub name: Qualified, - pub fields: Vec<(Span, Symbol, Expr)>, -} - -#[derive(Show)] -pub struct RecordUpdate { - pub expr: Expr, - pub fields: Vec<(Span, Symbol, Expr)>, -} - -#[derive(Show)] -pub struct HandlerExpr { - pub expr: Expr, - pub with: Expr, -} - -#[derive(Show)] -pub struct CasesExpr { - pub arms: Vec, -} - -#[derive(Show)] -pub struct Tuple { - pub exprs: Vec, -} - -#[derive(Show)] -pub enum ExprKind { - Lambda(LambdaExpr), - Application(ApplicationExpr), - - Variable(Symbol), - Constructor(Qualified), - Function(Qualified), - Effect(Qualified), - - Projection(ProjectionExpr), - Let(LetExpr), - When(WhenExpr), - Do(Block), - Literal(Literal), - - Annotation(AnnotationExpr), - RecordInstance(RecordInstance), - RecordUpdate(RecordUpdate), - Handler(HandlerExpr), - Cases(CasesExpr), - Tuple(Tuple), - - Error, -} - -pub type Expr = Box>; - -#[derive(Show)] -pub enum Visibility { - Public, - Private, -} - -#[derive(Show)] -pub struct Binder { - pub pattern: Pattern, - pub ty: Type, -} - -#[derive(Show)] -pub struct LetDecl { - pub visibility: Visibility, - pub name: Qualified, - pub binders: Vec, - pub ret: Option<(Option, Type)>, - pub body: Vec, -} - -#[derive(Show)] -pub struct Constructor { - pub name: Qualified, - pub args: Vec, - pub typ: Option, -} - -#[derive(Show)] -pub struct SumDecl { - pub constructors: Vec, -} - -#[derive(Show)] -pub struct RecordDecl { - pub fields: Vec<(Qualified, Type)>, -} - -#[derive(Show)] -pub enum TypeDef { - Sum(SumDecl), - Record(RecordDecl), - Synonym(Type), - Abstract, -} - -#[derive(Show)] -pub struct TypeDecl { - pub namespace: Symbol, - pub visibility: Visibility, - pub name: Qualified, - pub binders: Vec, - pub def: TypeDef, -} - -#[derive(Show)] -pub struct ModuleDecl { - pub namespace: Symbol, - pub visibility: Visibility, - pub name: Symbol, - pub decls: Option, -} - -#[derive(Show)] -pub struct EffectField { - pub visibility: Visibility, - pub name: Qualified, - pub args: Vec, - pub ty: Type, -} - -#[derive(Show)] -pub struct EffectDecl { - pub namespace: Symbol, - pub visibility: Visibility, - pub name: Qualified, - pub binders: Vec, - pub effects: Vec, -} - -#[derive(Show)] -pub struct ExternalDecl { - pub name: Qualified, - pub namespace: Symbol, - pub visibility: Visibility, - pub ty: Type, - pub ret: Symbol, -} - -#[derive(Show, Default)] -pub struct Program { - pub lets: Vec, - pub types: Vec, - pub modules: Vec, - pub effects: Vec, - pub externals: Vec, -} diff --git a/crates/vulpi-syntax/src/concrete/expr.rs b/crates/vulpi-syntax/src/concrete/expr.rs deleted file mode 100644 index 95e1fab..0000000 --- a/crates/vulpi-syntax/src/concrete/expr.rs +++ /dev/null @@ -1,170 +0,0 @@ -use pattern::Pattern; -use tree::{DoExpr, Literal, Type}; -use vulpi_location::Spanned; -use vulpi_macros::Show; - -use crate::tokens::Token; - -use super::*; - -#[derive(Show)] -pub enum Operator { - Add(Token), - Sub(Token), - Mul(Token), - Div(Token), - Rem(Token), - And(Token), - Or(Token), - Xor(Token), - Not(Token), - Eq(Token), - Neq(Token), - Lt(Token), - Gt(Token), - Le(Token), - Ge(Token), - Shl(Token), - Shr(Token), - Pipe(Token), -} - -#[derive(Show)] -pub struct LambdaExpr { - pub lambda: Token, - pub patterns: Vec>, - pub arrow: Token, - pub expr: Box, -} - -#[derive(Show)] -pub struct ApplicationExpr { - pub func: Box, - pub args: Vec>, -} - -#[derive(Show)] -pub struct ProjectionExpr { - pub expr: Box, - pub dot: Token, - pub field: Lower, -} - -#[derive(Show)] -pub struct BinaryExpr { - pub left: Box, - pub op: Operator, - pub right: Box, -} - -#[derive(Show)] -pub struct IfExpr { - pub if_: Token, - pub cond: Box, - pub then: Token, - pub then_expr: Box, - pub else_: Token, - pub else_expr: Box, -} - -#[derive(Show)] -pub struct PatternArm { - pub patterns: Vec<(Box, Option)>, - pub arrow: Token, - pub expr: Box, - pub guard: Option<(Token, Box)>, -} - -#[derive(Show)] -pub struct WhenExpr { - pub when: Token, - pub scrutinee: Vec<(Box, Option)>, - pub is: Token, - pub arms: Vec, -} - -#[derive(Show)] -pub struct AnnotationExpr { - pub expr: Box, - pub colon: Token, - pub ty: Box, -} - -#[derive(Show)] -pub struct LetExpr { - pub let_: Token, - pub pattern: Box, - pub eq: Token, - pub body: Box, - pub in_: Token, - pub value: Box, -} - -#[derive(Show)] -pub struct RecordField { - pub name: Lower, - pub eq: Token, - pub expr: Box, -} - -#[derive(Show)] -pub struct RecordInstance { - pub name: Path, - pub left_brace: Token, - pub fields: Vec<(RecordField, Option)>, - pub right_brace: Token, -} - -#[derive(Show)] -pub struct RecordUpdate { - pub expr: Box, - pub left_brace: Token, - pub fields: Vec<(RecordField, Option)>, - pub right_brace: Token, -} - -#[derive(Show)] -pub struct HandlerExpr { - pub handle: Token, - pub expr: Box, - pub with: Token, - pub handler: Box, -} - -#[derive(Show)] -pub struct CasesExpr { - pub cases: Token, - pub arms: Vec, -} - -pub type Tuple = Parenthesis>, Option)>>; - -#[derive(Show)] -pub enum ExprKind { - Lambda(LambdaExpr), - Application(ApplicationExpr), - - Variable(Lower), - Constructor(Path), - Function(Path), - - Acessor(ProjectionExpr), - Binary(BinaryExpr), - Let(LetExpr), - If(IfExpr), - When(WhenExpr), - Do(DoExpr), - Literal(Literal), - - Handler(HandlerExpr), - Cases(CasesExpr), - - Annotation(AnnotationExpr), - RecordInstance(RecordInstance), - RecordUpdate(RecordUpdate), - - Parenthesis(Parenthesis<(Box>, Option)>), - Tuple(Tuple), -} - -pub type Expr = Spanned; diff --git a/crates/vulpi-syntax/src/concrete/kind.rs b/crates/vulpi-syntax/src/concrete/kind.rs deleted file mode 100644 index 70cbd86..0000000 --- a/crates/vulpi-syntax/src/concrete/kind.rs +++ /dev/null @@ -1,16 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_macros::Show; - -use crate::tokens::Token; - -use super::{Parenthesis, Upper}; - -#[derive(Show)] -pub enum KindType { - Star(Token), - Variable(Upper), - Arrow(Box, Token, Box), - Parenthesis(Parenthesis>), -} - -pub type Kind = Spanned; diff --git a/crates/vulpi-syntax/src/concrete/literal.rs b/crates/vulpi-syntax/src/concrete/literal.rs deleted file mode 100644 index 086ac44..0000000 --- a/crates/vulpi-syntax/src/concrete/literal.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::tokens::Token; -use vulpi_location::Spanned; -use vulpi_macros::Show; - -#[derive(Show)] -pub enum LiteralKind { - String(Token), - Integer(Token), - Float(Token), - Char(Token), - Unit(Token), -} - -pub type Literal = Spanned; diff --git a/crates/vulpi-syntax/src/concrete/mod.rs b/crates/vulpi-syntax/src/concrete/mod.rs deleted file mode 100644 index 72d3386..0000000 --- a/crates/vulpi-syntax/src/concrete/mod.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! The concrete syntax tree for the language. This is the output of the parser. - -pub mod expr; -pub mod kind; -pub mod literal; -pub mod pattern; -pub mod statements; -pub mod top_level; -pub mod r#type; - -use vulpi_intern::Symbol; -use vulpi_macros::Show; - -/// Module that exposes the entire tree -pub mod tree { - pub use super::expr::*; - pub use super::kind::*; - pub use super::literal::*; - pub use super::pattern::*; - pub use super::r#type::*; - pub use super::statements::*; - pub use super::top_level::*; -} - -use vulpi_location::Span; - -use crate::tokens::Token; - -pub enum Either { - Left(L), - Right(R), -} - -#[derive(Show)] -pub struct Upper(pub Token); - -impl Upper { - pub fn symbol(&self) -> Symbol { - self.0.value.data.clone() - } -} - -#[derive(Show)] -pub struct Lower(pub Token); - -impl Lower { - pub fn symbol(&self) -> Symbol { - self.0.value.data.clone() - } -} - -#[derive(Show)] -pub enum Ident { - Upper(Upper), - Lower(Lower), -} - -#[derive(Show)] -pub struct Path { - pub segments: Vec<(Upper, Token)>, - pub last: T, - pub span: Span, -} - -impl From<&Path> for Vec { - fn from(value: &Path) -> Self { - value - .segments - .iter() - .map(|(upper, _)| upper.symbol()) - .chain(std::iter::once(value.last.symbol())) - .collect::>() - } -} - -impl From<&Path> for Vec { - fn from(value: &Path) -> Self { - value - .segments - .iter() - .map(|(upper, _)| upper.symbol()) - .chain(std::iter::once(value.last.symbol())) - .collect::>() - } -} - -impl Path { - pub fn diferentiate(self) -> Either, Path> { - let Path { - segments, - last, - span, - } = self; - - let segments = segments - .into_iter() - .map(|(upper, dot)| (upper, dot)) - .collect(); - - match last { - Ident::Upper(upper) => Either::Left(Path { - segments, - last: upper, - span, - }), - Ident::Lower(lower) => Either::Right(Path { - segments, - last: lower, - span, - }), - } - } -} - -#[derive(Show)] -pub struct Parenthesis { - pub left: Token, - pub data: T, - pub right: Token, -} - -impl Parenthesis { - pub fn map(self, f: impl FnOnce(T) -> U) -> Parenthesis { - let Parenthesis { left, data, right } = self; - - Parenthesis { - left, - data: f(data), - right, - } - } -} diff --git a/crates/vulpi-syntax/src/concrete/pattern.rs b/crates/vulpi-syntax/src/concrete/pattern.rs deleted file mode 100644 index 1cc1f14..0000000 --- a/crates/vulpi-syntax/src/concrete/pattern.rs +++ /dev/null @@ -1,51 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_macros::Show; - -use crate::tokens::Token; - -use super::{literal::Literal, r#type::Type, Lower, Parenthesis, Path, Upper}; - -#[derive(Show)] -pub struct PatAscription { - pub left: Box, - pub colon: Token, - pub right: Box, -} - -#[derive(Show)] -pub struct PatOr { - pub left: Box, - pub pipe: Token, - pub right: Box, -} - -#[derive(Show)] -pub struct PatApplication { - pub func: Path, - pub args: Vec>, -} - -#[derive(Show)] -pub struct PatEffectApp { - pub left_brace: Token, - pub func: Path, - pub args: Vec>, - pub right_brace: Token, - pub arrow: Option<(Token, Lower)>, -} - -#[derive(Show)] -pub enum PatternKind { - Wildcard(Token), - Constructor(Path), - Variable(Lower), - Literal(Literal), - Annotation(PatAscription), - Tuple(Vec<(Pattern, Option)>), - Or(PatOr), - Application(PatApplication), - EffectApp(PatEffectApp), - Parenthesis(Parenthesis>), -} - -pub type Pattern = Spanned; diff --git a/crates/vulpi-syntax/src/concrete/statements.rs b/crates/vulpi-syntax/src/concrete/statements.rs deleted file mode 100644 index acdd5a3..0000000 --- a/crates/vulpi-syntax/src/concrete/statements.rs +++ /dev/null @@ -1,34 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_macros::Show; - -use crate::tokens::Token; - -use super::{expr::Expr, tree::Pattern}; - -#[derive(Show)] -pub struct LetSttm { - pub let_: Token, - pub pattern: Box, - pub eq: Token, - pub expr: Box, -} - -#[derive(Show)] -pub enum StatementKind { - Let(LetSttm), - Expr(Box), - Error(Vec), -} - -pub type Statement = Spanned; - -#[derive(Show)] -pub struct Block { - pub statements: Vec, -} - -#[derive(Show)] -pub struct DoExpr { - pub do_: Token, - pub block: Block, -} diff --git a/crates/vulpi-syntax/src/concrete/top_level.rs b/crates/vulpi-syntax/src/concrete/top_level.rs deleted file mode 100644 index fd87407..0000000 --- a/crates/vulpi-syntax/src/concrete/top_level.rs +++ /dev/null @@ -1,247 +0,0 @@ -use vulpi_macros::Show; - -use crate::tokens::Token; - -#[derive(Show, Clone)] -pub enum Visibility { - Public(Token), - Private, -} - -use super::{ - expr::{Expr, PatternArm}, - kind::Kind, - r#type::{Effects, Type}, - tree::Pattern, - Lower, Parenthesis, Path, Upper, -}; - -#[derive(Show)] -pub struct Binder { - pub left_paren: Token, - pub pattern: Box, - pub colon: Token, - pub typ: Box, - pub right_paren: Token, -} - -#[derive(Show)] -pub struct LetCase { - pub pipe: Token, - pub arm: PatternArm, -} - -#[derive(Show)] -pub enum LetMode { - Body(Token, Box), - Cases(Vec), -} - -#[derive(Show)] -pub struct LetDecl { - pub visibility: Visibility, - pub let_: Token, - pub name: Lower, - pub binders: Vec, - pub ret: Option<(Token, Option, Box)>, - pub body: LetMode, -} - -#[derive(Show)] -pub struct Constructor { - pub pipe: Token, - pub name: Upper, - pub args: Vec>, - pub typ: Option<(Token, Box)>, -} - -#[derive(Show)] -pub struct SumDecl { - pub constructors: Vec, -} - -#[derive(Show)] -pub struct Field { - pub visibility: Visibility, - pub name: Lower, - pub colon: Token, - pub ty: Box, -} - -#[derive(Show)] -pub struct RecordDecl { - pub left_brace: Token, - pub fields: Vec<(Field, Option)>, - pub right_brace: Token, -} - -#[derive(Show)] -pub struct ExplicitTypeBinder { - pub name: Lower, - pub colon: Token, - pub kind: Box, -} - -#[derive(Show)] -pub enum TypeBinder { - Implicit(Lower), - Explicit(Parenthesis), -} - -#[derive(Show)] -pub enum TypeDef { - Sum(SumDecl), - Record(RecordDecl), - Synonym(Box), -} - -#[derive(Show)] -pub struct TypeDecl { - pub visibility: Visibility, - pub type_: Token, - pub name: Upper, - pub binders: Vec, - pub def: Option<(Token, TypeDef)>, -} - -#[derive(Show)] -pub struct UseAlias { - pub as_: Token, - pub alias: Upper, -} - -#[derive(Show)] -pub struct UseDecl { - pub visibility: Visibility, - pub use_: Token, - pub path: Path, - pub alias: Option, -} - -#[derive(Show)] -pub struct ModuleInline { - pub where_: Token, - pub top_levels: Vec, -} - -impl ModuleInline { - pub fn modules(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match &top_level { - TopLevel::Module(module) => Some(&**module), - _ => None, - }) - } - - pub fn uses(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match &top_level { - TopLevel::Use(use_) => Some(&**use_), - _ => None, - }) - } -} - -#[derive(Show)] -pub struct ModuleDecl { - pub visibility: Visibility, - pub mod_: Token, - pub name: Upper, - pub part: Option, -} - -#[derive(Show)] -pub struct EffectField { - pub visibility: Visibility, - pub name: Lower, - pub args: Vec>, - pub colon: Token, - pub ret: Box, -} - -#[derive(Show)] -pub struct EffectDecl { - pub visibility: Visibility, - pub effect: Token, - pub name: Upper, - pub binders: Vec, - pub where_: Option, - pub fields: Vec, -} - -#[derive(Show)] -pub struct ExternalDecl { - pub visibility: Visibility, - pub external: Token, - pub name: Lower, - pub colon: Token, - pub typ: Box, - pub equal: Token, - pub str: Token, -} - -#[derive(Show)] -pub enum TopLevel { - Let(Box), - Type(Box), - Use(Box), - Module(Box), - Effect(Box), - Error(Vec), - External(Box), -} - -#[derive(Show)] -pub struct Program { - pub top_levels: Vec, - pub eof: Token, -} - -impl Program { - pub fn modules(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match top_level { - TopLevel::Module(module) => Some(&**module), - _ => None, - }) - } - - pub fn uses(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match top_level { - TopLevel::Use(use_) => Some(&**use_), - _ => None, - }) - } - - pub fn types(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match top_level { - TopLevel::Type(type_) => Some(&**type_), - _ => None, - }) - } - - pub fn lets(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match top_level { - TopLevel::Let(let_) => Some(&**let_), - _ => None, - }) - } - - pub fn effects(&self) -> impl Iterator { - self.top_levels - .iter() - .filter_map(|top_level| match top_level { - TopLevel::Effect(effect) => Some(&**effect), - _ => None, - }) - } -} diff --git a/crates/vulpi-syntax/src/concrete/type.rs b/crates/vulpi-syntax/src/concrete/type.rs deleted file mode 100644 index 8613e8b..0000000 --- a/crates/vulpi-syntax/src/concrete/type.rs +++ /dev/null @@ -1,57 +0,0 @@ -use vulpi_location::Spanned; -use vulpi_macros::Show; - -use crate::concrete::Lower; -use crate::tokens::Token; - -use super::{top_level::TypeBinder, Parenthesis, Path, Upper}; - -#[derive(Show)] - -pub enum Effect { - Application(Path, Vec>), - Variable(Lower), -} - -#[derive(Show)] -pub struct Effects { - pub left_brace: Token, - pub effects: Vec<(Spanned, Option)>, - pub right_brace: Token, -} - -#[derive(Show)] -pub struct TypeArrow { - pub left: Box, - pub arrow: Token, - pub effects: Option, - pub right: Box, -} - -#[derive(Show)] -pub struct TypeApplication { - pub func: Box, - pub args: Vec>, -} - -#[derive(Show)] -pub struct TypeForall { - pub forall: Token, - pub params: Vec, - pub dot: Token, - pub body: Box, -} - -#[derive(Show)] -pub enum TypeKind { - Parenthesis(Parenthesis<(Box, Option)>), - Tuple(Parenthesis, Option)>>), - Type(Path), - TypeVariable(Lower), - Arrow(TypeArrow), - Application(TypeApplication), - Forall(TypeForall), - Unit(Token), -} - -pub type Type = Spanned; diff --git a/crates/vulpi-syntax/src/elaborated.rs b/crates/vulpi-syntax/src/elaborated.rs deleted file mode 100644 index d40563d..0000000 --- a/crates/vulpi-syntax/src/elaborated.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::collections::{HashMap, HashSet}; - -use vulpi_intern::Symbol; -use vulpi_macros::Show; - -use crate::r#abstract::Qualified; - -#[derive(Show, PartialEq, Eq, Hash, Clone, Debug)] -pub enum LiteralKind { - String(Symbol), - Integer(Symbol), - Float(Symbol), - Char(Symbol), - Unit, -} - -pub type Literal = Box; - -#[derive(Show)] -pub struct LetStatement { - pub pattern: Pattern, - pub expr: Expr, -} - -#[derive(Show)] -pub enum StatementKind { - Let(LetStatement), - Expr(Expr), - Error, -} - -pub type Statement = StatementKind; - -pub type Block = Vec>; - -#[derive(Show, Clone)] -pub struct PatOr { - pub left: Pattern, - pub right: Pattern, -} - -#[derive(Show, Clone, Debug)] -pub struct PatApplication { - pub func: Qualified, - pub args: Vec, -} - -#[derive(Show)] -pub struct PatEffect { - pub func: Qualified, - pub args: Vec, - pub cont: Option, -} - -pub enum PatEffectKind { - Effect(PatEffect), - Variable(Symbol), - Wildcard, - Error, -} - -#[derive(Show, Clone, Debug)] -pub enum PatternKind { - Wildcard, - Variable(Symbol), - Literal(Literal), - Application(PatApplication), - Tuple(Vec), - - Error, -} - -pub type Pattern = Box; - -#[derive(Show)] -pub struct LambdaExpr { - pub param: Pattern, - pub body: Expr, -} - -#[derive(Show)] -pub enum AppKind { - Infix, - Normal, -} - -#[derive(Show)] -pub struct ApplicationExpr { - pub typ: T, - pub func: Expr, - pub args: Vec>, -} - -#[derive(Show)] -pub struct ProjectionExpr { - pub field: Qualified, - pub expr: Expr, -} - -#[derive(Show)] -pub struct PatternArm { - pub patterns: Vec, - pub expr: Expr, - pub guard: Option>, -} - -#[derive(Show)] -pub struct WhenExpr { - pub scrutinee: Vec>, - pub arms: Vec>, -} - -#[derive(Show)] -pub struct LetExpr { - pub pattern: Pattern, - pub body: Expr, - pub value: Expr, -} - -#[derive(Show)] -pub struct RecordInstance { - pub name: Qualified, - pub fields: Vec<(Symbol, Expr)>, -} - -#[derive(Show)] -pub struct RecordUpdate { - pub expr: Expr, - pub fields: Vec<(Symbol, Expr)>, -} - -#[derive(Show)] -pub struct HandlerExpr { - pub expr: Expr, - pub with: Expr, -} - -#[derive(Show)] -pub struct CasesExpr { - pub arms: Vec>, -} - -#[derive(Show)] -pub struct Tuple { - pub exprs: Vec>, -} - -#[derive(Show)] -pub enum ExprKind { - Lambda(LambdaExpr), - Application(ApplicationExpr), - - Variable(Symbol), - Constructor(Qualified, Qualified), - Function(Qualified, T), - Effect(Qualified, Qualified), - - Projection(ProjectionExpr), - Let(LetExpr), - When(WhenExpr), - Do(Block), - Literal(Literal), - - RecordInstance(RecordInstance), - RecordUpdate(RecordUpdate), - Handler(HandlerExpr), - Cases(CasesExpr), - Tuple(Tuple), - - Error, -} - -pub type Expr = Box>; - -#[derive(Show)] -pub struct LetDecl { - pub binders: Vec<(Pattern, T)>, - pub effects: HashSet, - pub body: Vec>, -} - -#[derive(Show)] -pub enum TypeDecl { - Abstract, - Enum(Vec<(Qualified, usize)>), - Record(Vec), -} - -#[derive(Show)] -pub struct ExternalDecl { - pub typ: T, - pub binding: Symbol, -} - -#[derive(Show)] -pub struct Program { - pub lets: HashMap>, - pub types: HashMap, - pub effects: HashMap>, - pub externals: HashMap>, -} - -impl Default for Program { - fn default() -> Self { - Self { - lets: HashMap::new(), - types: HashMap::new(), - effects: HashMap::new(), - externals: HashMap::new(), - } - } -} diff --git a/crates/vulpi-syntax/src/lib.rs b/crates/vulpi-syntax/src/lib.rs deleted file mode 100644 index 7c1f1ac..0000000 --- a/crates/vulpi-syntax/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod r#abstract; -pub mod concrete; -pub mod elaborated; -pub mod tokens; diff --git a/crates/vulpi-syntax/src/tokens.rs b/crates/vulpi-syntax/src/tokens.rs deleted file mode 100644 index c18b787..0000000 --- a/crates/vulpi-syntax/src/tokens.rs +++ /dev/null @@ -1,204 +0,0 @@ -//! This module declares a bunch of tokens that are units of meaning in the language. There are a -//! bunch of them that are virtual token. - -use std::fmt::Debug; - -use vulpi_intern::Symbol; -use vulpi_location::Spanned; -use vulpi_show::{Show, TreeDisplay}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TokenData { - Let, // 'let' keyword - When, // 'when' keyword - Is, // 'is' keyword - With, // 'with' keyword - If, // 'if' keyword - Else, // 'else' keyword - Then, // 'then' keyword - Use, // 'use' keyword - As, // 'as' keyword - Type, // 'type' keyword - Pub, // 'pub' keyword - Do, // 'do' keyword - In, // 'in' keyword - Forall, // 'forall' keyword - Where, // 'where' keyword - Mod, // 'mod' keyword - Handle, // 'handle' keyword - Cases, // 'request' keyword - Effect, // 'effect' keyword - External, // 'external' keyword - - String, // String literal - Int, // Integer literal - Float, // Float Literal - Char, // Char literal - - LBrace, // '{' - RBrace, // '}' - LPar, // '(' - RPar, // ')' - LBracket, // '[' - RBracket, // ']' - LeftArrow, // '<-' - RightArrow, // '->' - FatArrow, // '=>' - Unit, - - LowerIdent, // Identifier - UpperIdent, // Identifier - Wildcard, - - Colon, // ':' - Semicolon, // ';' - Comma, // ',' - Dot, // '.' - Exclamation, // '!' - Equal, // '=' - Bar, // '|' - PipeRight, // '|>' - - Plus, // '+' - Minus, // '-' - Star, // '*' - Slash, // '/' - BackSlash, // '\' - Percent, // '%' - Caret, // '^' - Ampersand, // '&' - Tilde, // '~' - - Greater, // '>' - Less, // '<' - GreaterEqual, // '>=' - LessEqual, // '<=' - NotEqual, // '!=' - DoubleEqual, // '==' - - And, // '&&' - Or, // '||' - - Begin, // Virtual token for beginning of a block - End, // Virtual token for end of a block - Sep, // Virtual token for a semicolon - - Error, - Eof, -} - -#[derive(Debug, Clone)] -pub struct Comment { - pub whitespace: Spanned, - pub comment: Spanned, -} - -#[derive(Clone)] -pub struct Token { - pub comments: Vec, - pub whitespace: Spanned, - pub kind: TokenData, - pub value: Spanned, -} - -impl Show for Token { - fn show(&self) -> vulpi_show::TreeDisplay { - TreeDisplay::label("Token").with(TreeDisplay::label(&self.to_string())) - } -} - -impl Token { - pub fn is(&self, kind: TokenData) -> bool { - self.kind == kind - } - - pub fn data(&self) -> String { - self.value.data.get() - } - - pub fn symbol(&self) -> Symbol { - self.value.data.clone() - } -} - -impl Debug for Token { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("Token").field(&self.kind).finish() - } -} - -impl ToString for Token { - fn to_string(&self) -> String { - use TokenData::*; - - match self.kind { - String => format!("\"{}\"", self.value.data.get()), - Int => format!("int({})", self.value.data.get()), - Float => format!("float({})", self.value.data.get()), - LowerIdent => format!("lower {}", self.value.data.get()), - UpperIdent => format!("upper {}", self.value.data.get()), - Colon => ":".to_string(), - Semicolon => ";".to_string(), - Comma => ",".to_string(), - Dot => ".".to_string(), - Exclamation => "!".to_string(), - Equal => "=".to_string(), - Bar => "|".to_string(), - Plus => "+".to_string(), - Minus => "-".to_string(), - Star => "*".to_string(), - Slash => "/".to_string(), - Percent => "%".to_string(), - Caret => "^".to_string(), - Ampersand => "&".to_string(), - Tilde => "~".to_string(), - Greater => ">".to_string(), - Less => "<".to_string(), - GreaterEqual => ">=".to_string(), - LessEqual => "<=".to_string(), - NotEqual => "!=".to_string(), - DoubleEqual => "==".to_string(), - And => "&&".to_string(), - Or => "||".to_string(), - Begin => "{{".to_string(), - End => "}}".to_string(), - Sep => ";".to_string(), - Error => "error".to_string(), - Eof => "eof".to_string(), - Let => "let".to_string(), - When => "when".to_string(), - Is => "is".to_string(), - With => "with".to_string(), - If => "if".to_string(), - Else => "else".to_string(), - Then => "then".to_string(), - Use => "use".to_string(), - As => "as".to_string(), - Type => "type".to_string(), - Pub => "pub".to_string(), - Do => "do".to_string(), - Where => "where".to_string(), - Forall => "forall".to_string(), - In => "in".to_string(), - LBrace => "{{".to_string(), - RBrace => "}}".to_string(), - LPar => "(".to_string(), - RPar => ")".to_string(), - LBracket => "[".to_string(), - RBracket => "]".to_string(), - LeftArrow => "<-".to_string(), - RightArrow => "->".to_string(), - FatArrow => "=>".to_string(), - BackSlash => "\\".to_string(), - PipeRight => "|>".to_string(), - Char => format!("char('{}')", self.value.data.get()), - Unit => "()".to_string(), - Wildcard => "_".to_string(), - Mod => "mod".to_string(), - Handle => "handle".to_string(), - Cases => "cases".to_string(), - Effect => "effect".to_string(), - External => "external".to_string(), - } - } -} diff --git a/crates/vulpi-tests/Cargo.toml b/crates/vulpi-tests/Cargo.toml deleted file mode 100644 index eededf8..0000000 --- a/crates/vulpi-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "vulpi-tests" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - - -vulpi-lexer = { path = "../vulpi-lexer" } -vulpi-location = { path = "../vulpi-location" } -vulpi-parser = { path = "../vulpi-parser" } -vulpi-report = { path = "../vulpi-report" } -vulpi-show = { path = "../vulpi-show" } -vulpi-vfs = { path = "../vulpi-vfs" } -vulpi-resolver = { path = "../vulpi-resolver" } -vulpi-typer = { path = "../vulpi-typer" } diff --git a/crates/vulpi-tests/src/lib.rs b/crates/vulpi-tests/src/lib.rs deleted file mode 100644 index 09b0800..0000000 --- a/crates/vulpi-tests/src/lib.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! A tiny test runner for Vulpi based on the `atiny-tests` crate for the Atiny language. - -#![feature(path_file_prefix)] -#![feature(test)] - -extern crate test; - -use std::fs::{self, read_to_string}; -use std::path::PathBuf; - -use test::{TestDesc, TestDescAndFn, TestName}; - -const EXTENSION: &str = "vp"; - -pub mod util; - -/// A bunch of golden-tests that are run by the test runner. The test runner will run each test -/// that is inside the directory described inside the entry. -pub struct Test { - pub directory: &'static str, - pub run: fn(file_name: PathBuf) -> String, -} - -/// The main runner that receives tests and then runs them. -pub fn test_runner(tests: &[&Test]) { - let Some(opts) = get_test_opts() else { return; }; - - let mut rendered = Vec::new(); - - for test in tests { - let directory = std::fs::read_dir(test.directory).unwrap(); - - for file in directory.flatten() { - let (file_name, typ) = util::split_name(&file); - - if typ != EXTENSION { - continue; - } - - if file.file_type().unwrap().is_file() { - rendered.push(create_test_description(file_name, file, test.run)); - } - } - } - - match test::run_tests_console(&opts, rendered) { - Ok(true) => { - println!(); - } - Ok(false) => panic!("some tests failed"), - Err(e) => panic!("io error when running tests: {:?}", e), - } -} - -fn create_test_description( - file_name: String, - file: fs::DirEntry, - function: fn(PathBuf) -> String, -) -> TestDescAndFn { - TestDescAndFn { - desc: TestDesc { - name: TestName::DynTestName(file_name.clone()), - ignore: false, - should_panic: test::ShouldPanic::No, - ignore_message: None, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - compile_fail: false, - no_run: false, - test_type: test::TestType::UnitTest, - }, - testfn: test::TestFn::DynTestFn(Box::new(move || { - println!("testing '{}'", file_name); - - let path = file.path(); - - let expect_path = path.with_extension("expect"); - let result = function(path.with_extension(EXTENSION)); - - if let Ok(expects) = read_to_string(expect_path.clone()) { - if expects.eq(&result) { - Ok(()) - } else { - println!("Expected:\n\n{}\n\ngot:\n\n{}", expects, result); - Err("Mismatch".to_string()) - } - } else { - fs::write(expect_path, result).map_err(|err| err.to_string()) - } - })), - } -} - -fn get_test_opts() -> Option { - let args = std::env::args().collect::>(); - let parsed = test::test::parse_opts(&args); - match parsed { - Some(Ok(o)) => Some(o), - Some(Err(msg)) => panic!("{:?}", msg), - None => None, - } -} - -#[macro_export] -macro_rules! test { - ($directory:expr, $code:expr) => { - #[test_case] - const TEST: vulpi_tests::Test = vulpi_tests::Test { - directory: concat!(env!("CARGO_MANIFEST_DIR"), $directory), - run: $code, - }; - }; -} diff --git a/crates/vulpi-tests/src/util.rs b/crates/vulpi-tests/src/util.rs deleted file mode 100644 index 7fbc76b..0000000 --- a/crates/vulpi-tests/src/util.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::fs::DirEntry; - -/// Splits a dir entry into a name and it's extension. -pub fn split_name(file: &DirEntry) -> (String, String) { - let path = file.path(); - ( - path.file_prefix().unwrap().to_string_lossy().to_string(), - path.extension().unwrap().to_string_lossy().to_string(), - ) -} diff --git a/crates/vulpi-tests/suite/abstract.expect b/crates/vulpi-tests/suite/abstract.expect deleted file mode 100644 index 82114fd..0000000 --- a/crates/vulpi-tests/suite/abstract.expect +++ /dev/null @@ -1,127 +0,0 @@ -└Module - └decls - └Vec - ├Module - │ └ModuleDecl - │ ├namespace - │ │ └Symbol: Ata - │ ├visibility - │ │ └Public - │ ├name - │ │ └Symbol: Ata - │ └decls - │ └Vec - │ ├Type - │ │ └TypeDecl - │ │ ├namespace - │ │ │ └Symbol: Ata.A - │ │ ├visibility - │ │ │ └Public - │ │ ├name - │ │ │ └Qualified - │ │ │ ├Ata - │ │ │ └A - │ │ ├binders - │ │ │ └Vec - │ │ └def - │ │ └Abstract - │ └Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Ata.B - │ ├visibility - │ │ └Public - │ ├name - │ │ └Qualified - │ │ ├Ata - │ │ └B - │ ├binders - │ │ └Vec - │ └def - │ └Abstract - └Module - └ModuleDecl - ├namespace - │ └Symbol: Beta - ├visibility - │ └Private - ├name - │ └Symbol: Beta - └decls - └Vec - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Beta.C - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├Beta - │ │ └C - │ ├binders - │ │ └Vec - │ └def - │ └Abstract - └Let - └LetDecl - ├visibility - │ └Private - ├name - │ └Symbol: ata - ├binders - │ └Vec - │ ├Binder - │ │ ├pattern - │ │ │ └Spanned - │ │ │ ├106~107 - │ │ │ └Variable - │ │ │ └Symbol: x - │ │ └ty - │ │ └Spanned - │ │ ├109~110 - │ │ └Type - │ │ └Qualified - │ │ ├Ata - │ │ └A - │ └Binder - │ ├pattern - │ │ └Spanned - │ │ ├113~114 - │ │ └Variable - │ │ └Symbol: y - │ └ty - │ └Spanned - │ ├116~117 - │ └Type - │ └Qualified - │ ├Ata - │ └B - ├ret - │ └Tuple - │ ├None - │ └Spanned - │ ├121~122 - │ └Type - │ └Qualified - │ ├Beta - │ └C - └body - └LetMode - └cases - └Vec - └LetCase - └pattern - └PatternArm - ├patterns - │ └Vec - ├expr - │ └Spanned - │ ├125~126 - │ └Literal - │ └Spanned - │ ├125~126 - │ └Integer - │ └Symbol: 2 - └guard - └None diff --git a/crates/vulpi-tests/suite/abstract.vp b/crates/vulpi-tests/suite/abstract.vp deleted file mode 100644 index ec1c85c..0000000 --- a/crates/vulpi-tests/suite/abstract.vp +++ /dev/null @@ -1,9 +0,0 @@ -pub mod Ata where - pub type A - pub type B - -mod Beta where - type C - use Self.Ata - - let ata (x: A) (y: B) : C = 2 \ No newline at end of file diff --git a/crates/vulpi-tests/suite/algebraic.expect b/crates/vulpi-tests/suite/algebraic.expect deleted file mode 100644 index d4c9a7d..0000000 --- a/crates/vulpi-tests/suite/algebraic.expect +++ /dev/null @@ -1,191 +0,0 @@ -└Module - └decls - └Vec - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Result - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └Result - │ ├binders - │ │ └Vec - │ │ ├Implicit - │ │ │ └Symbol: a - │ │ └Implicit - │ │ └Symbol: b - │ └def - │ └Sum - │ └SumDecl - │ └constructors - │ └Vec - │ ├Constructor - │ │ ├name - │ │ │ └Symbol: Ok - │ │ ├args - │ │ │ └Vec - │ │ │ └Spanned - │ │ │ ├27~28 - │ │ │ └TypeVariable - │ │ │ └Symbol: a - │ │ └typ - │ │ └None - │ └Constructor - │ ├name - │ │ └Symbol: Err - │ ├args - │ │ └Vec - │ │ └Spanned - │ │ ├39~40 - │ │ └TypeVariable - │ │ └Symbol: b - │ └typ - │ └None - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: True - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └True - │ ├binders - │ │ └Vec - │ └def - │ └Abstract - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: False - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └False - │ ├binders - │ │ └Vec - │ └def - │ └Abstract - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Is - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └Is - │ ├binders - │ │ └Vec - │ │ └Implicit - │ │ └Symbol: a - │ └def - │ └Sum - │ └SumDecl - │ └constructors - │ └Vec - │ ├Constructor - │ │ ├name - │ │ │ └Symbol: T - │ │ ├args - │ │ │ └Vec - │ │ └typ - │ │ └Spanned - │ │ ├87~94 - │ │ └Application - │ │ └TypeApplication - │ │ ├func - │ │ │ └Spanned - │ │ │ ├87~89 - │ │ │ └Type - │ │ │ └Qualified - │ │ │ ├ - │ │ │ └Is - │ │ └args - │ │ └Vec - │ │ └Spanned - │ │ ├90~94 - │ │ └Type - │ │ └Qualified - │ │ ├ - │ │ └True - │ └Constructor - │ ├name - │ │ └Symbol: F - │ ├args - │ │ └Vec - │ └typ - │ └Spanned - │ ├105~113 - │ └Application - │ └TypeApplication - │ ├func - │ │ └Spanned - │ │ ├105~107 - │ │ └Type - │ │ └Qualified - │ │ ├ - │ │ └Is - │ └args - │ └Vec - │ └Spanned - │ ├108~113 - │ └Type - │ └Qualified - │ ├ - │ └False - └Let - └LetDecl - ├visibility - │ └Private - ├name - │ └Symbol: main - ├binders - │ └Vec - ├ret - │ └Tuple - │ ├None - │ └Spanned - │ ├126~133 - │ └Application - │ └TypeApplication - │ ├func - │ │ └Spanned - │ │ ├126~128 - │ │ └Type - │ │ └Qualified - │ │ ├ - │ │ └Is - │ └args - │ └Vec - │ └Spanned - │ ├129~133 - │ └Type - │ └Qualified - │ ├ - │ └True - └body - └LetMode - └cases - └Vec - └LetCase - └pattern - └PatternArm - ├patterns - │ └Vec - ├expr - │ └Spanned - │ ├136~140 - │ └Constructor - │ └Qualified - │ ├Is - │ └T - └guard - └None diff --git a/crates/vulpi-tests/suite/algebraic.vp b/crates/vulpi-tests/suite/algebraic.vp deleted file mode 100644 index 5945e73..0000000 --- a/crates/vulpi-tests/suite/algebraic.vp +++ /dev/null @@ -1,14 +0,0 @@ -type Result a b = - | Ok a - | Err b - -type True -type False - -type Is a = - | T : Is True - | F : Is False - -let main : Is True = Is.T - - diff --git a/crates/vulpi-tests/suite/effects.expect b/crates/vulpi-tests/suite/effects.expect deleted file mode 100644 index abd8222..0000000 --- a/crates/vulpi-tests/suite/effects.expect +++ /dev/null @@ -1,55 +0,0 @@ -suite/effects.vp:23:3: name not found: Log - - 21 | Log.log "a" - 22 | Log.log "b" - 23 | Log.log "c" - | ^^^^^^^ - 24 | - -suite/effects.vp:22:3: name not found: Log - - 20 | let variosLog : { Log } a = do - 21 | Log.log "a" - 22 | Log.log "b" - | ^^^^^^^ - 23 | Log.log "c" - -suite/effects.vp:21:3: name not found: Log - - 19 | - 20 | let variosLog : { Log } a = do - 21 | Log.log "a" - | ^^^^^^^ - 22 | Log.log "b" - -suite/effects.vp:20:19: name not found: - - 18 | other => other - 19 | - 20 | let variosLog : { Log } a = do - | ^^^ - 21 | Log.log "a" - -suite/effects.vp:26:3: unexpected token 'Sep' - - 24 | - 25 | let main : { IO } a = - 26 | handle variosLog with logToStdout! - | - -suite/effects.vp:14:3: unexpected token 'Sep' - - 12 | - 13 | let logToStdout! (x: Request (Log String) a -> a) : {IO} a = - 14 | cases - | - 15 | { Log.log e } => do - -suite/effects.vp:8:3: unexpected token 'Let' - - 6 | pub effect IO where - 7 | - 8 | let println (a: String) : { IO } () - | ^^^ - 9 | - diff --git a/crates/vulpi-tests/suite/effects.vp b/crates/vulpi-tests/suite/effects.vp deleted file mode 100644 index 7915119..0000000 --- a/crates/vulpi-tests/suite/effects.vp +++ /dev/null @@ -1,29 +0,0 @@ -pub mod Prelude where - pub type String - pub type Request a b - pub type Unit - - pub effect IO where - run : () - - pub let println (a: String) : { IO } () - -use Prelude - -pub effect Log e where - pub log e : () - -let logToStdout! (x: Request (Log String) a -> a) : {IO} a = - cases - { Log.log e -> k } => do - println e - handle k () with logToStdout! - other => other - -let variosLog : { Log } a = do - Log.log "a" - Log.log "b" - Log.log "c" - -let main : { IO } a = - handle variosLog with logToStdout! \ No newline at end of file diff --git a/crates/vulpi-tests/suite/expr.expect b/crates/vulpi-tests/suite/expr.expect deleted file mode 100644 index f1b98c9..0000000 --- a/crates/vulpi-tests/suite/expr.expect +++ /dev/null @@ -1,15 +0,0 @@ -suite/expr.vp:1:24: name not found: Operator - - 1 | let main : Int = 2 + 3 * 4 - | ^ - -suite/expr.vp:1:20: name not found: Operator - - 1 | let main : Int = 2 + 3 * 4 - | ^ - -suite/expr.vp:1:12: name not found: - - 1 | let main : Int = 2 + 3 * 4 - | ^^^ - diff --git a/crates/vulpi-tests/suite/expr.vp b/crates/vulpi-tests/suite/expr.vp deleted file mode 100644 index 8a8155a..0000000 --- a/crates/vulpi-tests/suite/expr.vp +++ /dev/null @@ -1 +0,0 @@ -let main : Int = 2 + 3 * 4 \ No newline at end of file diff --git a/crates/vulpi-tests/suite/expressions.expect b/crates/vulpi-tests/suite/expressions.expect deleted file mode 100644 index 5d12781..0000000 --- a/crates/vulpi-tests/suite/expressions.expect +++ /dev/null @@ -1,171 +0,0 @@ -└Module - └decls - └Vec - ├Module - │ └ModuleDecl - │ ├namespace - │ │ └Symbol: Prelude - │ ├visibility - │ │ └Public - │ ├name - │ │ └Symbol: Prelude - │ └decls - │ └Vec - │ └Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Prelude.Int - │ ├visibility - │ │ └Public - │ ├name - │ │ └Qualified - │ │ ├Prelude - │ │ └Int - │ ├binders - │ │ └Vec - │ └def - │ └Abstract - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Shake - │ ├visibility - │ │ └Public - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └Shake - │ ├binders - │ │ └Vec - │ └def - │ └Sum - │ └SumDecl - │ └constructors - │ └Vec - │ ├Constructor - │ │ ├name - │ │ │ └Symbol: True - │ │ ├args - │ │ │ └Vec - │ │ └typ - │ │ └None - │ └Constructor - │ ├name - │ │ └Symbol: False - │ ├args - │ │ └Vec - │ └typ - │ └None - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Priv - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├ - │ │ └Priv - │ ├binders - │ │ └Vec - │ └def - │ └Sum - │ └SumDecl - │ └constructors - │ └Vec - │ ├Constructor - │ │ ├name - │ │ │ └Symbol: True - │ │ ├args - │ │ │ └Vec - │ │ │ └Spanned - │ │ │ ├105~110 - │ │ │ └Type - │ │ │ └Qualified - │ │ │ ├ - │ │ │ └Shake - │ │ └typ - │ │ └None - │ └Constructor - │ ├name - │ │ └Symbol: False - │ ├args - │ │ └Vec - │ └typ - │ └None - └Module - └ModuleDecl - ├namespace - │ └Symbol: Ata - ├visibility - │ └Public - ├name - │ └Symbol: Ata - └decls - └Vec - ├Type - │ └TypeDecl - │ ├namespace - │ │ └Symbol: Ata.Bool - │ ├visibility - │ │ └Private - │ ├name - │ │ └Qualified - │ │ ├Ata - │ │ └Bool - │ ├binders - │ │ └Vec - │ └def - │ └Sum - │ └SumDecl - │ └constructors - │ └Vec - │ ├Constructor - │ │ ├name - │ │ │ └Symbol: True - │ │ ├args - │ │ │ └Vec - │ │ └typ - │ │ └None - │ └Constructor - │ ├name - │ │ └Symbol: False - │ ├args - │ │ └Vec - │ └typ - │ └None - └Let - └LetDecl - ├visibility - │ └Private - ├name - │ └Symbol: ata - ├binders - │ └Vec - ├ret - │ └Tuple - │ ├None - │ └Spanned - │ ├205~215 - │ └Type - │ └Qualified - │ ├ - │ └Shake - └body - └LetMode - └cases - └Vec - └LetCase - └pattern - └PatternArm - ├patterns - │ └Vec - ├expr - │ └Spanned - │ ├218~227 - │ └Constructor - │ └Qualified - │ ├Ata.Bool - │ └True - └guard - └None diff --git a/crates/vulpi-tests/suite/expressions.vp b/crates/vulpi-tests/suite/expressions.vp deleted file mode 100644 index 9b09024..0000000 --- a/crates/vulpi-tests/suite/expressions.vp +++ /dev/null @@ -1,18 +0,0 @@ -pub mod Prelude where - pub type Int - -pub type Shake = - | True - | False - -type Priv = - | True Shake - | False - -pub mod Ata where - type Bool = - | True - | False - - let ata : Self.Shake = Bool.True - diff --git a/crates/vulpi-tests/suite/handler.expect b/crates/vulpi-tests/suite/handler.expect deleted file mode 100644 index 058938a..0000000 --- a/crates/vulpi-tests/suite/handler.expect +++ /dev/null @@ -1,38 +0,0 @@ -suite/handler.vp:6:22: name not found: - - 4 | a - 5 | b - 6 | { Log.log e } => other - | ^^^^^ - -suite/handler.vp:6:7: name not found: Log - - 4 | a - 5 | b - 6 | { Log.log e } => other - | ^^^^^^^ - -suite/handler.vp:5:11: name not found: - - 3 | { Log.log e } => do - 4 | a - 5 | b - | ^ - 6 | { Log.log e } => other - -suite/handler.vp:4:11: name not found: - - 2 | cases - 3 | { Log.log e } => do - 4 | a - | ^ - 5 | b - -suite/handler.vp:3:7: name not found: Log - - 1 | let logToStdout! = - 2 | cases - 3 | { Log.log e } => do - | ^^^^^^^ - 4 | a - diff --git a/crates/vulpi-tests/suite/handler.vp b/crates/vulpi-tests/suite/handler.vp deleted file mode 100644 index d3bd7e4..0000000 --- a/crates/vulpi-tests/suite/handler.vp +++ /dev/null @@ -1,6 +0,0 @@ -let logToStdout! = - cases - { Log.log e } => do - a - b - { Log.log e } => other diff --git a/crates/vulpi-tests/suite/layout_parsing.expect b/crates/vulpi-tests/suite/layout_parsing.expect deleted file mode 100644 index 8ec3093..0000000 --- a/crates/vulpi-tests/suite/layout_parsing.expect +++ /dev/null @@ -1,30 +0,0 @@ -suite/layout_parsing.vp:9:12: name not found: - - 7 | - 8 | -- Tests if an error causes the layout to collapse - 9 | let test : Int = do - | ^^^ - 10 | ( - -suite/layout_parsing.vp:6:23: name not found: Operator - - 4 | 3 - 5 | - 6 | let add1 (n: Int) = n + 1 - | ^ - 7 | - -suite/layout_parsing.vp:6:14: name not found: - - 4 | 3 - 5 | - 6 | let add1 (n: Int) = n + 1 - | ^^^ - 7 | - -suite/layout_parsing.vp:1:12: name not found: - - 1 | let main : Int = do - | ^^^ - 2 | 1 - diff --git a/crates/vulpi-tests/suite/layout_parsing.vp b/crates/vulpi-tests/suite/layout_parsing.vp deleted file mode 100644 index aa66855..0000000 --- a/crates/vulpi-tests/suite/layout_parsing.vp +++ /dev/null @@ -1,12 +0,0 @@ -let main : Int = do - 1 - 2 - 3 - -let add1 (n: Int) = n + 1 - --- Tests if an error causes the layout to collapse -let test : Int = do - ( - add1 - 2) \ No newline at end of file diff --git a/crates/vulpi-tests/suite/modules.expect b/crates/vulpi-tests/suite/modules.expect deleted file mode 100644 index 4e09bf1..0000000 --- a/crates/vulpi-tests/suite/modules.expect +++ /dev/null @@ -1,28 +0,0 @@ -suite/modules.vp:6:29: private definition - - 4 | | Err b - 5 | - 6 | let main : Result Int Int = MyOwn.Result 2 3 - | ^^^^^^^^^^^^ - -suite/modules.vp:6:23: name not found: - - 4 | | Err b - 5 | - 6 | let main : Result Int Int = MyOwn.Result 2 3 - | ^^^ - -suite/modules.vp:6:19: name not found: - - 4 | | Err b - 5 | - 6 | let main : Result Int Int = MyOwn.Result 2 3 - | ^^^ - -suite/modules.vp:6:12: name not found: - - 4 | | Err b - 5 | - 6 | let main : Result Int Int = MyOwn.Result 2 3 - | ^^^^^^ - diff --git a/crates/vulpi-tests/suite/modules.vp b/crates/vulpi-tests/suite/modules.vp deleted file mode 100644 index 6a64c73..0000000 --- a/crates/vulpi-tests/suite/modules.vp +++ /dev/null @@ -1,6 +0,0 @@ -mod MyOwn where - type Result a b = - | Ok a - | Err b - -let main : Result Int Int = MyOwn.Result 2 3 \ No newline at end of file diff --git a/crates/vulpi-tests/suite/pipe.expect b/crates/vulpi-tests/suite/pipe.expect deleted file mode 100644 index ec59ccf..0000000 --- a/crates/vulpi-tests/suite/pipe.expect +++ /dev/null @@ -1,49 +0,0 @@ -suite/pipe.vp:7:5: name not found: Operator - - 5 | |> inc - 6 | |> inc - 7 | |> inc - | ^^ - -suite/pipe.vp:6:5: name not found: Operator - - 4 | 1 - 5 | |> inc - 6 | |> inc - | ^^ - 7 | |> inc - -suite/pipe.vp:5:5: name not found: Operator - - 3 | let main : Int = - 4 | 1 - 5 | |> inc - | ^^ - 6 | |> inc - -suite/pipe.vp:3:12: name not found: - - 1 | let inc (n: Int) : Int = n + 1 - 2 | - 3 | let main : Int = - | ^^^ - 4 | 1 - -suite/pipe.vp:1:28: name not found: Operator - - 1 | let inc (n: Int) : Int = n + 1 - | ^ - 2 | - -suite/pipe.vp:1:20: name not found: - - 1 | let inc (n: Int) : Int = n + 1 - | ^^^ - 2 | - -suite/pipe.vp:1:13: name not found: - - 1 | let inc (n: Int) : Int = n + 1 - | ^^^ - 2 | - diff --git a/crates/vulpi-tests/suite/pipe.vp b/crates/vulpi-tests/suite/pipe.vp deleted file mode 100644 index b98252f..0000000 --- a/crates/vulpi-tests/suite/pipe.vp +++ /dev/null @@ -1,7 +0,0 @@ -let inc (n: Int) : Int = n + 1 - -let main : Int = - 1 - |> inc - |> inc - |> inc \ No newline at end of file diff --git a/crates/vulpi-tests/suite/records.expect b/crates/vulpi-tests/suite/records.expect deleted file mode 100644 index a4a0863..0000000 --- a/crates/vulpi-tests/suite/records.expect +++ /dev/null @@ -1,15 +0,0 @@ -suite/records.vp:3:14: name not found: - - 1 | type User (t: * -> *) = { - 2 | name : String, - 3 | data : t Int - | ^^^ - 4 | } - -suite/records.vp:2:12: name not found: - - 1 | type User (t: * -> *) = { - 2 | name : String, - | ^^^^^^ - 3 | data : t Int - diff --git a/crates/vulpi-tests/suite/records.vp b/crates/vulpi-tests/suite/records.vp deleted file mode 100644 index 888d088..0000000 --- a/crates/vulpi-tests/suite/records.vp +++ /dev/null @@ -1,9 +0,0 @@ -type User (t: * -> *) = { - name : String, - data : t Int -} - -let main = do - let user = User { name = "ata", data = 2 } - - let updated = user { name = "lel" } \ No newline at end of file diff --git a/crates/vulpi-tests/suite/tuple.expect b/crates/vulpi-tests/suite/tuple.expect deleted file mode 100644 index 4b77af4..0000000 --- a/crates/vulpi-tests/suite/tuple.expect +++ /dev/null @@ -1,10 +0,0 @@ -suite/tuple.vp:1:22: name not found: - - 1 | let tuple : (String, Int) = ("Ata", 2) - | ^^^ - -suite/tuple.vp:1:14: name not found: - - 1 | let tuple : (String, Int) = ("Ata", 2) - | ^^^^^^ - diff --git a/crates/vulpi-tests/suite/tuple.vp b/crates/vulpi-tests/suite/tuple.vp deleted file mode 100644 index a67cc90..0000000 --- a/crates/vulpi-tests/suite/tuple.vp +++ /dev/null @@ -1 +0,0 @@ -let tuple : (String, Int) = ("Ata", 2) diff --git a/crates/vulpi-tests/suite/unicode_escape.expect b/crates/vulpi-tests/suite/unicode_escape.expect deleted file mode 100644 index f98a66c..0000000 --- a/crates/vulpi-tests/suite/unicode_escape.expect +++ /dev/null @@ -1,5 +0,0 @@ -suite/unicode_escape.vp:1:12: name not found: - - 1 | let main : String = "ata\n\"teste ザ ワールド" - | ^^^^^^ - diff --git a/crates/vulpi-tests/suite/unicode_escape.vp b/crates/vulpi-tests/suite/unicode_escape.vp deleted file mode 100644 index d03ace2..0000000 --- a/crates/vulpi-tests/suite/unicode_escape.vp +++ /dev/null @@ -1 +0,0 @@ -let main : String = "ata\n\"teste ザ ワールド" \ No newline at end of file diff --git a/crates/vulpi-tests/suite/when.expect b/crates/vulpi-tests/suite/when.expect deleted file mode 100644 index 38d40f4..0000000 --- a/crates/vulpi-tests/suite/when.expect +++ /dev/null @@ -1,22 +0,0 @@ -suite/when.vp:3:18: name not found: - - 1 | let ok : Int = - 2 | when 2 is - 3 | 2 | 3 if a == 2 => 1 - | ^ - 4 | 1 => 0 - -suite/when.vp:3:20: name not found: Operator - - 1 | let ok : Int = - 2 | when 2 is - 3 | 2 | 3 if a == 2 => 1 - | ^^ - 4 | 1 => 0 - -suite/when.vp:1:10: name not found: - - 1 | let ok : Int = - | ^^^ - 2 | when 2 is - diff --git a/crates/vulpi-tests/suite/when.vp b/crates/vulpi-tests/suite/when.vp deleted file mode 100644 index 386aea1..0000000 --- a/crates/vulpi-tests/suite/when.vp +++ /dev/null @@ -1,6 +0,0 @@ -let ok : Int = - when 2 is - 2 | 3 if a == 2 => 1 - 1 => 0 - _ => 2 - diff --git a/crates/vulpi-tests/tests/suite.rs b/crates/vulpi-tests/tests/suite.rs deleted file mode 100644 index 35d9ed2..0000000 --- a/crates/vulpi-tests/tests/suite.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![feature(custom_test_frameworks)] -#![test_runner(vulpi_tests::test_runner)] - -use std::collections::HashMap; - -use vulpi_lexer::Lexer; -use vulpi_parser::Parser; - -use vulpi_report::hash::HashReporter; -use vulpi_report::renderer::{classic::Classic, Reader, Renderer}; -use vulpi_report::Report; - -use vulpi_resolver::module_tree::Tree; -use vulpi_resolver::namespace::Namespaces; -use vulpi_resolver::Resolve; -use vulpi_resolver::{declare::Declare, namespace::Namespace}; -use vulpi_resolver::{declare::ImportResolve, scopes::Symbol}; - -use vulpi_show::Show; -use vulpi_tests::test; - -use vulpi_vfs::{real::RealFileSystem, FileSystem}; - -test!("/suite", |file_name| { - let reporter = Report::new(HashReporter::new()); - let cwd = std::env::current_dir().unwrap(); - - let mut vfs = RealFileSystem::new(cwd.clone()); - let id = vfs.load(file_name).unwrap(); - let source = vfs.read(id).unwrap(); - - let lexer = Lexer::new(source, id, reporter.clone()); - - let mut parser = Parser::new(lexer, id, reporter.clone()); - let program = parser.program(); - - let tree = Tree::new(Symbol::intern("")); - let mut namespaces = HashMap::new(); - - namespaces.insert(Symbol::intern(""), Namespace::new(Symbol::intern(""))); - - let mut namespaces = Namespaces { tree, namespaces }; - - let mut resolver = vulpi_resolver::Context::new(reporter.clone(), &mut namespaces); - - program.declare(&mut resolver); - program.resolve_imports(&mut resolver); - - // let mut ctx = vulpi_resolver::Context::new(reporter.clone(), namespaces, tree); - // - let program = program.resolve(&mut resolver); - // - // let env = vulpi_typer::env::Env::new(reporter.clone()); - // - // program.declare(env.clone()); - // program.define(env); - // - let report = reporter.all_diagnostics(); - - if !reporter.has_errors() { - program.show().to_string() - } else { - let mut writer = Reader::default(); - let ctx = Classic::new(&vfs, cwd); - - for diagnostic in report.iter().rev() { - diagnostic.render(&ctx, &mut writer).unwrap(); - } - - writer.to_string() - } -}); diff --git a/crates/vulpi-typer/Cargo.toml b/crates/vulpi-typer/Cargo.toml deleted file mode 100644 index b8f8934..0000000 --- a/crates/vulpi-typer/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "vulpi-typer" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -vulpi-intern = { path = "../vulpi-intern" } -vulpi-syntax = { path = "../vulpi-syntax" } -vulpi-location = { path = "../vulpi-location" } -vulpi-report = { path = "../vulpi-report" } -vulpi-show = { path = "../vulpi-show" } -vulpi-macros = { path = "../vulpi-macros" } -im-rc = "15.1.0" diff --git a/crates/vulpi-typer/src/check/expr.rs b/crates/vulpi-typer/src/check/expr.rs deleted file mode 100644 index 026e676..0000000 --- a/crates/vulpi-typer/src/check/expr.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! Checking of expressions - -use vulpi_syntax::{elaborated, r#abstract::Expr, r#abstract::ExprKind, r#abstract::Statement}; - -use crate::{ - errors::TypeErrorKind, - infer::pat::EffectPat, - r#type::{r#virtual, Effect, TypeKind}, - Context, Env, Kind, Real, Type, Virtual, -}; - -use super::Check; -use crate::infer::Infer; - -impl Check for Expr { - type Return = elaborated::Expr>; - - type Context<'a> = (&'a mut Context, &'a Effect, Env); - - fn check( - &self, - ty: crate::Type, - (ctx, ambient, mut env): Self::Context<'_>, - ) -> Self::Return { - env.on(self.span.clone()); - match (&self.data, ty.deref().as_ref()) { - (ExprKind::Do(block), _) => { - let mut stmts = Vec::new(); - - if !block.statements.is_empty() { - for (i, stmt) in block.statements.iter().enumerate() { - let is_last = i == block.statements.len() - 1; - let (elab, new_env) = if is_last { - stmt.check(ty.clone(), (ctx, ambient, env.clone())) - } else { - let (_, new_env, elab) = stmt.infer((ctx, ambient, env.clone())); - (elab, new_env) - }; - - env = new_env; - - stmts.push(elab) - } - } - - Box::new(elaborated::ExprKind::Do(stmts)) - } - (ExprKind::Cases(cases), _) => { - let hole = ctx.hole(&env, Kind::typ()); - let hole_scrutinee = ctx.hole(&env, Kind::typ()); - - let ambient = ctx.lacks(&env, Default::default()); - - let ret_eff = ctx.lacks(&env, Default::default()); - - for case in &cases.arms { - let mut env = env.clone(); - - if case.patterns.len() != 1 { - ctx.report(&env, TypeErrorKind::WrongArity(1, case.patterns.len())); - ctx.subsumes(env, ty, Type::error()); - return Box::new(elaborated::ExprKind::Error); - } - - let mut hashmap = Default::default(); - let effect_pat = &EffectPat(hole_scrutinee.clone(), &case.patterns[0]); - let (pat_ty, _) = effect_pat.infer((ctx, &mut hashmap, &mut env)); - - let label = match pat_ty.deref().as_ref() { - TypeKind::Extend(l, eff, _) => { - ctx.subsumes(env.clone(), eff.clone(), ret_eff.clone()); - l.clone() - } - _ => { - ctx.report(&env, TypeErrorKind::NotEffect); - ctx.subsumes(env, ty, Type::error()); - return Box::new(elaborated::ExprKind::Error); - } - }; - - for binding in hashmap { - env.add_var(binding.0, binding.1); - } - - case.expr.check(hole.clone(), (ctx, &ambient, env.clone())); - - let request = ctx.find_prelude_type("Request", env.clone()); - - let app = Type::::application( - request, - vec![ret_eff.clone(), hole_scrutinee.clone()], - ); - - let fun = Type::::new(TypeKind::Arrow(r#virtual::Pi { - ty: app, - effs: ctx.remove_effect(label, &ambient), - body: hole.clone(), - })); - - ctx.subsumes(env.clone(), fun, ty.clone()); - } - - Box::new(elaborated::ExprKind::Error) - } - (_, TypeKind::Forall(l)) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - self.check( - l.body.apply_local(Some(l.name.clone()), lvl_ty.clone()), - (ctx, ambient, env.add(Some(l.name.clone()), lvl_ty)), - ) - } - _ => { - let (expr_ty, elab_expr) = self.infer((ctx, ambient, env.clone())); - ctx.subsumes(env, expr_ty, ty); - elab_expr - } - } - } -} - -impl Check for Statement { - type Return = (elaborated::Statement>, Env); - - type Context<'a> = (&'a mut Context, &'a Effect, Env); - - fn check(&self, ty: Type, (ctx, ambient, env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - - let (typ, env, elab) = self.infer((ctx, ambient, env)); - - ctx.subsumes(env.clone(), typ, ty); - (elab, env) - } -} diff --git a/crates/vulpi-typer/src/check/mod.rs b/crates/vulpi-typer/src/check/mod.rs deleted file mode 100644 index 6f8ecdd..0000000 --- a/crates/vulpi-typer/src/check/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! This is a check trait that checks if an expression matches a type. - -use crate::{Type, Virtual}; - -pub mod expr; -pub mod pat; - -pub trait Check { - type Return; - type Context<'a>; - - fn check(&self, ty: Type, context: Self::Context<'_>) -> Self::Return; -} diff --git a/crates/vulpi-typer/src/check/pat.rs b/crates/vulpi-typer/src/check/pat.rs deleted file mode 100644 index 0efdaa9..0000000 --- a/crates/vulpi-typer/src/check/pat.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::collections::HashMap; - -use vulpi_intern::Symbol; -use vulpi_syntax::{ - elaborated, r#abstract::Pattern, r#abstract::PatternArm, r#abstract::PatternKind, -}; - -use crate::{ - errors::TypeErrorKind, - infer::pat::EffectPat, - r#type::{eval::Quote, Effect}, - Context, Env, Real, Type, Virtual, -}; - -use super::Check; -use crate::infer::Infer; - -impl Check for PatternArm { - type Return = elaborated::PatternArm>; - - type Context<'a> = (&'a mut Context, Effect, Env); - - fn check( - &self, - mut ty: Type, - (ctx, ambient, mut env): Self::Context<'_>, - ) -> Self::Return { - let mut map = Default::default(); - - let mut elaborated_patterns = Vec::new(); - - for pat in &self.patterns { - env.on(pat.span.clone()); - - if let Some((left, _, right)) = ctx.as_function(&env, ty.clone()) { - let elab = pat.check(left, (ctx, &mut map, env.clone())); - elaborated_patterns.push(elab); - ty = right; - } else { - ctx.report( - &env, - TypeErrorKind::NotAFunction(env.clone(), ty.quote(env.level)), - ); - return elaborated::PatternArm { - patterns: Vec::new(), - guard: None, - expr: self.expr.check(ty, (ctx, &ambient, env.clone())), - }; - } - } - - for binding in map { - env.add_var(binding.0, binding.1); - } - - let elab_expr = self.expr.check(ty, (ctx, &ambient, env.clone())); - - let guard = self - .guard - .as_ref() - .map(|g| g.infer((ctx, &ambient, env.clone()))); - - let elab_guard = if let Some((typ, guard)) = guard { - let bool = ctx.find_prelude_type("Bool", env.clone()); - ctx.subsumes(env.clone(), typ, bool); - Some(guard) - } else { - None - }; - - elaborated::PatternArm { - patterns: elaborated_patterns, - guard: elab_guard, - expr: elab_expr, - } - } -} - -impl Check for Vec { - type Return = Vec>>; - - type Context<'a> = (&'a mut Context, Effect, Env); - - fn check(&self, ty: Type, (ctx, ambient, env): Self::Context<'_>) -> Self::Return { - if self.is_empty() { - todo!() - } else { - let size = self[0].patterns.len(); - - let mut elab_arms = Vec::new(); - let elab_arm = self[0].check(ty.clone(), (ctx, ambient.clone(), env.clone())); - - elab_arms.push(elab_arm); - - for pat in self.iter().skip(1) { - if pat.patterns.len() != size { - ctx.report(&env, TypeErrorKind::WrongArity(pat.patterns.len(), size)); - return vec![]; - } - - let elab_arm = pat.check(ty.clone(), (ctx, ambient.clone(), env.clone())); - elab_arms.push(elab_arm); - } - - elab_arms - } - } -} - -impl Check for Pattern { - type Return = elaborated::Pattern; - - type Context<'a> = (&'a mut Context, &'a mut HashMap>, Env); - - fn check(&self, ty: Type, (ctx, map, env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - match &self.data { - PatternKind::Wildcard => Box::new(elaborated::PatternKind::Wildcard), - PatternKind::Variable(n) => { - map.insert(n.clone(), ty); - - Box::new(elaborated::PatternKind::Variable(n.clone())) - } - _ => { - let (typ, elab_pat) = self.infer((ctx, map, env.clone())); - ctx.subsumes(env, typ, ty); - elab_pat - } - } - } -} - -impl<'b> Check for EffectPat<'b> { - type Return = elaborated::PatEffectKind; - - type Context<'a> = (&'a mut Context, &'a mut HashMap>, Env); - - fn check(&self, ty: Type, context: Self::Context<'_>) -> Self::Return { - let (ctx, map, env) = context; - env.on(self.1.span.clone()); - let (infered, pat) = self.infer((ctx, map, &mut env.clone())); - ctx.subsumes(env, infered, ty); - pat - } -} diff --git a/crates/vulpi-typer/src/context.rs b/crates/vulpi-typer/src/context.rs deleted file mode 100644 index aefb4ab..0000000 --- a/crates/vulpi-typer/src/context.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! This file declares a mutable environment that is useful to keep track of information that does -//! not need to be immutable like the Env. - -use std::collections::HashMap; - -use crate::{ - module::Modules, - r#type::{eval::Eval, r#virtual::Pi, Hole, State}, -}; -use im_rc::HashSet; -use vulpi_intern::Symbol; -use vulpi_report::{Diagnostic, Report}; -use vulpi_syntax::{elaborated, r#abstract::Qualified}; - -use crate::{ - errors::{TypeError, TypeErrorKind}, - r#type::{ - eval::Quote, - r#virtual::Env, - r#virtual::Virtual, - real::{self, Real}, - HoleInner, Level, Type, TypeKind, - }, -}; - -/// A mutable context that is used differently from [Env]. It is used to keep data between every -/// thing inside the type checker. -pub struct Context { - pub counter: usize, - pub reporter: Report, - pub modules: Modules, - pub elaborated: elaborated::Program>, - pub errored: bool, -} - -impl Context { - pub fn new(reporter: Report) -> Self { - Self { - counter: 0, - reporter, - modules: Default::default(), - elaborated: Default::default(), - errored: false, - } - } - - pub fn report(&mut self, env: &Env, kind: TypeErrorKind) { - self.errored = true; - self.reporter.report(Diagnostic::new(TypeError { - span: env.span.borrow().clone(), - kind, - })); - } - - fn inc_counter(&mut self) -> usize { - self.counter += 1; - self.counter - 1 - } - - pub fn find_prelude_type(&mut self, name: &str, env: Env) -> Type { - let path = Symbol::intern("Prelude"); - let name = Symbol::intern(name); - if self.modules.get(&path).types.get(&name).is_some() { - Type::variable(Qualified { path, name }) - } else { - self.report(&env, crate::errors::TypeErrorKind::CannotFind(name)); - Type::error() - } - } - - /// Creates a new name with the prefix `t_` and a unique number. - pub fn new_name(&mut self) -> Symbol { - Symbol::intern(&format!("t_{}", self.inc_counter())) - } - - /// Creates a new hole that is a type that is not yet known - pub fn hole(&mut self, env: &Env, kind: Type) -> Type { - env.hole(kind, self.new_name()) - } - - /// Creates a "lacks" hole that stores effects that should lack. - pub fn lacks(&mut self, env: &Env, hash_set: HashSet) -> Type { - env.lacks(self.new_name(), hash_set) - } - - pub fn as_function( - &mut self, - env: &Env, - typ: Type, - ) -> Option<(Type, Type, Type)> { - match typ.deref().as_ref() { - TypeKind::Arrow(pi) => Some((pi.ty.clone(), pi.effs.clone(), pi.body.clone())), - TypeKind::Error => Some((typ.clone(), Type::new(TypeKind::Empty), typ.clone())), - TypeKind::Forall(_) => { - let typ = self.instantiate(env, &typ); - self.as_function(env, typ) - } - TypeKind::Hole(empty) => { - let hole_inner = empty.0.borrow().clone(); - if let HoleInner::Empty(_, kind, _) = hole_inner { - let hole_a = self.hole(env, kind.clone()); - let hole_b = self.hole(env, kind); - - empty.fill(Type::new(TypeKind::Arrow(Pi { - ty: hole_a.clone(), - effs: Type::new(TypeKind::Empty), - body: hole_b.clone(), - }))); - - Some((hole_a, Type::new(TypeKind::Empty), hole_b)) - } else { - unreachable!() - } - } - _ => None, - } - } - - /// Instantiates a poly type to a monotype. - pub fn instantiate(&mut self, env: &Env, ty: &Type) -> Type { - match ty.deref().as_ref() { - TypeKind::Forall(forall) => { - // Determines if a hole should be lack or not checking if it has effect kind. - let arg = if forall.kind.is_row() { - env.lacks(forall.name.clone(), Default::default()) - } else { - env.hole(forall.kind.clone(), forall.name.clone()) - }; - - let kind = forall.kind.clone(); - - // Applies the body using the hole argument. - forall.body.apply(Some(forall.name.clone()), arg, kind) - } - _ => ty.clone(), - } - } - - pub fn instantiate_with(&mut self, ty: &Type, arg: Type) -> Type { - match ty.deref().as_ref() { - TypeKind::Forall(forall) => { - let kind = forall.kind.clone(); - forall.body.apply(Some(forall.name.clone()), arg, kind) - } - _ => ty.clone(), - } - } - - pub fn instantiate_with_args( - &mut self, - ty: &Type, - args: Vec>, - ) -> Type { - let mut ty = ty.clone(); - for arg in args { - ty = self.instantiate_with(&ty, arg); - } - ty - } - - pub fn instantiate_all(&mut self, env: &Env, ty: &Type) -> Type { - match ty.deref().as_ref() { - TypeKind::Forall(_) => { - let res = self.instantiate(env, ty); - self.instantiate_all(env, &res) - } - _ => ty.clone(), - } - } - - fn accumulate_variables( - env: Env, - level: Level, - ty: Type, - new_vars: &mut HashMap, (Symbol, Level, Type)>, - turn: bool, - ) -> Type { - match ty.as_ref() { - TypeKind::Arrow(p) => { - let ty = - Context::accumulate_variables(env.clone(), level, p.ty.clone(), new_vars, turn); - let effs = Context::accumulate_variables( - env.clone(), - level, - p.effs.clone(), - new_vars, - turn, - ); - let body = - Context::accumulate_variables(env, level, p.body.clone(), new_vars, turn); - Type::new(TypeKind::Arrow(real::Arrow { ty, effs, body })) - } - TypeKind::Forall(forall) => { - let kind = Context::accumulate_variables( - env.clone(), - level, - forall.kind.clone(), - new_vars, - turn, - ); - let body = - Context::accumulate_variables(env, level, forall.body.clone(), new_vars, turn); - Type::new(TypeKind::Forall(real::Forall { - name: forall.name.clone(), - kind, - body, - })) - } - TypeKind::Hole(hole) => { - if new_vars.contains_key(hole) { - return ty.clone(); - } - - let l = Level(level.0 + new_vars.len()); - - let borrow = hole.0.borrow().clone(); - match borrow { - HoleInner::Empty(n, k, _) => { - new_vars.insert(hole.clone(), (n, l, k.quote(env.level))); - ty.clone() - } - HoleInner::Row(n, _, _) => { - new_vars.insert(hole.clone(), (n, l, Type::new(TypeKind::Row))); - ty.clone() - } - HoleInner::Filled(e) => { - let e = e.quote(env.level); - - Context::accumulate_variables(env, level, e, new_vars, turn) - } - } - } - TypeKind::Tuple(t) => { - let t = t - .iter() - .map(|t| { - Context::accumulate_variables(env.clone(), level, t.clone(), new_vars, turn) - }) - .collect(); - Type::new(TypeKind::Tuple(t)) - } - TypeKind::Application(f, a) => { - let f = - Context::accumulate_variables(env.clone(), level, f.clone(), new_vars, turn); - let a = Context::accumulate_variables(env, level, a.clone(), new_vars, turn); - Type::new(TypeKind::Application(f, a)) - } - TypeKind::Extend(l, t, u) => Type::new(TypeKind::Extend( - l.clone(), - Context::accumulate_variables(env.clone(), level, t.clone(), new_vars, turn), - Context::accumulate_variables(env, level, u.clone(), new_vars, turn), - )), - TypeKind::Bound(n) if turn => { - let new = (*n).shift(Level(level.0 + new_vars.len())); - Type::new(TypeKind::Bound(new)) - } - _ => ty, - } - } - - #[allow(clippy::only_used_in_recursion)] - pub fn remove_effect(&mut self, label: Qualified, ty: &Type) -> Type { - match ty.deref().as_ref() { - TypeKind::Extend(l, _, rest) if label == *l => self.remove_effect(label, rest), - TypeKind::Extend(l, ty, rest) => { - Type::::extend(l.clone(), ty.clone(), self.remove_effect(label, rest)) - } - _ => ty.clone(), - } - } - - pub fn skolemize(&mut self, env: Env, ty: &Type) -> Type { - let mut vars = Default::default(); - - let real = ty.clone().quote(env.level); - - let real = Context::accumulate_variables(env.clone(), Level(0), real, &mut vars, false); - - let vars = vars.into_iter().collect::>(); - - #[allow(clippy::redundant_clone)] - let mut new_env = env.clone(); - - for (hole, (n, lvl, _)) in vars.iter() { - let bound = Type::bound(*lvl); - new_env = new_env.add(Some(n.clone()), bound.clone()); - hole.0.replace(HoleInner::Filled(bound)); - } - - let real = vars.iter().fold(real, |rest, (_, (name, _, kind))| { - Type::exists(real::Forall { - name: name.clone(), - kind: kind.clone(), - body: rest, - }) - }); - - real.eval(&env) - } - - /// Opens a type by replacing a closed effect to a open one. - pub fn open(&mut self, env: &Env, ty: Type) -> Type { - match ty.as_ref() { - TypeKind::Extend(label, effect, rest) => { - Type::::extend(label.clone(), effect.clone(), self.open(env, rest.clone())) - } - TypeKind::Empty => self.lacks(env, Default::default()), - _ => ty.clone(), - } - } -} diff --git a/crates/vulpi-typer/src/coverage.rs b/crates/vulpi-typer/src/coverage.rs deleted file mode 100644 index a1b2c3e..0000000 --- a/crates/vulpi-typer/src/coverage.rs +++ /dev/null @@ -1,548 +0,0 @@ -//! Coverage checking algorithm for pa(tt)erns. - -use std::fmt::Display; - -use im_rc::HashSet; -use vulpi_syntax::{ - elaborated::{Literal, LiteralKind, Pattern, PatternArm, PatternKind}, - r#abstract::Qualified, -}; - -use crate::{ - r#type::{eval::Eval, TypeKind}, - Context, Env, Real, Type, Virtual, -}; - -#[derive(Clone)] -pub enum Pat { - Tuple(Vec), - Constructor(Qualified, Vec), - Wildcard, - Literal(Literal), - Or(Box, Box), -} - -impl Display for Pat { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Pat::Tuple(args) => { - write!(f, "(")?; - for (i, arg) in args.iter().enumerate() { - write!(f, "{}", arg)?; - if i != args.len() - 1 { - write!(f, ", ")?; - } - } - write!(f, ")") - } - Pat::Constructor(name, args) => { - if args.is_empty() { - write!(f, "{}", name.name.get()) - } else { - write!(f, "({}", name.name.get())?; - for arg in args.iter() { - write!(f, " {}", arg)?; - } - write!(f, ")") - } - } - Pat::Wildcard => write!(f, "_"), - Pat::Literal(lit) => match &**lit { - LiteralKind::String(s) => write!(f, "\"{}\"", s.get()), - LiteralKind::Integer(i) => write!(f, "{}", i.get()), - LiteralKind::Float(fe) => write!(f, "{}", fe.get()), - LiteralKind::Char(c) => write!(f, "'{}'", c.get()), - LiteralKind::Unit => write!(f, "()"), - }, - Pat::Or(l, r) => { - write!(f, "{} | {}", l, r) - } - } - } -} - -impl Pat { - pub fn from_pattern(pat: &Pattern) -> Option { - match &**pat { - PatternKind::Wildcard => Some(Pat::Wildcard), - PatternKind::Variable(_) => Some(Pat::Wildcard), - PatternKind::Tuple(args) => Some(Pat::Tuple( - args.iter() - .map(Pat::from_pattern) - .collect::>>()?, - )), - PatternKind::Literal(l) => Some(Pat::Literal(l.clone())), - PatternKind::Application(p) => Some(Pat::Constructor( - p.func.clone(), - p.args - .iter() - .map(Pat::from_pattern) - .collect::>>()?, - )), - PatternKind::Error => None, - } - } - - pub fn is_wildcard(&self) -> bool { - matches!(self, Pat::Wildcard) - } - - pub fn constructor(&self) -> Option { - match self { - Pat::Constructor(name, _) => Some(name.clone()), - _ => None, - } - } -} - -/// A line in the problem matrix. It's used to indicate that there's an answer to a open pattern -/// problem. -#[derive(Clone)] -pub struct Row(im_rc::Vector); - -impl Row { - /// Removes the first column of the row - pub fn pop_front(&self) -> Self { - let mut line = self.clone(); - line.0.pop_front(); - line - } - - /// Checks if the line is empty - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Adds an item to the beggining of the Row - pub fn preppend(&self, item: T) -> Self { - let mut line = self.clone(); - line.0.push_front(item); - line - } - - pub fn split(&self, place: usize) -> (Self, Self) { - let (left, right) = self.0.clone().split_at(place); - (Row(left), Row(right)) - } - - pub fn first(&self) -> &T { - self.0.get(0).unwrap() - } - - pub fn inline(&self, mut other: Vec) -> Self { - let mut copied = self.clone(); - copied.0.pop_front(); - other.extend(copied.0); - Row(other.into()) - } -} - -impl Row { - pub fn specialize(&self, useful: Pat) -> Vec> { - let first = &self.0[0]; - match (useful, first) { - (Pat::Wildcard, Pat::Tuple(args)) => vec![self.inline(wildcards(args.len()))], - (Pat::Wildcard, Pat::Constructor(_, args)) => vec![self.inline(wildcards(args.len()))], - (Pat::Wildcard, Pat::Wildcard) => vec![self.pop_front()], - (Pat::Wildcard, Pat::Literal(_)) => vec![self.pop_front()], - - (Pat::Constructor(n, _), Pat::Constructor(m, args)) if n == *m => { - vec![self.inline(args.clone())] - } - - (Pat::Constructor(_, args), Pat::Wildcard) => vec![self.inline(wildcards(args.len()))], - - (Pat::Tuple(a), Pat::Tuple(b)) if a.len() == b.len() => { - vec![self.inline(b.to_vec())] - } - - (Pat::Literal(n), Pat::Literal(m)) if n == *m => vec![self.pop_front()], - - (_, _) => vec![], - } - } - - pub fn default_row(self) -> Vec> { - let first = &self.0[0]; - match first { - Pat::Wildcard => vec![self.pop_front()], - Pat::Or(l, r) => { - let mut l = self.preppend(*l.clone()).default_row(); - l.extend(self.preppend(*r.clone()).default_row()); - l - } - _ => vec![], - } - } - - pub fn is_wildcard(&self) -> bool { - self.0[0].is_wildcard() - } - - pub fn used_constructor(&self) -> Option { - self.first().constructor() - } -} - -/// A matrix is a vector of rows. -#[derive(Clone)] -pub struct Matrix(Vec>); - -impl Matrix { - pub fn is_wildcard(&self) -> bool { - self.0.iter().all(|x| x.is_wildcard()) - } - - pub fn used_constructors(&self) -> HashSet { - self.0.iter().flat_map(|x| x.used_constructor()).collect() - } - - pub fn specialize(self, useful: Pat) -> Matrix { - Matrix( - self.0 - .into_iter() - .flat_map(|x| x.specialize(useful.clone())) - .collect(), - ) - } - - pub fn default_matrix(self) -> Matrix { - Matrix(self.0.into_iter().flat_map(|x| x.default_row()).collect()) - } -} - -fn wildcards(n: usize) -> Vec { - vec![Pat::Wildcard; n] -} - -pub enum Witness { - Ok, - NonExhaustive(Row), -} - -impl Witness { - pub fn non_exaustive(&self) -> bool { - matches!(self, Witness::NonExhaustive(_)) - } - - pub fn expand(self, name: Option, size: usize) -> Self { - let Witness::NonExhaustive(x) = self else { - return self - }; - - let (left, right) = x.split(size); - - let data = if let Some(name) = name { - Pat::Constructor(name, left.0.into_iter().collect()) - } else { - Pat::Tuple(left.0.into_iter().collect()) - }; - - let row = right.preppend(data); - - Self::NonExhaustive(row) - } - - pub fn preppend(self, pat: Pat) -> Self { - let Witness::NonExhaustive(row) = self else { - return self - }; - - Witness::NonExhaustive(row.preppend(pat)) - } -} - -pub enum Finitude { - Infinite, - Finite(T), -} - -pub enum Completeness { - Complete(HashSet), - Incomplete(Finitude>), -} - -impl Completeness { - pub fn check(all: HashSet, used: HashSet) -> Self { - let diff: HashSet<_> = all.clone().difference(used).into_iter().collect(); - if diff.is_empty() { - Completeness::Complete(all) - } else { - Completeness::Incomplete(Finitude::Finite(diff)) - } - } - - pub fn infinite() -> Self { - Completeness::Incomplete(Finitude::Infinite) - } -} - -/// A problem is a matrix, a vector of types and a row that is guiding the specialization -#[derive(Clone)] -pub struct Problem { - types: Row>, - case: Row, - matrix: Matrix, -} - -impl Display for Row { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for case in self.0.clone().into_iter() { - write!(f, "{} ", case)?; - } - writeln!(f) - } -} -impl Display for Problem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "|- ")?; - for case in &self.case.0 { - write!(f, "{}", case)?; - } - writeln!(f)?; - - for row in &self.matrix.0 { - write!(f, "| ")?; - for case in &row.0 { - write!(f, "{}", case)?; - } - writeln!(f)?; - } - - Ok(()) - } -} - -impl Problem { - pub fn exhaustiveness(arms: &[PatternArm>], types: Vec>) -> Self { - let map = arms - .iter() - .flat_map(|x| { - x.patterns - .iter() - .map(Pat::from_pattern) - .collect::>>() - .map(|x| Row(x.into())) - }) - .collect::>(); - - Self { - types: Row(types[0..map.get(0).map(|x| x.0.len()).unwrap_or_default()].into()), - case: Row(wildcards(arms[0].patterns.len()).into()), - matrix: Matrix(map), - } - } - - /// Checks if the pattern matrix is empty (0x0) - pub fn is_empty(&self) -> bool { - self.matrix.0.is_empty() - } - - /// Checks if the pattern matrix contains a line that has no columns (nx0) - pub fn is_exhaustive(&self) -> bool { - self.matrix.0.iter().any(|x| x.0.is_empty()) - } - - pub fn specialize( - self, - ctx: &mut Context, - env: Env, - types: Vec>, - case_pats: Vec, - case: Pat, - ) -> Witness { - let specialized = Self { - types: self.types.inline(types), - case: self.case.inline(case_pats), - matrix: self.matrix.specialize(case), - }; - - specialized.exaustive(ctx, env) - } - - pub fn default_matrix(self) -> Self { - Self { - types: self.types.pop_front(), - case: self.case.pop_front(), - matrix: self.matrix.default_matrix(), - } - } - - pub fn specialize_wildcard(self, ctx: &mut Context, env: Env) -> Witness { - self.default_matrix() - .exaustive(ctx, env) - .preppend(Pat::Wildcard) - } - - pub fn specialize_cons( - self, - ctx: &mut Context, - env: Env, - name: Qualified, - case_pats: Vec, - args: Vec>, - ) -> Witness { - let (signature, _, _) = ctx.modules.constructor(&name); - let signature = ctx.instantiate_with_args(&signature.eval(&env), args); - - let spine = signature.arrow_spine(); - - let case = Pat::Constructor(name, case_pats.clone()); - - self.specialize(ctx, env, spine, case_pats, case) - } - - pub fn exaustive(self, ctx: &mut Context, env: Env) -> Witness { - if self.is_empty() { - Witness::NonExhaustive(self.case) - } else if self.is_exhaustive() { - Witness::Ok - } else { - self.match_exhaustiveness(ctx, env) - } - } - - pub fn is_complete_signature(&self, ctx: &mut Context, type_name: Qualified) -> Completeness { - let signature = ctx.modules.typ(&type_name); - - if let crate::module::Def::Enum(constructors) = signature.def { - Completeness::check( - constructors.into_iter().collect(), - self.matrix.used_constructors(), - ) - } else { - Completeness::infinite() - } - } - - pub fn synthetize(&self, ctx: &mut Context, name: Qualified) -> Pat { - let (_, args, _) = ctx.modules.constructor(&name); - Pat::Constructor(name.clone(), wildcards(args)) - } - - pub fn exhaustiveness_wildcard( - self, - ctx: &mut Context, - env: Env, - type_name: Qualified, - type_spine: Vec>, - ) -> Witness { - if self.matrix.is_wildcard() { - self.specialize_wildcard(ctx, env) - } else { - match self.is_complete_signature(ctx, type_name.clone()) { - Completeness::Complete(_) => self.split(ctx, env, type_name, type_spine), - Completeness::Incomplete(Finitude::Finite(cons)) => { - let name = cons.into_iter().collect::>()[0].clone(); - // let (ty, size) = ctx.modules.constructor(&name); - let pat = self.synthetize(ctx, name); - // let args = ctx.instantiate_all(&env, &ty.eval(&env)).arrow_spine(); - // let witness = self.specialize_cons(ctx, env, name, wildcards(size), args); - - let witness = self.default_matrix().exaustive(ctx, env); - - witness.preppend(pat) - } - Completeness::Incomplete(Finitude::Infinite) => { - let witness = self.specialize_wildcard(ctx, env); - witness.preppend(Pat::Wildcard) - } - } - } - } - - pub fn split( - self, - ctx: &mut Context, - env: Env, - type_name: Qualified, - type_spine: Vec>, - ) -> Witness { - let typ = ctx.modules.typ(&type_name); - - if let crate::module::Def::Enum(constructors) = typ.def { - for constructor in constructors { - let (_, size, _) = ctx.modules.constructor(&constructor); - - let witness = self.clone().specialize_cons( - ctx, - env.clone(), - constructor.clone(), - wildcards(size), - type_spine.clone(), - ); - - if witness.non_exaustive() { - return witness.expand(Some(constructor), size); - } - } - - Witness::Ok - } else { - unreachable!("This should never happen") - } - } - - pub fn exhaustiveness_tuple( - self, - ctx: &mut Context, - env: Env, - spine: Vec>, - ) -> Witness { - let size = spine.len(); - let case_pats = wildcards(size); - let witness = self.specialize(ctx, env, spine, case_pats.clone(), Pat::Tuple(case_pats)); - - if witness.non_exaustive() { - witness.expand(None, size) - } else { - Witness::Ok - } - } - - pub fn match_exhaustiveness(self, ctx: &mut Context, env: Env) -> Witness { - let case = self.case.first(); - let current = self.types.first(); - - match (case, current.deref().as_ref()) { - (Pat::Wildcard, TypeKind::Application(_, _)) - | (Pat::Wildcard, TypeKind::Variable(_)) => { - let (head, spine) = current.application_spine(); - match head.as_ref() { - TypeKind::Variable(name) => { - self.exhaustiveness_wildcard(ctx, env, name.clone(), spine) - } - _ => self.specialize_wildcard(ctx, env), - } - } - - (Pat::Wildcard, TypeKind::Tuple(spine)) => { - let spine = spine.to_vec(); - self.exhaustiveness_tuple(ctx, env, spine) - } - - (Pat::Wildcard, _) => self.specialize_wildcard(ctx, env), - - (Pat::Constructor(n, pats), TypeKind::Application(_, _)) => { - let args = current.application_spine().1; - let name = n.clone(); - let pats = pats.clone(); - self.specialize_cons(ctx, env, name, pats, args) - } - (Pat::Tuple(m), TypeKind::Tuple(n)) => { - let case_pats = m.clone(); - let types = n.clone(); - let size = n.len(); - - self.specialize(ctx, env, types, case_pats, Pat::Tuple(wildcards(size))) - } - - (Pat::Literal(n), _) => { - let literal_kind = n.clone(); - self.specialize(ctx, env, vec![], vec![], Pat::Literal(literal_kind)) - } - - _ => unreachable!("This should never happen"), - } - } -} diff --git a/crates/vulpi-typer/src/errors.rs b/crates/vulpi-typer/src/errors.rs deleted file mode 100644 index 420345e..0000000 --- a/crates/vulpi-typer/src/errors.rs +++ /dev/null @@ -1,118 +0,0 @@ -use vulpi_intern::Symbol; -use vulpi_location::Span; -use vulpi_report::{IntoDiagnostic, Text}; -use vulpi_syntax::r#abstract::Qualified; - -use crate::{ - coverage::{Pat, Row}, - r#type::{r#virtual::Env, real::Real, Type}, -}; - -pub enum TypeErrorKind { - UnboundTypeVariable(Symbol), - TypeMismatch(Env, Type, Type), - KindMismatch(Env, Type, Type), - InfiniteType, - CannotFind(Symbol), - AtLeastOneArgument, - EscapingScope, - NotAFunctionKind, - WrongArity(usize, usize), - NotAFunction(Env, Type), - NotImplemented, - NotEffect, - MissingLabel(Qualified), - InvalidLabels(Vec), - EffectsNotAllowedInNormalPatterns, - PatternsNotAllowedHere, - - DuplicatedField, - NotFoundField, - NotARecord, - MissingField(Symbol), - AmbientDoesNotContainEffects(Env, Vec>), - NonExhaustive(Row), -} - -pub struct TypeError { - pub span: Span, - pub kind: TypeErrorKind, -} - -impl IntoDiagnostic for TypeError { - fn message(&self) -> Text { - match &self.kind { - TypeErrorKind::TypeMismatch(env, left, right) => Text::from(format!( - "type mismatch: {} != {}", - left.show(env), - right.show(env) - )), - TypeErrorKind::KindMismatch(env, left, right) => Text::from(format!( - "kind mismatch: {} != {}", - left.show(env), - right.show(env), - )), - TypeErrorKind::InfiniteType => Text::from("infinite type".to_string()), - TypeErrorKind::EscapingScope => Text::from("escaping scope".to_string()), - TypeErrorKind::NotAFunctionKind => Text::from("not a function kind".to_string()), - TypeErrorKind::UnboundTypeVariable(name) => { - Text::from(format!("unbound type variable: {}", name.get())) - } - TypeErrorKind::WrongArity(expected, found) => Text::from(format!( - "wrong arity: expected {} arguments, found {}", - expected, found - )), - TypeErrorKind::NotAFunction(env, ty) => { - Text::from(format!("not a function: {}", ty.show(env))) - } - TypeErrorKind::CannotFind(name) => Text::from(format!("cannot find: {}", name.get())), - TypeErrorKind::NotImplemented => Text::from("not implemented".to_string()), - TypeErrorKind::DuplicatedField => Text::from("duplicated field".to_string()), - TypeErrorKind::NotFoundField => Text::from("not found field".to_string()), - TypeErrorKind::NotARecord => Text::from("not a record".to_string()), - TypeErrorKind::MissingField(name) => { - Text::from(format!("missing field: {}", name.get())) - } - TypeErrorKind::NotEffect => Text::from("not effect".to_string()), - TypeErrorKind::MissingLabel(name) => { - Text::from(format!("missing label: {}", name.name.get())) - } - TypeErrorKind::InvalidLabels(labels) => Text::from(format!( - "invalid labels: {}", - labels - .iter() - .map(|label| label.name.get()) - .collect::>() - .join(", ") - )), - TypeErrorKind::EffectsNotAllowedInNormalPatterns => { - Text::from("effects are not allowed in normal patterns".to_string()) - } - TypeErrorKind::PatternsNotAllowedHere => { - Text::from("patterns are not allowed here".to_string()) - } - TypeErrorKind::AtLeastOneArgument => { - Text::from("at least one argument is required".to_string()) - } - TypeErrorKind::AmbientDoesNotContainEffects(env, effects) => Text::from(format!( - "the ambient does not contain effects: {}", - effects - .iter() - .map(|effect| effect.show(env).to_string()) - .collect::>() - .join(", ") - )), - TypeErrorKind::NonExhaustive(row) => { - Text::from(format!("non-exhaustive patterns: {}", row)) - } - } - } - - fn severity(&self) -> vulpi_report::Severity { - vulpi_report::Severity::Error - } - - fn location(&self) -> Span { - self.span.clone() - } -} diff --git a/crates/vulpi-typer/src/infer/effect.rs b/crates/vulpi-typer/src/infer/effect.rs deleted file mode 100644 index 20ed770..0000000 --- a/crates/vulpi-typer/src/infer/effect.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Effect inference. - -use vulpi_syntax::r#abstract::Effects; - -use crate::{ - context::Context, - r#type::{r#virtual::Env, real::Real, Type, TypeKind}, -}; - -use super::Infer; - -impl Infer for Option { - type Return = Type; - type Context<'a> = (&'a mut Context, Env); - - fn infer(&self, (ctx, env): Self::Context<'_>) -> Self::Return { - if let Some(effects) = self { - let mut last = if let Some(rest) = &effects.rest { - let (ty, kind) = rest.infer((ctx, env.clone())); - ctx.subsumes(env.clone(), kind, crate::r#type::Kind::effect()); - ty - } else { - Type::new(TypeKind::Empty) - }; - - for effect in effects.effects.iter().rev() { - env.on(effect.span.clone()); - - let (ty, kind) = effect.infer((ctx, env.clone())); - - ctx.subsumes(env.clone(), kind, crate::r#type::Kind::effect()); - - let (head, _) = ty.application_spine(); - - let TypeKind::Variable(name) = head.as_ref() else { return ty }; - - last = Type::new(TypeKind::Extend(name.clone(), ty, last)); - } - - last - } else { - Type::new(TypeKind::Empty) - } - } -} diff --git a/crates/vulpi-typer/src/infer/expr.rs b/crates/vulpi-typer/src/infer/expr.rs deleted file mode 100644 index ab36664..0000000 --- a/crates/vulpi-typer/src/infer/expr.rs +++ /dev/null @@ -1,489 +0,0 @@ -//! Inference of expressions - -use crate::coverage::Problem; -use crate::coverage::Witness; -use crate::r#type::eval::Eval; -use crate::r#type::eval::Quote; -use crate::r#type::r#virtual; -use crate::r#type::TypeKind; -use crate::Real; - -use crate::Kind; - -use crate::check::Check; -use im_rc::HashMap; -use im_rc::HashSet; -use vulpi_intern::Symbol; -use vulpi_syntax::elaborated; -use vulpi_syntax::r#abstract::Qualified; -use vulpi_syntax::{ - r#abstract::Statement, - r#abstract::{Expr, ExprKind, StatementKind}, -}; - -use crate::{ - errors::TypeErrorKind, - r#type::{r#virtual::Virtual, Effect}, - Context, Env, Type, -}; - -use super::Infer; - -impl Infer for Expr { - type Return = (Type, elaborated::Expr>); - - type Context<'a> = (&'a mut Context, &'a Effect, Env); - - fn infer(&self, (ctx, ambient, mut env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - - match &self.data { - ExprKind::Application(app) => { - let (mut ty, func_elab) = app.func.infer((ctx, ambient, env.clone())); - - let mut elab_args = Vec::new(); - - for arg in &app.args { - env.on(arg.span.clone()); - - let (arg_ty, arg_elab) = arg.infer((ctx, ambient, env.clone())); - elab_args.push(arg_elab); - - if let Some((left, effs, right)) = ctx.as_function(&env, ty.deref()) { - let opened = ctx.open(&env, effs); - ctx.subsumes(env.clone(), left, arg_ty); - - env.on(self.span.clone()); - ctx.subsumes(env.clone(), ambient.clone(), opened); - - ty = right; - } else { - ctx.report( - &env, - TypeErrorKind::NotAFunction(env.clone(), ty.quote(env.level)), - ); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - } - } - - ( - ty.clone(), - Box::new(elaborated::ExprKind::Application( - elaborated::ApplicationExpr { - typ: ty.quote(env.level), - func: func_elab, - args: elab_args, - }, - )), - ) - } - ExprKind::Variable(m) => ( - env.vars.get(m).unwrap().clone(), - Box::new(elaborated::ExprKind::Variable(m.clone())), - ), - ExprKind::Constructor(n) => ( - ctx.modules.constructor(n).0.eval(&env), - Box::new(elaborated::ExprKind::Constructor( - ctx.modules.constructor(n).2, - n.clone(), - )), - ), - ExprKind::Function(n) => ( - ctx.modules.let_decl(n).typ.clone(), - Box::new(elaborated::ExprKind::Function( - n.clone(), - ctx.modules.let_decl(n).typ.clone().quote(env.level), - )), - ), - ExprKind::Effect(n) => ( - ctx.modules.effect(n).0, - Box::new(elaborated::ExprKind::Effect( - ctx.modules.effect(n).1, - n.clone(), - )), - ), - ExprKind::Let(e) => { - let (val_ty, body_elab) = e.body.infer((ctx, ambient, env.clone())); - - let mut hashmap = Default::default(); - let (pat_ty, pat_elab) = e.pattern.infer((ctx, &mut hashmap, env.clone())); - - ctx.subsumes(env.clone(), pat_ty, val_ty); - - for binding in hashmap { - env.add_var(binding.0, binding.1) - } - - let (ty, value_elab) = e.value.infer((ctx, ambient, env.clone())); - - ( - ty, - Box::new(elaborated::ExprKind::Let(elaborated::LetExpr { - pattern: pat_elab, - value: value_elab, - body: body_elab, - })), - ) - } - ExprKind::Tuple(t) => { - let mut types = Vec::new(); - let mut elaborated = Vec::new(); - - for ty in &t.exprs { - let (ty, elab) = ty.infer((ctx, ambient, env.clone())); - types.push(ty); - elaborated.push(elab); - } - - ( - Type::tuple(types), - Box::new(elaborated::ExprKind::Tuple( - vulpi_syntax::elaborated::Tuple { exprs: elaborated }, - )), - ) - } - ExprKind::Error => (Type::error(), Box::new(elaborated::ExprKind::Error)), - ExprKind::When(when) => { - // TODO: Check mode - let ret_type = ctx.hole(&env, Kind::typ()); - - ctx.errored = false; - - let (_, arms, ret, elab_arms) = - when.arms.infer((ctx, ambient.clone(), env.clone())); - - let perform = !ctx.errored; - - if arms.len() != when.scrutinee.len() { - ctx.report( - &env, - TypeErrorKind::WrongArity(arms.len(), when.scrutinee.len()), - ); - } - - let mut elab_scrutinee = Vec::new(); - - for (arm, scrutinee) in arms.iter().cloned().zip(when.scrutinee.iter()) { - let elab = scrutinee.check(arm, (ctx, ambient, env.clone())); - elab_scrutinee.push(elab); - } - - ctx.subsumes(env.clone(), ret_type.clone(), ret); - - if perform { - let problem = Problem::exhaustiveness(&elab_arms, arms); - - if let Witness::NonExhaustive(case) = problem.exaustive(ctx, env.clone()) { - ctx.report(&env, TypeErrorKind::NonExhaustive(case)); - }; - } - - ( - ret_type, - Box::new(elaborated::ExprKind::When(elaborated::WhenExpr { - scrutinee: elab_scrutinee, - arms: elab_arms, - })), - ) - } - ExprKind::Do(block) => { - let mut ty = Type::tuple(vec![]); - let mut stmts = Vec::new(); - - for stmt in &block.statements { - let (new_ty, new_env, stmt) = stmt.infer((ctx, ambient, env.clone())); - ty = new_ty; - env = new_env; - - stmts.push(stmt); - } - - (ty, Box::new(elaborated::ExprKind::Do(stmts))) - } - ExprKind::Literal(n) => { - let (ty, elab) = n.infer((ctx, env)); - (ty, Box::new(elaborated::ExprKind::Literal(elab))) - } - ExprKind::Annotation(ann) => { - let (ty, elab_expr) = ann.expr.infer((ctx, ambient, env.clone())); - let (typ, _) = ann.ty.infer((ctx, env.clone())); - let right = typ.eval(&env); - ctx.subsumes(env.clone(), ty, right.clone()); - (right, elab_expr) - } - ExprKind::Lambda(lam) => { - let mut hashmap = Default::default(); - let (pat_ty, elab_pat) = lam.param.infer((ctx, &mut hashmap, env.clone())); - - for binding in hashmap { - env.add_var(binding.0, binding.1) - } - - let ambient = ctx.lacks(&env, Default::default()); - let (body, elab_body) = lam.body.infer((ctx, &ambient, env.clone())); - - ( - Type::new(TypeKind::Arrow(r#virtual::Pi { - ty: pat_ty, - effs: ambient, - body, - })), - Box::new(elaborated::ExprKind::Lambda(elaborated::LambdaExpr { - param: elab_pat, - body: elab_body, - })), - ) - } - ExprKind::Projection(expr) => { - let (ty, elab_expr) = expr.expr.infer((ctx, ambient, env.clone())); - - let (head, spine) = ty.application_spine(); - - let TypeKind::Variable(name) = head.as_ref() else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let typ = ctx.modules.typ(name); - - let crate::module::Def::Record(rec) = typ.def else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let Some(field_name) = rec.iter().find(|x| x.name == expr.field) else { - ctx.report(&env, TypeErrorKind::NotFoundField); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let field = ctx.modules.field(field_name); - - let eval_ty = field.eval(&env); - - ( - ctx.instantiate_with_args(&eval_ty, spine), - Box::new(elaborated::ExprKind::Projection( - elaborated::ProjectionExpr { - expr: elab_expr, - field: field_name.clone(), - }, - )), - ) - } - ExprKind::RecordInstance(instance) => { - let typ = ctx.modules.typ(&instance.name); - - let crate::module::Def::Record(rec) = typ.def else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let iter = rec.into_iter().map(|x| (x.name.clone(), x)); - - let available: HashMap = HashMap::from_iter(iter); - let mut used = HashSet::::default(); - - let binders = typ - .binders - .iter() - .map(|x| ctx.hole::(&env, x.1.clone())) - .collect::>(); - - let ret_type = Type::::application( - Type::variable(instance.name.clone()), - binders.clone(), - ); - - let mut elab_fields = Vec::new(); - - for (span, name, expr) in &instance.fields { - env.on(span.clone()); - - let Some(qualified) = available.get(name) else { - ctx.report(&env, TypeErrorKind::NotFoundField); - continue - }; - - if used.contains(name) { - ctx.report(&env, TypeErrorKind::DuplicatedField); - continue; - } - - let field = ctx.modules.field(qualified).eval(&env); - let inst_field = ctx.instantiate_with_args(&field, binders.clone()); - - let elab_expr = expr.check(inst_field.clone(), (ctx, ambient, env.clone())); - - elab_fields.push((name.clone(), elab_expr)); - - used.insert(name.clone()); - } - - let diff = available - .keys() - .cloned() - .collect::>() - .difference(used); - - for key in diff { - ctx.report(&env, TypeErrorKind::MissingField(key)); - } - - ( - ret_type, - Box::new(elaborated::ExprKind::RecordInstance( - elaborated::RecordInstance { - name: instance.name.clone(), - fields: elab_fields, - }, - )), - ) - } - ExprKind::RecordUpdate(update) => { - let (typ, elab_expr) = update.expr.infer((ctx, ambient, env.clone())); - - let (head, binders) = typ.application_spine(); - - let TypeKind::Variable(name) = head.as_ref() else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let Some(typ) = ctx.modules.get(&name.path).types.get(&name.name).cloned() else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let crate::module::Def::Record(rec) = &typ.def else { - ctx.report(&env, TypeErrorKind::NotARecord); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let iter = rec.iter().map(|x| (x.name.clone(), x.clone())); - - let available: HashMap = HashMap::from_iter(iter); - let mut used = HashSet::::default(); - - let ret_type = - Type::::application(Type::variable(name.clone()), binders.clone()); - - let mut elab_fields = Vec::new(); - - for (span, name, expr) in &update.fields { - env.on(span.clone()); - - let Some(qualified) = available.get(name) else { - ctx.report(&env, TypeErrorKind::NotFoundField); - continue - }; - - if used.contains(name) { - ctx.report(&env, TypeErrorKind::DuplicatedField); - continue; - } - - let field = ctx.modules.field(qualified).eval(&env); - let inst_field = ctx.instantiate_with_args(&field, binders.clone()); - - let elab = expr.check(inst_field.clone(), (ctx, ambient, env.clone())); - - elab_fields.push((name.clone(), elab)); - - used.insert(name.clone()); - } - - ( - ret_type, - Box::new(elaborated::ExprKind::RecordUpdate( - elaborated::RecordUpdate { - expr: elab_expr, - fields: elab_fields, - }, - )), - ) - } - ExprKind::Handler(h) => { - let scrutinee = ctx.hole::(&env, Type::typ()); - - let (handle_type, elab_handler) = h.with.infer((ctx, ambient, env.clone())); - - let Some((left, eff, right)) = ctx.as_function(&env, handle_type.clone()) else { - ctx.report(&env, TypeErrorKind::NotAFunction(env.clone(), handle_type.quote(env.level))); - return (Type::error(), Box::new(elaborated::ExprKind::Error)); - }; - - let request = ctx.find_prelude_type("Request", env.clone()); - - let removed_effect = ctx.hole::(&env, Type::effect()); - - let app = Type::::application( - request, - vec![removed_effect.clone(), scrutinee.clone()], - ); - - let (var, _) = removed_effect.application_spine(); - - ctx.subsumes(env.clone(), left, app); - - let new_ambient = if let TypeKind::Variable(name) = var.deref().as_ref() { - Type::::extend(name.clone(), removed_effect, ambient.clone()) - } else { - ambient.clone() - }; - - let elab_expr = h.expr.check(scrutinee, (ctx, &new_ambient, env.clone())); - - let eff = ctx.open(&env, eff); - ctx.subsumes(env.clone(), ambient.clone(), eff); - - ( - right, - Box::new(elaborated::ExprKind::Handler(elaborated::HandlerExpr { - expr: elab_expr, - with: elab_handler, - })), - ) - } - ExprKind::Cases(_) => { - let ty = ctx.hole::(&env, Type::typ()); - (ty.clone(), self.check(ty, (ctx, ambient, env.clone()))) - } - } - } -} - -impl Infer for Statement { - type Return = (Type, Env, elaborated::Statement>); - - type Context<'a> = (&'a mut Context, &'a Effect, Env); - - fn infer(&self, (ctx, ambient, mut env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - match &self.data { - StatementKind::Let(decl) => { - let mut hashmap = Default::default(); - let (pat_ty, elab_pat) = decl.pattern.infer((ctx, &mut hashmap, env.clone())); - - let elab_expr = decl.expr.check(pat_ty, (ctx, ambient, env.clone())); - - for binding in hashmap { - env.add_var(binding.0, binding.1) - } - - ( - Type::tuple(vec![]), - env, - elaborated::StatementKind::Let(elaborated::LetStatement { - pattern: elab_pat, - expr: elab_expr, - }), - ) - } - StatementKind::Expr(expr) => { - let (ty, elab_expr) = expr.infer((ctx, ambient, env.clone())); - (ty, env, elaborated::StatementKind::Expr(elab_expr)) - } - StatementKind::Error => (Type::error(), env, elaborated::StatementKind::Error), - } - } -} diff --git a/crates/vulpi-typer/src/infer/kind.rs b/crates/vulpi-typer/src/infer/kind.rs deleted file mode 100644 index 32d0cc8..0000000 --- a/crates/vulpi-typer/src/infer/kind.rs +++ /dev/null @@ -1,36 +0,0 @@ -use vulpi_syntax::r#abstract::{Kind, KindType}; - -use crate::r#type::{ - self, - r#virtual::Env, - real::{self, Real}, - Type, TypeKind, -}; - -use super::Infer; - -impl Infer for Kind { - type Return = r#type::Kind; - - type Context<'a> = Env; - - fn infer(&self, context: Self::Context<'_>) -> Self::Return { - context.on(self.span.clone()); - - match &self.data { - KindType::Star => Type::typ(), - KindType::Effect => Type::effect(), - KindType::Constraint => todo!(), - KindType::Arrow(l, r) => { - let l = l.infer(context.clone()); - let r = r.infer(context); - Type::new(TypeKind::Arrow(real::Arrow { - ty: l, - effs: Type::new(TypeKind::Empty), - body: r, - })) - } - KindType::Error => Type::error(), - } - } -} diff --git a/crates/vulpi-typer/src/infer/literal.rs b/crates/vulpi-typer/src/infer/literal.rs deleted file mode 100644 index ee080a9..0000000 --- a/crates/vulpi-typer/src/infer/literal.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Inference of literals - -use vulpi_syntax::{elaborated, r#abstract::Literal, r#abstract::LiteralKind}; - -use super::Infer; -use crate::{r#type::r#virtual::Virtual, Context, Env, Type}; - -impl Infer for Literal { - type Return = (Type, elaborated::Literal); - - type Context<'a> = (&'a mut Context, Env); - - fn infer(&self, (ctx, env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - - match &self.data { - LiteralKind::String(n) => ( - ctx.find_prelude_type("String", env), - Box::new(elaborated::LiteralKind::String(n.clone())), - ), - LiteralKind::Integer(n) => ( - ctx.find_prelude_type("Int", env), - Box::new(elaborated::LiteralKind::Integer(n.clone())), - ), - LiteralKind::Float(n) => ( - ctx.find_prelude_type("Float", env), - Box::new(elaborated::LiteralKind::Float(n.clone())), - ), - LiteralKind::Char(n) => ( - ctx.find_prelude_type("Char", env), - Box::new(elaborated::LiteralKind::Char(n.clone())), - ), - LiteralKind::Unit => (Type::tuple(vec![]), Box::new(elaborated::LiteralKind::Unit)), - } - } -} diff --git a/crates/vulpi-typer/src/infer/mod.rs b/crates/vulpi-typer/src/infer/mod.rs deleted file mode 100644 index c93cfe3..0000000 --- a/crates/vulpi-typer/src/infer/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! The inference trait. It correponds to the `Γ |- e ⇒ A -| ∆` on the paper. It is responsible for -//! inferring the type of an expression given a context. - -pub mod effect; -pub mod expr; -pub mod kind; -pub mod literal; -pub mod pat; -pub mod r#type; - -/// The inference trait. It descovers the type of an expression based on the context. -pub trait Infer { - type Return; - type Context<'a>; - - fn infer(&self, context: Self::Context<'_>) -> Self::Return; -} - -impl Infer for Option { - type Return = Option; - type Context<'a> = T::Context<'a>; - - fn infer(&self, context: Self::Context<'_>) -> Self::Return { - self.as_ref().map(|x| x.infer(context)) - } -} - -impl Infer for Box { - type Return = Box; - type Context<'a> = T::Context<'a>; - fn infer(&self, context: Self::Context<'_>) -> Self::Return { - Box::new(self.as_ref().infer(context)) - } -} diff --git a/crates/vulpi-typer/src/infer/pat.rs b/crates/vulpi-typer/src/infer/pat.rs deleted file mode 100644 index ed51c42..0000000 --- a/crates/vulpi-typer/src/infer/pat.rs +++ /dev/null @@ -1,296 +0,0 @@ -//! Inference of patterns - -use std::collections::HashMap; - -use vulpi_intern::Symbol; -use vulpi_syntax::{ - elaborated::{self, PatApplication}, - r#abstract::Pattern, - r#abstract::PatternArm, - r#abstract::PatternKind, -}; - -use crate::{ - errors::TypeErrorKind, - r#type::{eval::Eval, r#virtual::Virtual, Effect}, - Context, Env, Kind, Real, Type, -}; - -use super::Infer; - -impl Infer for PatternArm { - type Return = ( - Vec>, - Type, - elaborated::PatternArm>, - ); - - type Context<'a> = (&'a mut Context, Effect, Env); - - fn infer(&self, (ctx, ambient, mut env): Self::Context<'_>) -> Self::Return { - let mut patterns = Vec::new(); - let mut elaborated_patterns = Vec::new(); - - let mut map = Default::default(); - for pat in &self.patterns { - let (typ, elab) = pat.infer((ctx, &mut map, env.clone())); - patterns.push(typ); - elaborated_patterns.push(elab); - } - - for binding in map { - env.add_var(binding.0, binding.1); - } - - let (typ, elab_expr) = self.expr.infer((ctx, &ambient, env.clone())); - - let guard = self - .guard - .as_ref() - .map(|g| g.infer((ctx, &ambient, env.clone()))); - - let elab_guard = if let Some((typ, guard)) = guard { - let bool = ctx.find_prelude_type("Bool", env.clone()); - ctx.subsumes(env.clone(), typ, bool); - Some(guard) - } else { - None - }; - - ( - patterns, - typ, - elaborated::PatternArm { - patterns: elaborated_patterns, - guard: elab_guard, - expr: elab_expr, - }, - ) - } -} - -impl Infer for Vec { - type Return = ( - Type, - Vec>, - Type, - Vec>>, - ); - - type Context<'a> = (&'a mut Context, Effect, Env); - - fn infer(&self, (ctx, ambient, env): Self::Context<'_>) -> Self::Return { - if self.is_empty() { - ( - ctx.hole(&env, Kind::typ()), - vec![], - ctx.hole(&env, Kind::typ()), - vec![], - ) - } else { - let (types, ret_type, elab_arm) = self[0].infer((ctx, ambient.clone(), env.clone())); - - let mut elab_arms = vec![elab_arm]; - - for pat in self.iter().skip(1) { - let (new_types, new_ret_type, elab_arm) = - pat.infer((ctx, ambient.clone(), env.clone())); - - elab_arms.push(elab_arm); - - if new_types.len() != types.len() { - ctx.report( - &env, - TypeErrorKind::WrongArity(new_types.len(), types.len()), - ); - return (Type::error(), types, Type::error(), vec![]); - } - - for (old, new) in types.iter().zip(new_types) { - ctx.subsumes(env.clone(), old.clone(), new); - } - - ctx.subsumes(env.clone(), ret_type.clone(), new_ret_type); - } - - ( - Type::::function(types.clone(), ret_type.clone()), - types, - ret_type, - elab_arms, - ) - } - } -} -/// Helper structure made for inference of effect patterns. -pub(crate) struct EffectPat<'a>(pub Type, pub &'a Pattern); - -impl Infer for Pattern { - type Return = (Type, elaborated::Pattern); - - type Context<'a> = (&'a mut Context, &'a mut HashMap>, Env); - - fn infer(&self, (ctx, map, env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - - match &self.data { - PatternKind::Wildcard => ( - ctx.hole(&env, Type::typ()), - Box::new(elaborated::PatternKind::Wildcard), - ), - PatternKind::Tuple(tuple) => { - let mut types = Vec::new(); - let mut elab_pats = Vec::new(); - - for pat in tuple { - let (typ, elab_pat) = pat.infer((ctx, map, env.clone())); - types.push(typ); - elab_pats.push(elab_pat); - } - - ( - Type::tuple(types), - Box::new(elaborated::PatternKind::Tuple(elab_pats)), - ) - } - PatternKind::Variable(symbol) => { - let value = ctx.hole(&env, Type::typ()); - - if let Some(typ) = map.get(symbol) { - ctx.subsumes(env, typ.clone(), value.clone()); - } else { - map.insert(symbol.clone(), value.clone()); - } - - ( - value, - Box::new(elaborated::PatternKind::Variable(symbol.clone())), - ) - } - PatternKind::Literal(lit) => { - let (typ, lit) = lit.infer((ctx, env)); - (typ, Box::new(elaborated::PatternKind::Literal(lit))) - } - PatternKind::Ascription(ann) => { - let (typ, _) = ann.typ.infer((ctx, env.clone())); - let eval_typ = typ.eval(&env); - let (value, pat) = ann.pat.infer((ctx, map, env.clone())); - ctx.subsumes(env, eval_typ.clone(), value); - (eval_typ, pat) - } - PatternKind::Or(_) => { - unimplemented!("Or patterns are not yet implemented") - } - PatternKind::Application(app) => { - let (typ, arity, _) = ctx.modules.constructor(&app.func); - - let mut typ = typ.eval(&env); - - if arity != app.args.len() { - ctx.report(&env, TypeErrorKind::WrongArity(arity, app.args.len())); - return (Type::error(), Box::new(elaborated::PatternKind::Error)); - } - - let mut types = Vec::new(); - let mut args = Vec::new(); - - for arg in &app.args { - let (arg_ty, elab_arg) = arg.infer((ctx, map, env.clone())); - - types.push(arg_ty.clone()); - args.push(elab_arg); - - let Some((param_ty, _, rest)) = ctx.as_function(&env, typ) else { unreachable!() }; - - typ = rest; - ctx.subsumes(env.clone(), param_ty, arg_ty); - } - - ( - typ, - Box::new(elaborated::PatternKind::Application(PatApplication { - func: app.func.clone(), - args, - })), - ) - } - PatternKind::Effect(_) => { - ctx.report(&env, TypeErrorKind::EffectsNotAllowedInNormalPatterns); - (Type::error(), Box::new(elaborated::PatternKind::Error)) - } - PatternKind::Error => (Type::error(), Box::new(elaborated::PatternKind::Error)), - } - } -} - -impl<'b> Infer for EffectPat<'b> { - type Return = (Type, elaborated::PatEffectKind); - - type Context<'a> = ( - &'a mut Context, - &'a mut HashMap>, - &'a mut Env, - ); - - fn infer(&self, (ctx, map, env): Self::Context<'_>) -> Self::Return { - env.on(self.1.span.clone()); - - match &self.1.data { - PatternKind::Wildcard => ( - ctx.lacks(env, Default::default()), - elaborated::PatEffectKind::Wildcard, - ), - PatternKind::Variable(n) => { - map.insert(n.clone(), self.0.clone()); - ( - ctx.lacks(env, Default::default()), - elaborated::PatEffectKind::Variable(n.clone()), - ) - } - PatternKind::Effect(eff) => { - let (mut typ, _, arity) = ctx.modules.effect(&eff.func); - - if arity != eff.args.len() { - ctx.report(env, TypeErrorKind::WrongArity(arity, eff.args.len())); - return (Type::error(), elaborated::PatEffectKind::Error); - } - - let mut types = Vec::new(); - let mut ret_eff = typ.clone(); - let mut elab_args = Vec::new(); - - for arg in &eff.args { - let (arg_ty, elab_arg) = arg.infer((ctx, map, env.clone())); - types.push(arg_ty.clone()); - elab_args.push(elab_arg); - - let Some((param_ty, effect, rest)) = ctx.as_function(env, typ) else { unreachable!() }; - ret_eff = effect; - - typ = rest; - ctx.subsumes(env.clone(), param_ty, arg_ty); - } - - if let Some(cont) = &eff.cont { - let typ = ctx.skolemize(env.clone(), &typ); - let cont_ty = Type::::function(vec![typ], self.0.clone()); - map.insert(cont.clone(), cont_ty); - } - - ( - ret_eff, - elaborated::PatEffectKind::Effect(elaborated::PatEffect { - func: eff.func.clone(), - args: elab_args, - cont: eff.cont.clone(), - }), - ) - } - PatternKind::Error => (Type::error(), elaborated::PatEffectKind::Error), - _ => { - ctx.report(env, TypeErrorKind::EffectsNotAllowedInNormalPatterns); - (Type::error(), elaborated::PatEffectKind::Error) - } - } - } -} diff --git a/crates/vulpi-typer/src/infer/type.rs b/crates/vulpi-typer/src/infer/type.rs deleted file mode 100644 index 1cdb687..0000000 --- a/crates/vulpi-typer/src/infer/type.rs +++ /dev/null @@ -1,123 +0,0 @@ -//! Inference of types - -use crate::{ - context::Context, - errors::TypeErrorKind, - r#type::{ - self, - eval::{Eval, Quote}, - r#virtual::Env, - r#virtual::Virtual, - real::{self, Real}, - Index, Kind, Type, - }, -}; - -use super::Infer; -use vulpi_syntax::{r#abstract, r#abstract::TypeKind}; - -impl Infer for r#abstract::Type { - type Return = (Type, Kind); - - type Context<'a> = (&'a mut Context, Env); - - fn infer(&self, (ctx, env): Self::Context<'_>) -> Self::Return { - env.on(self.span.clone()); - - match &self.data { - TypeKind::Arrow(pi) => { - let (ty, kind) = pi.left.infer((ctx, env.clone())); - env.on(pi.left.span.clone()); - ctx.subsumes(env.clone(), kind, Kind::typ()); - - let (body, kind) = pi.right.infer((ctx, env.clone())); - env.on(pi.right.span.clone()); - ctx.subsumes(env.clone(), kind, Kind::typ()); - - let effs = pi.effects.infer((ctx, env.clone())); - - let typ = Type::new(r#type::TypeKind::Arrow(real::Arrow { ty, effs, body })); - (typ, Kind::typ()) - } - TypeKind::Tuple(t) => { - let mut types = Vec::new(); - - for ty in t { - let (ty, kind) = ty.infer((ctx, env.clone())); - ctx.subsumes(env.clone(), kind, Kind::typ()); - types.push(ty); - } - - (Type::tuple(types), Kind::typ()) - } - TypeKind::Application(app) => { - let (ty, mut k) = app.func.infer((ctx, env.clone())); - - let mut args = Vec::new(); - - for arg in &app.args { - env.on(arg.span.clone()); - - let (arg_ty, arg_kind) = arg.infer((ctx, env.clone())); - - args.push(arg_ty); - - if let Some((left, _, right)) = ctx.as_function(&env, k.deref()) { - ctx.subsumes(env.clone(), arg_kind, left); - k = right; - } else { - ctx.report( - &env, - TypeErrorKind::NotAFunction(env.clone(), k.quote(env.level)), - ); - return (Type::error(), Kind::error()); - } - } - - (Type::::application(ty, args), k) - } - TypeKind::Forall(forall) => { - let mut env = env.clone(); - let mut names = Vec::new(); - - for binder in &forall.params { - let (name, ty) = binder.infer((ctx, env.clone())); - env = env.add(Some(name.clone()), ty.eval(&env)); - names.push((name, ty)); - } - - let (ty, kind) = forall.body.infer((ctx, env)); - - let forall = names.into_iter().fold(ty, |body, (name, kind)| { - Type::forall(real::Forall { name, kind, body }) - }); - - (forall, kind) - } - TypeKind::TypeVariable(name) => { - let Some((index, _, kind)) = env.find(name) else { - ctx.report(&env, TypeErrorKind::CannotFind(name.clone())); - return (Type::error(), Type::error()) - }; - - (Type::bound(Index(index)), kind) - } - TypeKind::Type(name) => (Type::variable(name.clone()), ctx.modules.typ(name).kind), - TypeKind::Unit => (Type::tuple(Vec::new()), Kind::typ()), - TypeKind::Error => (Type::error(), Kind::error()), - } - } -} - -impl Infer for r#abstract::TypeBinder { - type Return = (vulpi_intern::Symbol, Type); - - type Context<'a> = (&'a mut Context, Env); - - fn infer(&self, (ctx, env): Self::Context<'_>) -> Self::Return { - match self { - r#abstract::TypeBinder::Implicit(n) => (n.clone(), ctx.hole(&env, Kind::typ())), - r#abstract::TypeBinder::Explicit(n, k) => (n.clone(), k.infer(env.clone())), - } - } -} diff --git a/crates/vulpi-typer/src/lib.rs b/crates/vulpi-typer/src/lib.rs deleted file mode 100644 index 160821e..0000000 --- a/crates/vulpi-typer/src/lib.rs +++ /dev/null @@ -1,626 +0,0 @@ -//! This is the entrypoint for the `vulpi-typer` crate. It is responsible for type checking a -//! higher rank, higher kinded, algebraic type system. It is also responsible for type inference -//! and type checking of the ambient effects system. - -pub use context::Context; -use coverage::{Problem, Witness}; -use errors::TypeErrorKind; -use r#type::real::Arrow; -use r#type::TypeKind; -pub use r#type::{r#virtual::Env, Type}; -pub use r#type::{r#virtual::Virtual, real::Real, Kind}; -use vulpi_report::Report; -use vulpi_syntax::r#abstract::LetDecl; - -use crate::check::Check; -use crate::r#type::eval::{Eval, Quote}; -use crate::r#type::real::Forall; -use crate::r#type::Index; -use infer::Infer; -use module::{Def, LetDef, TypeData}; - -use vulpi_syntax::{ - elaborated, - r#abstract::{EffectDecl, ExternalDecl, ModuleDecl, Program, TypeDecl, TypeDef}, -}; - -pub mod check; -pub mod context; -pub mod coverage; -pub mod errors; -pub mod infer; -pub mod module; -pub mod r#type; - -/// Trait for declaration of top level items inside the type checker. -pub trait Declare { - fn declare(&self, context: (&mut Context, Env)); - fn define(&self, _context: (&mut Context, Env)) {} -} - -impl Declare for Vec { - fn declare(&self, context: (&mut Context, Env)) { - for decl in self { - decl.declare((context.0, context.1.clone())); - } - } - - fn define(&self, context: (&mut Context, Env)) { - for decl in self { - decl.define((context.0, context.1.clone())); - } - } -} - -impl Declare for Option { - fn declare(&self, context: (&mut Context, Env)) { - if let Some(decl) = self { - decl.declare(context); - } - } - - fn define(&self, context: (&mut Context, Env)) { - if let Some(decl) = self { - decl.define(context); - } - } -} - -impl Declare for TypeDecl { - fn declare(&self, (context, env): (&mut Context, Env)) { - let vec = &self.binders; - - let mut names = Vec::new(); - let mut binders = Vec::new(); - - for binder in vec { - let (n, binder) = binder.infer((context, env.clone())); - binders.push(binder.eval(&env)); - names.push(n); - } - - let kind = Type::::function(binders.clone(), Type::typ()); - - let type_def = &self.def; - let def = get_definition_of_type(type_def); - - context.modules.get(&self.name.path).types.insert( - self.name.name.clone(), - TypeData { - kind, - binders: names.into_iter().zip(binders.into_iter()).collect(), - module: self.namespace.clone(), - def, - }, - ); - } - - fn define(&self, (ctx, mut env): (&mut Context, Env)) { - let type_decl = ctx.modules.typ(&self.name); - - for (name, binder) in &type_decl.binders { - env = env.add(Some(name.clone()), binder.clone()); - } - - let ret_type = Type::::application( - Type::variable(self.name.clone()), - (0..type_decl.binders.len()) - .rev() - .map(|x| Type::bound(Index(x))) - .collect(), - ); - - let decl = match &self.def { - TypeDef::Sum(cons) => { - let mut constructors = Vec::new(); - - let mut cons_types = Vec::new(); - - for cons in &cons.constructors { - constructors.push((cons.name.clone(), cons.args.len())); - - let mut types = Vec::new(); - - for arg in &cons.args { - env.on(arg.span.clone()); - let (typ, kind) = arg.infer((ctx, env.clone())); - ctx.subsumes(env.clone(), kind, Kind::typ()); - types.push(typ); - } - - let typ = Type::::function(types, ret_type.clone()); - cons_types.push((cons.name.clone(), cons.args.len(), typ)); - } - - for (name, arity, mut cons_typ) in cons_types { - for (name, binder) in type_decl.binders.iter().rev() { - cons_typ = Type::forall(Forall { - name: name.clone(), - kind: binder.clone().quote(env.level), - body: cons_typ, - }); - } - - ctx.modules - .get(&name.path) - .constructors - .insert(name.name.clone(), (cons_typ, arity, self.name.clone())); - } - - elaborated::TypeDecl::Enum(constructors) - } - TypeDef::Record(rec) => { - let mut types = Vec::new(); - let mut names = Vec::new(); - - for field in &rec.fields { - names.push(field.0.clone()); - - let (typ, kind) = field.1.infer((ctx, env.clone())); - env.on(field.1.span.clone()); - - ctx.subsumes(env.clone(), kind, Kind::typ()); - - types.push(typ); - } - - for (name, mut typ) in names.iter().zip(types.into_iter()) { - for (name, binder) in type_decl.binders.iter().rev() { - typ = Type::forall(Forall { - name: name.clone(), - kind: binder.clone().quote(env.level), - body: typ, - }); - } - - ctx.modules - .get(&name.path) - .fields - .insert(name.name.clone(), typ); - } - - elaborated::TypeDecl::Record(names) - } - TypeDef::Synonym(_) => todo!(), - TypeDef::Abstract => elaborated::TypeDecl::Abstract, - }; - - ctx.elaborated.types.insert(self.name.clone(), decl); - } -} - -fn get_definition_of_type(type_def: &TypeDef) -> Def { - match type_def { - TypeDef::Sum(cons) => Def::Enum(cons.constructors.iter().map(|x| x.name.clone()).collect()), - TypeDef::Record(rec) => Def::Record(rec.fields.iter().map(|x| x.0.clone()).collect()), - TypeDef::Synonym(_) => Def::Type, - TypeDef::Abstract => Def::Type, - } -} - -impl Declare for ExternalDecl { - fn declare(&self, (ctx, mut env): (&mut Context, Env)) { - let fvs = self.ty.data.free_variables(); - - let mut unbound = Vec::new(); - - for fv in fvs { - let ty = ctx.hole(&env, Type::typ()); - env = env.add(Some(fv.clone()), ty.clone()); - unbound.push((fv, ty.quote(env.level))) - } - - let (typ, k) = self.ty.infer((ctx, env.clone())); - ctx.subsumes(env.clone(), k, Kind::typ()); - - let typ = typ.eval(&env); - - ctx.modules.get(&self.namespace).variables.insert( - self.name.name.clone(), - LetDef { - typ: typ.clone(), - unbound, - ambient: Type::new(TypeKind::Empty), - unbound_effects: vec![], - ret: typ.clone(), - args: vec![], - }, - ); - - ctx.elaborated.externals.insert( - self.name.clone(), - elaborated::ExternalDecl { - typ: typ.quote(env.level), - binding: self.ret.clone(), - }, - ); - } -} - -impl Declare for EffectDecl { - fn declare(&self, (context, env): (&mut Context, Env)) { - let mut binders = Vec::new(); - let mut names = Vec::new(); - - for binder in &self.binders { - let (n, binder) = binder.infer((context, env.clone())); - binders.push(binder.eval(&env)); - names.push(n); - } - - let kind = Type::::function(binders.clone(), Type::effect()); - - let effects = self - .effects - .iter() - .map(|x| x.name.clone()) - .collect::>(); - - context.modules.get(&self.name.path.clone()).types.insert( - self.name.name.clone(), - TypeData { - kind, - binders: names.into_iter().zip(binders.into_iter()).collect(), - module: self.namespace.clone(), - def: Def::Effect(effects.clone()), - }, - ); - - context - .elaborated - .effects - .insert(self.name.clone(), effects); - } - - fn define(&self, (ctx, mut env): (&mut Context, Env)) { - let type_decl = ctx.modules.typ(&self.name); - - for (name, binder) in &type_decl.binders { - env = env.add(Some(name.clone()), binder.clone()); - } - - let mut names = Vec::new(); - let mut eff_types = Vec::new(); - - for eff in &self.effects { - let mut env = env.clone(); - names.push(eff.name.clone()); - - let mut fvs = eff.ty.data.free_variables(); - let mut bound = Vec::new(); - - for arg in &eff.args { - fvs.extend(arg.data.free_variables()); - } - - for (name, _) in &type_decl.binders { - fvs.remove(name); - } - - let size = fvs.len(); - - for fv in fvs { - let ty = ctx.hole(&env, Type::typ()); - env = env.add(Some(fv.clone()), ty.clone()); - bound.push((fv, ty)); - } - - let extension_type_name = ctx.new_name(); - let hole = ctx.hole(&env, Type::typ()); - env = env.add(Some(extension_type_name.clone()), hole); - - let eff_type = Type::::application( - Type::variable(self.name.clone()), - (0..type_decl.binders.len()) - .rev() - .map(|x| Type::bound(Index(x + size + 1))) - .collect(), - ); - - let mut types = Vec::new(); - - for arg in &eff.args { - env.on(arg.span.clone()); - let (typ, kind) = arg.infer((ctx, env.clone())); - ctx.subsumes(env.clone(), kind, Kind::typ()); - types.push(typ); - } - - if eff.args.is_empty() { - ctx.report(&env, errors::TypeErrorKind::AtLeastOneArgument) - } else { - let (ret_type, kind) = eff.ty.infer((ctx, env.clone())); - env.on(eff.ty.span.clone()); - ctx.subsumes(env.clone(), kind, Kind::typ()); - - let popped = types.pop().unwrap(); - - let extension_type = Type::::bound(Index(0)); - - let fun = Type::new(TypeKind::::Arrow(Arrow { - ty: popped, - effs: Type::::extend( - self.name.clone(), - eff_type.clone(), - extension_type.clone(), - ), - body: ret_type, - })); - - let mut typ = Type::::function(types, fun.clone()); - - typ = Type::forall(Forall { - name: extension_type_name.clone(), - kind: Type::row(), - body: typ, - }); - - for (name, kind) in bound { - typ = Type::forall(Forall { - name, - kind: kind.quote(env.level), - body: typ, - }); - } - - eff_types.push((eff.args.len(), typ)); - } - } - - for (name, (arity, mut cons_typ)) in names.iter().zip(eff_types.into_iter()) { - for (name, binder) in type_decl.binders.iter().rev() { - cons_typ = Type::forall(Forall { - name: name.clone(), - kind: binder.clone().quote(env.level), - body: cons_typ, - }); - } - - ctx.modules.get(&name.path).effects.insert( - name.name.clone(), - (cons_typ.eval(&env), self.name.clone(), arity), - ); - } - } -} - -impl Declare for LetDecl { - fn declare(&self, (ctx, mut env): (&mut Context, Env)) { - let has_effect = self.ret.as_ref().map(|x| x.0.is_some()).unwrap_or_default(); - - if has_effect && self.binders.is_empty() { - ctx.report(&env, errors::TypeErrorKind::AtLeastOneArgument); - return; - } - - let mut efvs = self - .ret - .as_ref() - .and_then(|x| { - x.0.as_ref() - .and_then(|x| x.rest.as_ref().map(|x| x.data.free_effects())) - }) - .unwrap_or_default(); - - let mut fvs = self - .ret - .as_ref() - .map(|x| x.1.data.free_variables()) - .unwrap_or_default(); - - for arg in &self.binders { - fvs.extend(arg.ty.data.free_variables()); - efvs.extend(arg.ty.data.free_effects()); - } - - let mut unbound = Vec::new(); - let mut effect_bounds = Vec::new(); - - for fv in fvs { - let ty = ctx.hole(&env, Type::typ()); - env = env.add(Some(fv.clone()), ty.clone()); - unbound.push((fv, ty.quote(env.level))); - } - - for fv in efvs { - let ty = ctx.lacks(&env, Default::default()); - env = env.add(Some(fv.clone()), ty.clone()); - effect_bounds.push((fv, ty.quote(env.level))); - } - - let mut args = Vec::new(); - - for arg in &self.binders { - let (ty, kind) = arg.ty.infer((ctx, env.clone())); - env.on(arg.ty.span.clone()); - - ctx.subsumes(env.clone(), kind, Kind::typ()); - - args.push(ty); - } - - let (effs, ret) = if let Some((eff, ret)) = &self.ret { - let effs = eff.infer((ctx, env.clone())); - - let (ty, kind) = ret.infer((ctx, env.clone())); - env.on(ret.span.clone()); - ctx.subsumes(env.clone(), kind, Kind::typ()); - - (effs, ty) - } else { - (Type::new(TypeKind::Empty), ctx.hole(&env, Kind::typ())) - }; - - let func_args = args.clone(); - - let ret_type = if has_effect { - let ty = args.pop().unwrap(); - Type::new(TypeKind::Arrow(Arrow { - ty, - effs: effs.clone(), - body: ret.clone(), - })) - } else { - ret.clone() - }; - - let mut typ = Type::::function(args.clone(), ret_type); - - for (name, _) in effect_bounds.clone() { - typ = Type::forall(Forall { - name, - kind: Type::row(), - body: typ, - }); - } - - for (name, kind) in unbound.clone() { - typ = Type::forall(Forall { - name, - kind, - body: typ, - }); - } - - ctx.modules.get(&self.name.path.clone()).variables.insert( - self.name.name.clone(), - LetDef { - typ: typ.eval(&env), - unbound, - ambient: effs, - unbound_effects: effect_bounds, - ret: ret.eval(&env), - args: func_args, - }, - ); - } - - fn define(&self, (ctx, mut env): (&mut Context, Env)) { - let let_decl = ctx.modules.let_decl(&self.name).clone(); - - for (fv, ty) in &let_decl.unbound { - env = env.add(Some(fv.clone()), ty.eval(&env).clone()); - } - - for (fv, ty) in &let_decl.unbound_effects { - env = env.add(Some(fv.clone()), ty.eval(&env).clone()); - } - - let mut binders = Default::default(); - let mut elab_binders = Vec::new(); - - for (binder, ty) in self.binders.iter().zip(let_decl.args.iter()) { - let pat = binder - .pattern - .check(ty.eval(&env), (ctx, &mut binders, env.clone())); - - elab_binders.push((pat, ty.clone())); - } - - for binder in binders { - env.add_var(binder.0, binder.1); - } - - let ty = let_decl.ret.clone(); - - let eval = let_decl.ambient.eval(&env); - - let binders = elab_binders; - - let effects = let_decl - .ambient - .eval(&env) - .effect_row_set() - .into_keys() - .collect(); - - let types = ty.arrow_spine(); - - ctx.errored = false; - - let body = self.body.check(ty, (ctx, eval, env.clone())); - - if !ctx.errored { - let problem = Problem::exhaustiveness(&body, types); - let patterns = &self.body.last().unwrap().patterns; - - if patterns.first().is_some() { - env.on(patterns - .first() - .unwrap() - .span - .clone() - .mix(patterns.last().unwrap().span.clone())); - - if let Witness::NonExhaustive(case) = problem.exaustive(ctx, env.clone()) { - ctx.report(&env, TypeErrorKind::NonExhaustive(case)); - }; - } - } - - ctx.elaborated.lets.insert( - self.name.clone(), - elaborated::LetDecl { - binders, - effects, - body, - }, - ); - } -} - -impl Declare for ModuleDecl { - fn declare(&self, (ctx, env): (&mut Context, Env)) { - self.decls.declare((ctx, env)); - } - - fn define(&self, (ctx, env): (&mut Context, Env)) { - self.decls.define((ctx, env)); - } -} - -impl Declare for Program { - fn declare(&self, (ctx, env): (&mut Context, Env)) { - self.modules.declare((ctx, env.clone())); - self.types.declare((ctx, env.clone())); - self.effects.declare((ctx, env.clone())); - self.lets.declare((ctx, env.clone())); - self.externals.declare((ctx, env)); - } - - fn define(&self, (ctx, env): (&mut Context, Env)) { - self.modules.define((ctx, env.clone())); - self.types.define((ctx, env.clone())); - self.effects.define((ctx, env.clone())); - self.lets.define((ctx, env.clone())); - self.externals.define((ctx, env)); - } -} - -pub struct TypeEnv { - pub context: Context, - pub env: Env, -} - -impl TypeEnv { - pub fn declare(&mut self, program: &Program) -> &mut Self { - program.declare((&mut self.context, self.env.clone())); - self - } - - pub fn define(&mut self, program: &Program) -> &mut Self { - program.define((&mut self.context, self.env.clone())); - self - } - - pub fn output(&mut self) -> elaborated::Program> { - std::mem::take(&mut self.context.elaborated) - } -} - -pub fn type_checker(reporter: Report) -> TypeEnv { - let context = Context::new(reporter); - let env = Env::default(); - - TypeEnv { context, env } -} diff --git a/crates/vulpi-typer/src/module.rs b/crates/vulpi-typer/src/module.rs deleted file mode 100644 index 31d0b74..0000000 --- a/crates/vulpi-typer/src/module.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Module for declaration of top level items inside the type checker. The main structure of this -//! module is the [Module] structure that is responsible for storing the types of the top level -//! items. - -use std::collections::HashMap; - -use vulpi_intern::Symbol; -use vulpi_syntax::{elaborated, r#abstract::Qualified}; - -use crate::{ - r#type::{r#virtual::Virtual, Effect, Type}, - Real, -}; - -#[derive(Clone)] -pub enum Def { - Enum(Vec), - Record(Vec), - Effect(Vec), - Type, -} - -#[derive(Clone)] -pub struct TypeData { - pub kind: Type, - pub binders: Vec<(Symbol, Type)>, - pub module: Symbol, - pub def: Def, -} - -#[derive(Clone)] -pub struct LetDef { - pub typ: Type, - pub unbound: Vec<(Symbol, Type)>, - pub args: Vec>, - pub ambient: Effect, - pub ret: Type, - pub unbound_effects: Vec<(Symbol, Type)>, -} - -#[derive(Default)] -pub struct Interface { - /// The types of the functions. - pub variables: HashMap, - - /// The types of the functions. - pub constructors: HashMap, usize, Qualified)>, - - /// The types of the types. - pub types: HashMap, - - /// The fields of the records. - pub fields: HashMap>, - - /// The effects of some symbols. - pub effects: HashMap, Qualified, usize)>, -} - -#[derive(Default)] -pub struct Modules { - /// The modules. - pub modules: HashMap, -} - -impl Modules { - pub fn new() -> Self { - Self { - modules: Default::default(), - } - } - - pub fn typ(&mut self, qualified: &Qualified) -> TypeData { - let module = self.get(&qualified.path); - module.types.get(&qualified.name).unwrap().clone() - } - - pub fn constructor(&mut self, qualified: &Qualified) -> (Type, usize, Qualified) { - let module = self.get(&qualified.path); - module.constructors.get(&qualified.name).unwrap().clone() - } - - pub fn effect(&mut self, qualified: &Qualified) -> (Type, Qualified, usize) { - let module = self.get(&qualified.path); - module.effects.get(&qualified.name).unwrap().clone() - } - - pub fn let_decl(&mut self, qualified: &Qualified) -> &mut LetDef { - let module = self.get(&qualified.path); - module.variables.get_mut(&qualified.name).unwrap() - } - - pub fn field(&mut self, qualified: &Qualified) -> Type { - let module = self.get(&qualified.path); - module.fields.get(&qualified.name).unwrap().clone() - } - - pub fn get(&mut self, id: &Symbol) -> &mut Interface { - self.modules.entry(id.clone()).or_default() - } -} diff --git a/crates/vulpi-typer/src/type/eval.rs b/crates/vulpi-typer/src/type/eval.rs deleted file mode 100644 index 6ab9ef7..0000000 --- a/crates/vulpi-typer/src/type/eval.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Module for evaluation and quotation of real and virtual [Type]s. The main difference between -//! the two is that virtual types contain closures and can be executed while real types are just -//! types. - -use super::{ - r#virtual, - r#virtual::Env, - r#virtual::Virtual, - real::{self, Real}, - Hole, HoleInner, Level, Type, TypeKind, -}; - -/// Trait for evaluation of types. -pub trait Eval { - fn eval(&self, env: &Env) -> T; -} - -impl Eval> for Type { - fn eval(&self, env: &Env) -> Type { - match self.as_ref() { - TypeKind::Arrow(pi) => Type::new(TypeKind::Arrow(r#virtual::Pi { - ty: pi.ty.clone().eval(env), - effs: pi.effs.clone().eval(env), - body: pi.body.clone().eval(env), - })), - TypeKind::Forall(f) => Type::new(TypeKind::Forall(r#virtual::Forall { - name: f.name.clone(), - kind: f.kind.clone().eval(env), - body: r#virtual::Closure { - env: env.clone(), - body: f.body.clone(), - }, - })), - TypeKind::Exists(f) => Type::new(TypeKind::Exists(r#virtual::Forall { - name: f.name.clone(), - kind: f.kind.clone().eval(env), - body: r#virtual::Closure { - env: env.clone(), - body: f.body.clone(), - }, - })), - TypeKind::Row => Type::new(TypeKind::Row), - TypeKind::Type => Type::new(TypeKind::Type), - TypeKind::Effect => Type::new(TypeKind::Effect), - TypeKind::Hole(r) => Type::new(TypeKind::Hole(r.clone())), - TypeKind::Variable(v) => Type::new(TypeKind::Variable(v.clone())), - TypeKind::Bound(v) => env.types[v.0].clone(), - TypeKind::Tuple(v) => Type::new(TypeKind::Tuple(v.clone().eval(env))), - TypeKind::Application(v, u) => Type::new(TypeKind::Application( - v.clone().eval(env), - u.clone().eval(env), - )), - TypeKind::Empty => Type::new(TypeKind::Empty), - TypeKind::Extend(l, t, u) => Type::new(TypeKind::Extend( - l.clone(), - t.clone().eval(env), - u.clone().eval(env), - )), - TypeKind::Error => Type::new(TypeKind::Error), - } - } -} - -impl Eval>> for Vec> { - fn eval(&self, env: &Env) -> Vec> { - self.iter().map(|v| v.eval(env)).collect() - } -} - -impl Eval> for Hole { - fn eval(&self, env: &Env) -> Type { - match &*self.0.borrow() { - HoleInner::Empty(s, k, l) => { - Type::new(TypeKind::Hole(Hole::empty(s.clone(), k.eval(env), *l))) - } - HoleInner::Row(s, l, r) => { - Type::new(TypeKind::Hole(Hole::row(s.clone(), *l, r.clone()))) - } - HoleInner::Filled(f) => f.clone().eval(env), - } - } -} - -/// Quotation of types. -pub trait Quote { - fn quote(&self, lvl: Level) -> T; -} - -impl Quote> for Hole { - fn quote(&self, depth: Level) -> Type { - match &*self.0.borrow() { - HoleInner::Empty(_, _, _) => Type::new(TypeKind::Hole(self.clone())), - HoleInner::Row(_, _, _) => Type::new(TypeKind::Hole(self.clone())), - HoleInner::Filled(f) => f.clone().quote(depth), - } - } -} - -impl Quote>> for Vec> { - fn quote(&self, lvl: Level) -> Vec> { - self.iter().map(|v| v.quote(lvl)).collect() - } -} - -impl Quote> for Type { - fn quote(&self, depth: Level) -> Type { - match self.as_ref() { - TypeKind::Type => Type::new(TypeKind::Type), - TypeKind::Row => Type::new(TypeKind::Row), - TypeKind::Effect => Type::new(TypeKind::Effect), - TypeKind::Arrow(pi) => Type::new(TypeKind::Arrow(real::Arrow { - ty: pi.ty.clone().quote(depth), - effs: pi.effs.clone().quote(depth), - body: pi.body.clone().quote(depth), - })), - TypeKind::Forall(f) => Type::new(TypeKind::Forall(real::Forall { - name: f.name.clone(), - kind: f.kind.clone().quote(depth), - body: f - .body - .apply_local(Some(f.name.clone()), Type::new(TypeKind::Bound(depth))) - .quote(depth.inc()), - })), - TypeKind::Exists(f) => Type::new(TypeKind::Exists(real::Forall { - name: f.name.clone(), - kind: f.kind.clone().quote(depth), - body: f - .body - .apply_local(Some(f.name.clone()), Type::new(TypeKind::Bound(depth))) - .quote(depth.inc()), - })), - - TypeKind::Hole(h) => h.quote(depth), - TypeKind::Variable(v) => Type::new(TypeKind::Variable(v.clone())), - TypeKind::Bound(i) => Type::new(TypeKind::Bound(Level::to_index(depth, *i))), - TypeKind::Tuple(p) => Type::new(TypeKind::Tuple(p.quote(depth))), - TypeKind::Application(func, arg) => { - let func = func.quote(depth); - let arg = arg.quote(depth); - Type::new(TypeKind::Application(func, arg)) - } - TypeKind::Empty => Type::new(TypeKind::Empty), - TypeKind::Extend(label, t, u) => Type::new(TypeKind::Extend( - label.clone(), - t.clone().quote(depth), - u.clone().quote(depth), - )), - TypeKind::Error => Type::new(TypeKind::Error), - } - } -} diff --git a/crates/vulpi-typer/src/type/mod.rs b/crates/vulpi-typer/src/type/mod.rs deleted file mode 100644 index 3e231de..0000000 --- a/crates/vulpi-typer/src/type/mod.rs +++ /dev/null @@ -1,761 +0,0 @@ -//! The definition of types for the Vulpi language. It includes a type called [Type] that defines -//! two types: A real and a virtual type. Both are used in the type system, but the virtual type -//! is only used in the type checker as a evaluated state. - -pub mod eval; -pub mod unify; - -use std::{cell::RefCell, hash::Hash, rc::Rc}; - -use im_rc::HashSet; -use vulpi_intern::Symbol; -use vulpi_syntax::r#abstract::Qualified; - -pub use r#virtual::Env; - -use crate::Virtual; - -/// The level of the type. It is used for type checking and type inference. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -pub struct Level(pub usize); - -/// The inverse of a the type. It is used for type checking and type inference. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Index(pub usize); - -impl Index { - pub fn shift(self, level: Level) -> Self { - Self(self.0 + level.0) - } -} - -impl Level { - /// Increment the level - pub fn inc(self) -> Self { - Self(self.0 + 1) - } - - /// Decrements the level. - pub fn dec(self) -> Self { - Self(self.0 - 1) - } - - /// Transforms a level into an index. - pub fn to_index(base: Level, current: Level) -> Index { - if base.0 < current.0 { - panic!( - "The base level is {} and the current level is {}", - base.0, current.0 - ) - } - Index(base.0 - current.0 - 1) - } - - pub fn from_index(base: Level, index: Index) -> Level { - Level(base.0 - index.0 - 1) - } -} - -/// The state of the type. It's used for diferentiating between the real and virtual type. -pub trait State { - type Pi; - type Forall; - type Type; - type Bound; -} - -/// The type kind is the type of types. It is used for type checking and type inference. -pub enum TypeKind { - /// The type of types - Type, - - /// The type of effects - Effect, - - /// The type of the rows - Row, - - /// The pi type is used for dependent functions. - Arrow(S::Pi), - - /// The forall type is used for polymorphic functions. - Forall(S::Forall), - - /// The forall type is used for polymorphic functions. - Exists(S::Forall), - - /// The type of holes. - Hole(Hole), - - /// Type for types that are defined by the user. - Variable(Qualified), - - /// De brujin indexed type. - Bound(S::Bound), - - /// The type for tuples. - Tuple(Vec), - - /// The type for type applications - Application(S::Type, S::Type), - - /// The type for empty rows in effect rows. - Empty, - - /// The type for extending rows in effect rows. - Extend(Qualified, S::Type, S::Type), - - /// A type error. - Error, -} - -/// The type of types. It is used for type checking and type inference. -#[derive(Clone)] -pub struct Type(Rc>); - -pub type Effect = Type; - -/// A type of a type is the same as a type! -pub type Kind = Type; - -impl Type { - pub fn new(kind: TypeKind) -> Self { - Self(Rc::new(kind)) - } - - /// Checks if the type is a row type. - pub fn is_row(&self) -> bool { - matches!(self.0.as_ref(), TypeKind::Row) - } - - pub fn is_empty(&self) -> bool { - matches!(self.0.as_ref(), TypeKind::Empty) - } - - pub(crate) fn forall(forall: S::Forall) -> Self { - Self::new(TypeKind::Forall(forall)) - } - - pub(crate) fn exists(forall: S::Forall) -> Self { - Self::new(TypeKind::Exists(forall)) - } - - pub(crate) fn typ() -> Type { - Type::new(TypeKind::Type) - } - - pub(crate) fn row() -> Type { - Type::new(TypeKind::Row) - } - - pub(crate) fn effect() -> Type { - Type::new(TypeKind::Effect) - } - - pub(crate) fn variable(name: Qualified) -> Type { - Type::new(TypeKind::Variable(name)) - } - - pub(crate) fn error() -> Type { - Type::new(TypeKind::Error) - } - - pub(crate) fn bound(level: S::Bound) -> Type { - Type::new(TypeKind::Bound(level)) - } - - pub(crate) fn tuple(types: Vec) -> Type { - Type::new(TypeKind::Tuple(types)) - } -} - -impl AsRef> for Type { - fn as_ref(&self) -> &TypeKind { - &self.0 - } -} - -/// The inside of a hole. It contains a Level in the Empty in order to avoid infinite loops and -/// the hole to go out of scope. -#[derive(Clone)] -pub enum HoleInner { - Empty(Symbol, Kind, Level), - Row(Symbol, Level, HashSet), - Filled(Type), -} - -/// A hole is a type that is not yet known. It is used for type inference. -#[derive(Clone)] -pub struct Hole(pub Rc>>); - -impl Hash for Hole { - fn hash(&self, state: &mut H) { - let s = (self.0.as_ptr()) as usize; - s.hash(state); - } -} - -impl PartialEq for Hole { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.0, &other.0) - } -} - -impl Eq for Hole {} - -impl Hole { - pub fn is_empty(&self) -> bool { - matches!(&*self.0.borrow(), HoleInner::Empty(_, _, _)) - } - - pub fn is_lacks(&self) -> bool { - matches!(&*self.0.borrow(), HoleInner::Row(_, _, _)) - } -} - -impl Hole { - pub fn new(hole_inner: HoleInner) -> Self { - Self(Rc::new(RefCell::new(hole_inner))) - } - - pub fn row(name: Symbol, level: Level, labels: HashSet) -> Self { - Self(Rc::new(RefCell::new(HoleInner::Row(name, level, labels)))) - } - - pub fn empty(name: Symbol, kind: Kind, level: Level) -> Self { - Self(Rc::new(RefCell::new(HoleInner::Empty(name, kind, level)))) - } - - pub fn fill(&self, ty: Type) { - *self.0.borrow_mut() = HoleInner::Filled(ty); - } -} - -pub mod r#virtual { - use std::{cell::RefCell, collections::HashMap}; - - use im_rc::HashSet; - use vulpi_intern::Symbol; - use vulpi_location::Span; - use vulpi_syntax::r#abstract::Qualified; - - use super::{eval::Eval, real::Real, Hole, HoleInner, Kind, Level, State, Type, TypeKind}; - - /// The virtual state is used as label for the [State] trait as a way to express that the type - /// contains closures and can be executed. - #[derive(Clone)] - pub struct Virtual; - - /// The typing environment is used for type checking and type inference. - #[derive(Clone, Default)] - pub struct Env { - pub names: im_rc::Vector>, - pub types: im_rc::Vector>, - pub kinds: im_rc::Vector>, - pub vars: im_rc::HashMap>, - pub level: Level, - pub span: RefCell, - } - - impl Env { - pub fn add_var(&mut self, name: Symbol, ty: Type) { - self.vars.insert(name, ty); - } - - /// Sets the location of the environment. It is used for error reporting. - pub fn on(&self, span: Span) { - *self.span.borrow_mut() = span; - } - - pub fn find(&self, name: &Symbol) -> Option<(usize, Type, Type)> { - self.names - .iter() - .zip(self.types.iter()) - .zip(self.kinds.iter()) - .enumerate() - .find_map(|(i, ((n, t), k))| { - if n.as_ref() == Some(name) { - Some((i, t.clone(), k.clone())) - } else { - None - } - }) - } - - /// Adds a type to the environment. - pub fn add(&self, name: Option, kind: Type) -> Self { - let mut clone = self.clone(); - clone.names.push_front(name); - clone.types.push_front(Type::bound(clone.level)); - clone.kinds.push_front(kind); - clone.level = clone.level.inc(); - clone - } - - pub fn add_at_end(&self, name: Option, kind: Type) -> Self { - let mut clone = self.clone(); - clone.names.push_back(name); - clone.types.push_back(Type::bound(clone.level)); - clone.kinds.push_back(kind); - clone.level = clone.level.inc(); - clone - } - - pub fn define(&self, name: Option, ty: Type, kind: Type) -> Self { - let mut clone = self.clone(); - clone.names.push_front(name); - clone.types.push_front(ty); - clone.kinds.push_front(kind); - clone.level = clone.level.inc(); - clone - } - - pub fn hole(&self, kind: Kind, label: Symbol) -> Type { - Type::new(TypeKind::Hole(Hole::empty(label, kind, self.level))) - } - - pub fn lacks(&self, symbol: Symbol, hash_set: HashSet) -> Type { - Type::new(TypeKind::Hole(Hole::row(symbol, self.level, hash_set))) - } - } - - /// A simulation of a closure in a type. It contains the environment and the body of the closure. - pub struct Closure { - pub env: Env, - pub body: Type, - } - - impl Closure { - /// "Applies" a closure adding a new type to the environment and evaluating the body. - pub fn apply( - &self, - name: Option, - arg: Type, - kind: Type, - ) -> Type { - self.body.eval(&self.env.define(name, arg, kind)) - } - - pub fn apply_local(&self, name: Option, arg: Type) -> Type { - self.body.eval(&self.env.add(name, arg)) - } - } - - /// A pi type without binder. It's used for a bunch of things but not right now :> - pub struct Pi { - pub ty: Type, - pub effs: Type, - pub body: Type, - } - - /// A forall with binder so we can bind on types that have higher kinds and ranks. - pub struct Forall { - pub name: Symbol, - pub kind: Type, - pub body: Closure, - } - - impl State for Virtual { - type Pi = Pi; - type Forall = Forall; - type Type = Type; - type Bound = Level; - } - - impl Type { - pub(crate) fn application_spine(&self) -> (Self, Vec) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Application(left, right) = current.deref().as_ref() { - spine.push(right.clone()); - current = left.clone(); - } - - spine.reverse(); - - (current, spine) - } - - pub fn arrow_spine(&self) -> Vec { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Arrow(pi) = current.deref().as_ref() { - spine.push(pi.ty.clone()); - current = pi.body.clone(); - } - - spine.push(current); - - spine - } - - pub(crate) fn effect_row_set(&self) -> HashMap> { - match self.deref().as_ref() { - TypeKind::Extend(l, t, rest) => { - let mut map = rest.effect_row_set(); - map.insert(l.clone(), t.clone()); - map - } - _ => Default::default(), - } - } - - pub(crate) fn is_row_effect(&self) -> bool { - match self.deref().as_ref() { - TypeKind::Extend(_, _, _) => true, - TypeKind::Empty => true, - TypeKind::Hole(m) if m.is_lacks() => true, - _ => false, - } - } - - pub fn deref(&self) -> Type { - match self.as_ref() { - TypeKind::Hole(h) => match h.0.borrow().clone() { - HoleInner::Filled(ty) => ty.deref(), - _ => self.clone(), - }, - _ => self.clone(), - } - } - - pub fn application(left: Self, right: Vec) -> Self { - right - .into_iter() - .fold(left, |acc, x| Type::new(TypeKind::Application(acc, x))) - } - - pub fn extend(label: Qualified, ty: Type, typ: Type) -> Type { - Type::new(TypeKind::Extend(label, ty, typ)) - } - - pub(crate) fn row_spine(&self) -> (Option>, Vec<(Qualified, Self)>) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Extend(label, ty, rest) = current.as_ref() { - spine.push((label.clone(), ty.clone())); - current = rest.clone(); - } - - match current.as_ref() { - TypeKind::Empty => (None, spine), - TypeKind::Hole(e) => (Some(e.clone()), spine), - _ => (None, spine), - } - } - - pub(crate) fn function(right: Vec, ret: Self) -> Self { - right.into_iter().rev().fold(ret, |body, ty| { - Type::new(TypeKind::Arrow(Pi { - ty, - effs: Type::new(TypeKind::Empty), - body, - })) - }) - } - } -} - -pub mod real { - use std::fmt::Display; - - use crate::Virtual; - use vulpi_intern::Symbol; - use vulpi_show::Show as OShow; - - use vulpi_syntax::r#abstract::Qualified; - - use super::{ - eval::Quote, r#virtual::Env, Hole, HoleInner, Index, Level, State, Type, TypeKind, - }; - - /// The real state is used as label for the [State] trait as a way to express that the type - /// contains closures and can be executed. - #[derive(Clone)] - pub struct Real; - - /// A pi type without binder. It's used for a bunch of things but not right now :> - pub struct Arrow { - pub ty: Type, - pub effs: Type, - pub body: Type, - } - - /// A forall with binder so we can bind on types that have higher kinds and ranks. - pub struct Forall { - pub name: Symbol, - pub kind: Type, - pub body: Type, - } - - impl State for Real { - type Pi = Arrow; - type Forall = Forall; - type Type = Type; - type Bound = Index; - } - - /// Environment of names that is useful for pretty printing. - #[derive(Clone)] - struct NameEnv(im_rc::Vector>); - - impl From for NameEnv { - fn from(env: Env) -> Self { - Self(env.names) - } - } - - impl OShow for Type { - fn show(&self) -> vulpi_show::TreeDisplay { - vulpi_show::TreeDisplay::label("Type") - } - } - - impl Type { - pub(crate) fn application_spine(&self) -> (Self, Vec) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Application(left, right) = current.as_ref() { - spine.push(right.clone()); - current = left.clone(); - } - - spine.reverse(); - - (current, spine) - } - - pub(crate) fn forall_spine(&self) -> (Vec<(Symbol, Self)>, Self) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Forall(Forall { name, kind, body }) = current.as_ref() { - spine.push((name.clone(), kind.clone())); - current = body.clone(); - } - - (spine, current) - } - - pub(crate) fn exists_spine(&self) -> (Vec<(Symbol, Self)>, Self) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Exists(Forall { name, kind, body }) = current.as_ref() { - spine.push((name.clone(), kind.clone())); - current = body.clone(); - } - - (spine, current) - } - - pub fn arrow_spine(&self) -> Vec { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Arrow(pi) = current.as_ref() { - spine.push(pi.ty.clone()); - current = pi.body.clone(); - } - - spine.push(current); - - spine - } - - pub fn extend(label: Qualified, ty: Type, typ: Type) -> Type { - Type::new(TypeKind::Extend(label, ty, typ)) - } - - pub(crate) fn row_spine(&self) -> (Option, Vec<(Qualified, Self)>) { - let mut spine = Vec::new(); - let mut current = self.clone(); - - while let TypeKind::Extend(label, ty, rest) = current.as_ref() { - spine.push((label.clone(), ty.clone())); - current = rest.clone(); - } - - match current.as_ref() { - TypeKind::Empty => (None, spine), - _ => (Some(current), spine), - } - } - - pub(crate) fn application(left: Self, right: Vec) -> Self { - right - .into_iter() - .fold(left, |acc, x| Type::new(TypeKind::Application(acc, x))) - } - - pub(crate) fn function(right: Vec, ret: Self) -> Self { - right.into_iter().rev().fold(ret, |body, ty| { - Type::new(TypeKind::Arrow(Arrow { - ty, - effs: Type::new(TypeKind::Empty), - body, - })) - }) - } - } - - trait Formattable { - fn format(&self, env: &NameEnv, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result; - } - - impl Formattable for Hole { - fn format(&self, env: &NameEnv, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.0.borrow().clone() { - HoleInner::Empty(s, _, l) => write!(f, "^{}~{}", s.get(), l.0), - HoleInner::Row(s, _, _) => write!(f, "~{}", s.get()), - HoleInner::Filled(forall) => { - write!(f, "!")?; - forall.quote(Level(env.0.len())).format(env, f) - } - } - } - } - - impl Formattable for Type { - fn format(&self, env: &NameEnv, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.as_ref() { - TypeKind::Row => write!(f, "Row"), - TypeKind::Type => write!(f, "Type"), - TypeKind::Effect => write!(f, "Effect"), - TypeKind::Arrow(pi) => { - write!(f, "(")?; - pi.ty.format(env, f)?; - write!(f, " -> ")?; - - match pi.effs.as_ref() { - TypeKind::Empty => (), - _ => { - write!(f, "{{")?; - pi.effs.format(env, f)?; - write!(f, "}} ")?; - } - } - - pi.body.format(env, f)?; - write!(f, ")") - } - TypeKind::Forall(_) => { - let mut env = env.clone(); - write!(f, "(forall ")?; - - let (binder, rest) = self.forall_spine(); - - for (i, (name, kind)) in binder.iter().enumerate() { - write!(f, "({}: ", name.get())?; - kind.format(&env, f)?; - write!(f, ")")?; - if i != binder.len() - 1 { - write!(f, " ")?; - } - env.0.push_front(Some(name.clone())) - } - - write!(f, ". ")?; - - rest.format(&env, f)?; - - write!(f, ")") - } - TypeKind::Exists(_) => { - let mut env = env.clone(); - write!(f, "(exists ")?; - - let (binder, rest) = self.exists_spine(); - - for (i, (name, kind)) in binder.iter().enumerate() { - write!(f, "({}: ", name.get())?; - kind.format(&env, f)?; - write!(f, ")")?; - if i != binder.len() - 1 { - write!(f, " ")?; - } - env.0.push_front(Some(name.clone())) - } - - write!(f, ". ")?; - - rest.format(&env, f)?; - - write!(f, ")") - } - TypeKind::Hole(hole) => hole.format(env, f), - TypeKind::Variable(n) => write!(f, "{}", n.name.get()), - TypeKind::Bound(n) => { - write!( - f, - "{}~{}", - env.0[n.0] - .clone() - .unwrap_or(Symbol::intern(&format!("_{}", n.0))) - .get(), - n.0 - ) - } - TypeKind::Tuple(t) => { - write!(f, "(")?; - for (i, ty) in t.iter().enumerate() { - ty.format(env, f)?; - if i != t.len() - 1 { - write!(f, ", ")?; - } - } - write!(f, ")") - } - TypeKind::Application(_, _) => { - let (p, args) = self.application_spine(); - write!(f, "(")?; - p.format(env, f)?; - for arg in args { - write!(f, " ")?; - arg.format(env, f)?; - } - write!(f, ")") - } - TypeKind::Empty => write!(f, "{{}}"), - TypeKind::Extend(_, _, _) => { - let (last, args) = self.row_spine(); - - for (i, (_, e)) in args.iter().enumerate() { - e.format(env, f)?; - if i != args.len() - 1 { - write!(f, ", ")?; - } - } - - if let Some(last) = last { - write!(f, " | ")?; - last.format(env, f)?; - } - - Ok(()) - } - TypeKind::Error => write!(f, ""), - } - } - } - - impl Type { - /// Function that generates a [Show] object responsible for the pretty printing of the type. - pub fn show(&self, env: &Env) -> Show { - Show(self.clone(), env.clone().into()) - } - } - - /// A interface to show types with the correct names. - pub struct Show(Type, NameEnv); - - impl Display for Show { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.format(&self.1, f) - } - } -} diff --git a/crates/vulpi-typer/src/type/unify.rs b/crates/vulpi-typer/src/type/unify.rs deleted file mode 100644 index ffacdc3..0000000 --- a/crates/vulpi-typer/src/type/unify.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! Module for unication and subsumption of types. - -#![allow(clippy::only_used_in_recursion)] - -use im_rc::HashSet; -use vulpi_syntax::r#abstract::Qualified; - -use crate::{context::Context, errors::TypeErrorKind}; - -use super::{ - eval::Quote, - r#virtual::Pi, - r#virtual::{Env, Virtual}, - Hole, HoleInner, Level, Type, TypeKind, -}; - -type Result = std::result::Result; - -impl Context { - pub fn subsumes(&mut self, env: Env, left: Type, right: Type) { - fn go(ctx: &mut Context, env: Env, left: Type, right: Type) -> Result { - let l = left.deref(); - let r = right.deref(); - - match (l.as_ref(), r.as_ref()) { - (TypeKind::Hole(n), _) if n.is_empty() => { - ctx.sub_hole_type(env, n.clone(), r.clone()) - } - (_, TypeKind::Hole(n)) if n.is_empty() => { - ctx.sub_type_hole(env, l.clone(), n.clone()) - } - (TypeKind::Arrow(m), TypeKind::Arrow(n)) => { - // Change due to variance. - go(ctx, env.clone(), n.ty.clone(), m.ty.clone())?; - go(ctx, env.clone(), m.effs.clone(), n.effs.clone())?; - go(ctx, env, m.body.clone(), n.body.clone()) - } - (_, TypeKind::Forall(forall)) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - go( - ctx, - env.add(None, lvl_ty.clone()), - l.clone(), - forall.body.apply_local(None, lvl_ty), - ) - } - (TypeKind::Forall(_), _) => { - let instantiated = ctx.instantiate(&env, &l); - go(ctx, env, instantiated, r.clone()) - } - (_, _) => ctx.unify(env, l, r), - } - } - - let result = go(self, env.clone(), left.clone(), right.clone()); - - if let Err(kind) = result { - match kind { - TypeErrorKind::TypeMismatch(_, _, _) => { - if left.is_row_effect() && right.is_row_effect() { - let left = left.effect_row_set(); - let right = right.effect_row_set(); - - let left_set = left.keys().cloned().collect::>(); - let right_set = right.keys().cloned().collect::>(); - - let difference = right_set.difference(left_set); - - let effects = difference - .iter() - .map(|x| { - left.get(x) - .or_else(|| right.get(x)) - .unwrap() - .quote(env.level) - }) - .collect::>(); - - self.report( - &env, - TypeErrorKind::AmbientDoesNotContainEffects(env.clone(), effects), - ) - } else { - self.report( - &env, - TypeErrorKind::TypeMismatch( - env.clone(), - left.quote(env.level), - right.quote(env.level), - ), - ) - } - } - _ => self.report(&env, kind), - } - } - } - - fn sub_hole_type(&mut self, env: Env, left: Hole, right: Type) -> Result { - match right.deref().as_ref() { - TypeKind::Forall(forall) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - self.sub_hole_type( - env.add(Some(forall.name.clone()), lvl_ty.clone()), - left, - forall.body.apply_local(None, lvl_ty), - ) - } - TypeKind::Arrow(pi) => { - let HoleInner::Empty(_, kind, _) = left.0.borrow().clone() else { unreachable!() }; - - let hole_a = self.hole(&env, kind.clone()); - let hole_b = self.hole(&env, kind); - - left.fill(Type::new(TypeKind::Arrow(Pi { - ty: hole_a.clone(), - effs: pi.effs.clone(), - body: hole_b.clone(), - }))); - - let a = pi.ty.clone(); - let b = pi.body.clone(); - - let TypeKind::Hole(hole_a) = hole_a.as_ref() else { unreachable!() }; - let TypeKind::Hole(hole_b) = hole_b.as_ref() else { unreachable!() }; - - self.sub_type_hole(env.clone(), a, hole_a.clone())?; - self.sub_hole_type(env, hole_b.clone(), b) - } - _ => self.unify_hole(env, left, right), - } - } - - fn sub_type_hole(&mut self, env: Env, left: Type, right: Hole) -> Result { - let deref = &left.deref(); - match deref.as_ref() { - TypeKind::Forall(_) => { - let left = self.instantiate(&env, deref); - self.sub_type_hole(env, left, right) - } - TypeKind::Arrow(pi) => { - let HoleInner::Empty(_, kind, _) = right.0.borrow().clone() else { unreachable!() }; - - let hole_a = self.hole(&env, kind.clone()); - let hole_b = self.hole(&env, kind); - - right.fill(Type::new(TypeKind::Arrow(Pi { - ty: hole_a.clone(), - effs: pi.effs.clone(), - body: hole_b.clone(), - }))); - - let a = pi.ty.clone(); - let b = pi.body.clone(); - - let TypeKind::Hole(hole_a) = hole_a.as_ref() else { unreachable!() }; - let TypeKind::Hole(hole_b) = hole_b.as_ref() else { unreachable!() }; - - self.sub_hole_type(env.clone(), hole_a.clone(), a)?; - self.sub_type_hole(env, b, hole_b.clone()) - } - _ => self.unify_hole(env, right, left), - } - } - - fn unify(&mut self, env: Env, left: Type, right: Type) -> Result { - let l = left.deref(); - let r = right.deref(); - match (l.as_ref(), r.as_ref()) { - (TypeKind::Tuple(x), TypeKind::Tuple(y)) if x.len() == y.len() => x - .iter() - .zip(y.iter()) - .try_for_each(|(x, y)| self.unify(env.clone(), x.clone(), y.clone())), - (TypeKind::Application(f, a), TypeKind::Application(g, b)) => { - self.unify(env.clone(), f.clone(), g.clone())?; - self.unify(env, a.clone(), b.clone()) - } - (TypeKind::Extend(label, field_ty, row_tail), TypeKind::Extend(_, _, _)) => { - let (field_ty1, row_tail1) = self.rewrite_row(env.clone(), right, label.clone())?; - // TODO: Check recursive row types - self.unify(env.clone(), field_ty.clone(), field_ty1)?; - self.unify(env, row_tail.clone(), row_tail1) - } - (TypeKind::Hole(n), TypeKind::Hole(m)) if n == m => Ok(()), - (TypeKind::Hole(m), _) => self.unify_hole(env, m.clone(), r), - (_, TypeKind::Hole(m)) => self.unify_hole(env, m.clone(), l), - (TypeKind::Bound(x), TypeKind::Bound(y)) if x == y => Ok(()), - (TypeKind::Variable(x), TypeKind::Variable(y)) if x == y => Ok(()), - (TypeKind::Empty, TypeKind::Empty) => Ok(()), - (TypeKind::Exists(ex), _) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - self.unify( - env.add(Some(ex.name.clone()), lvl_ty.clone()), - ex.body.apply_local(None, lvl_ty), - right, - ) - } - (_, TypeKind::Exists(ex)) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - self.unify( - env.add(Some(ex.name.clone()), lvl_ty.clone()), - left, - ex.body.apply_local(None, lvl_ty), - ) - } - (TypeKind::Type, TypeKind::Type) => Ok(()), - (TypeKind::Effect, TypeKind::Effect) => Ok(()), - (TypeKind::Error, _) | (_, TypeKind::Error) => Ok(()), - (_, _) => Err(TypeErrorKind::TypeMismatch( - env.clone(), - left.quote(env.level), - right.quote(env.level), - )), - } - } - - fn occurs(&self, env: Env, scope: &Level, hole: Hole, ty: Type) -> Result { - match ty.deref().as_ref() { - TypeKind::Arrow(pi) => { - self.occurs(env.clone(), scope, hole.clone(), pi.ty.clone())?; - self.occurs(env.clone(), scope, hole.clone(), pi.effs.clone())?; - self.occurs(env, scope, hole, pi.body.clone()) - } - TypeKind::Forall(forall) => { - let lvl_ty = Type::new(TypeKind::Bound(env.level)); - self.occurs(env, scope, hole, forall.body.apply_local(None, lvl_ty)) - } - TypeKind::Hole(h) if h.clone() == hole => Err(TypeErrorKind::InfiniteType), - TypeKind::Bound(l) if l >= scope => Err(TypeErrorKind::EscapingScope), - TypeKind::Tuple(t) => t - .iter() - .try_for_each(|t| self.occurs(env.clone(), scope, hole.clone(), t.clone())), - TypeKind::Application(f, a) => { - self.occurs(env.clone(), scope, hole.clone(), f.clone())?; - self.occurs(env, scope, hole, a.clone()) - } - TypeKind::Extend(_, t, p) => { - self.occurs(env.clone(), scope, hole.clone(), t.clone())?; - self.occurs(env, scope, hole, p.clone()) - } - _ => Ok(()), - } - } - - fn unify_hole(&mut self, env: Env, hole: Hole, right: Type) -> Result { - let borrow = hole.0.borrow().clone(); - match borrow { - HoleInner::Empty(_, _, lvl) => match right.deref().as_ref() { - TypeKind::Hole(hole1) if hole == hole1.clone() => Ok(()), - _ => { - self.occurs(env, &lvl, hole.clone(), right.clone())?; - hole.fill(right); - Ok(()) - } - }, - HoleInner::Row(_, _, ls1) => match right.deref().as_ref() { - TypeKind::Hole(hole1) if hole == hole1.clone() => Ok(()), - TypeKind::Hole(hole1) if hole1.is_lacks() => { - let HoleInner::Row(_, _, ls) = hole1.0.borrow().clone() else { unreachable!() }; - let union = ls.union(ls1); - - let typ = self.lacks(&env, union); - hole.fill(typ.clone()); - hole1.fill(typ); - - Ok(()) - } - _ => self.unify_row(env, hole, right), - }, - HoleInner::Filled(f) => self.unify(env, f, right), - } - } - - fn unify_row(&mut self, env: Env, hole: Hole, right: Type) -> Result { - let HoleInner::Row(_, _, ls) = hole.0.borrow().clone() else { unreachable!() }; - let (mv, ls1) = right.row_spine(); - let ls1 = ls1.into_iter().map(|x| x.0).collect::>(); - - let binding = ls1.intersection(ls.clone()); - let labels = binding.into_iter().collect::>(); - - if labels.is_empty() { - if let Some(hole1) = mv { - let HoleInner::Row(_, _, r1) = hole.0.borrow().clone() else { unreachable!() }; - let c = r1.union(ls); - let lacks = self.lacks(&env, c); - hole1.fill(lacks); - } - hole.fill(right); - Ok(()) - } else { - Err(TypeErrorKind::InvalidLabels(labels)) - } - } - - fn rewrite_row( - &mut self, - env: Env, - typ: Type, - n_lab: Qualified, - ) -> Result<(Type, Type)> { - match typ.deref().as_ref() { - TypeKind::Empty => Err(TypeErrorKind::MissingLabel(n_lab)), - TypeKind::Extend(label, field, res) => { - if label.clone() == n_lab { - return Ok((field.clone(), res.clone())); - } - - match res.deref().as_ref() { - TypeKind::Hole(h) if h.is_lacks() => { - let beta = self.lacks(&env, vec![n_lab.clone()].into_iter().collect()); - let gamma = self.hole(&env, Type::new(TypeKind::Effect)); - - self.unify_row( - env, - h.clone(), - Type::::extend(n_lab, gamma.clone(), beta.clone()), - )?; - - Ok(( - gamma, - Type::::extend(label.clone(), field.clone(), beta), - )) - } - _ => { - let (field_ty, rest) = self.rewrite_row(env.clone(), res.clone(), n_lab)?; - - Ok(( - field_ty, - Type::::extend(label.clone(), field.clone(), rest), - )) - } - } - } - _ => unreachable!(), - } - } -} diff --git a/crates/vulpi-vfs/Cargo.toml b/crates/vulpi-vfs/Cargo.toml index 210cf52..8660470 100644 --- a/crates/vulpi-vfs/Cargo.toml +++ b/crates/vulpi-vfs/Cargo.toml @@ -6,4 +6,3 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vulpi-location = { path = "../vulpi-location" } diff --git a/crates/vulpi-vfs/src/lib.rs b/crates/vulpi-vfs/src/lib.rs index 4352861..677b293 100644 --- a/crates/vulpi-vfs/src/lib.rs +++ b/crates/vulpi-vfs/src/lib.rs @@ -1,30 +1,9 @@ -//! Virtual file system for the compiler. It's used to store the source code of the files that are -//! being compiled. - -use std::path::PathBuf; - -use vulpi_location::FileId; - pub mod real; -#[derive(Debug)] -pub enum Error { - NotFound(PathBuf), - NotFoundId, - AlreadyExists, -} - -/// A virtual file system trait that can be implemented by the user. It's used to store the source -/// code of the files that are being compiled and to store the compiled modules. -pub trait FileSystem { - fn load(&mut self, path: Path) -> Result; - fn unload(&mut self, id: FileId) -> Result<(), Error>; - fn path(&self, id: FileId) -> Result<&Path, Error>; - - fn store(&mut self, id: FileId, content: String) -> Result<(), Error>; - fn read(&self, id: FileId) -> Result<&Content, Error>; +use std::error::Error; - fn create(&mut self, path: Path) -> Result; - fn write(&mut self, id: FileId) -> Result<(), Error>; - fn delete(&mut self, id: FileId) -> Result<(), Error>; -} +pub trait FileSystem { + type Path; + fn write(&self, path: Self::Path, content: Vec); + fn read(&self, path: Self::Path) -> Result, Box>; +} \ No newline at end of file diff --git a/crates/vulpi-vfs/src/real.rs b/crates/vulpi-vfs/src/real.rs index f83111b..797e66a 100644 --- a/crates/vulpi-vfs/src/real.rs +++ b/crates/vulpi-vfs/src/real.rs @@ -1,107 +1,16 @@ -use std::{collections::HashMap, fs, path::PathBuf}; +use std::{path, fs}; -use vulpi_location::FileId; +use crate::FileSystem; -use super::{Error, FileSystem}; - -pub struct RealFileSystem { - root: PathBuf, - file_map: HashMap, - path_map: HashMap, - counter: usize, -} - -impl RealFileSystem { - pub fn new(root: PathBuf) -> Self { - Self { - root, - file_map: HashMap::new(), - path_map: HashMap::new(), - counter: 0, - } - } - - pub fn get_path(&self, path: PathBuf) -> Result { - let path = &self.root.clone().join(path); - path.canonicalize() - .map_err(|_| Error::NotFound(path.clone())) - } -} - -impl FileSystem for RealFileSystem { - fn load(&mut self, path: PathBuf) -> Result { - let path = self.get_path(path)?; - - if let Some(id) = self.path_map.get(&path) { - return Ok(*id); - } - - let content = - fs::read_to_string(path.clone()).map_err(|_| Error::NotFound(path.clone()))?; - - let id = FileId(self.counter); - self.counter += 1; - - let content = (path.clone(), content); - - self.file_map.insert(id, content); - self.path_map.insert(path, id); - - Ok(id) - } - - fn unload(&mut self, id: FileId) -> Result<(), Error> { - self.file_map.remove(&id).ok_or(Error::NotFoundId)?; - Ok(()) - } - - fn store(&mut self, id: FileId, content: String) -> Result<(), Error> { - let file = self.file_map.get_mut(&id).ok_or(Error::NotFoundId)?; - *file = (file.0.clone(), content); - Ok(()) - } - - fn read(&self, id: FileId) -> Result<&String, Error> { - let file = self.file_map.get(&id).ok_or(Error::NotFoundId)?; - Ok(&file.1) - } - - fn create(&mut self, path: PathBuf) -> Result { - let path = self.get_path(path)?; - - if path.exists() { - return Err(Error::AlreadyExists); - } - - let id = FileId(self.counter); - self.counter += 1; - - self.file_map.insert(id, (path.clone(), String::new())); - self.path_map.insert(path, id); - - Ok(id) - } - - fn write(&mut self, id: FileId) -> Result<(), Error> { - if let Some((path, content)) = self.file_map.get(&id) { - fs::write(path, content).map_err(|_| Error::NotFound(path.clone()))?; - Ok(()) - } else { - Err(Error::NotFoundId) - } - } - - fn delete(&mut self, id: FileId) -> Result<(), Error> { - if let Some((path, _)) = self.file_map.get(&id) { - fs::remove_file(path).map_err(|_| Error::NotFound(path.clone()))?; - Ok(()) - } else { - Err(Error::NotFoundId) - } +pub struct RealFileSystem; +impl FileSystem for RealFileSystem { + type Path = path::PathBuf; + + fn write(&self, path: Self::Path, content: Vec) { + fs::write(path, content).unwrap(); } - fn path(&self, id: FileId) -> Result<&PathBuf, Error> { - let file = self.file_map.get(&id).ok_or(Error::NotFoundId)?; - Ok(&file.0) + fn read(&self, path: Self::Path) -> Result, Box> { + fs::read(path).map_err(|_| "Cannot read".into()) } -} +} \ No newline at end of file diff --git a/images/logo.png b/images/logo.png deleted file mode 100644 index 99d2257..0000000 Binary files a/images/logo.png and /dev/null differ