diff --git a/Cargo.lock b/Cargo.lock index c48af1eaf87bb222c935a64f7ce1ddf8fc6df455..54f370fcb5920bb7db473bea9baf8e7369887d1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,47 +13,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys", @@ -61,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "atomic-polyfill" @@ -76,9 +77,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" @@ -142,9 +143,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfgrammar" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829b900c3abfb519f93fe713765625385117372cc83b9c68c22d3d8807d89440" +checksum = "163348850b1cd34fa99ef1592b5d598ea7e6752f18aff2125b67537e887edb36" dependencies = [ "indexmap", "lazy_static", @@ -202,9 +203,9 @@ checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "critical-section" @@ -268,9 +269,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -288,9 +289,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heapless" @@ -405,6 +406,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itoa" version = "1.0.11" @@ -421,7 +428,10 @@ dependencies = [ "hercules_opt", "lrlex", "lrpar", + "num-rational", + "num-traits", "ordered-float", + "phf", ] [[package]] @@ -432,9 +442,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "lock_api" @@ -448,9 +458,9 @@ dependencies = [ [[package]] name = "lrlex" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd189d9a727faaf7ec012bb2939f5c843aee894d02715e97c2882c2d2e96093" +checksum = "77ff18e1bd3ed77d7bc2800a0f8b0e922a3c7ba525505be8bab9cf45dfc4984b" dependencies = [ "cfgrammar", "getopts", @@ -459,16 +469,16 @@ dependencies = [ "num-traits", "quote", "regex", - "regex-syntax 0.7.5", + "regex-syntax", "serde", "vergen", ] [[package]] name = "lrpar" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca23a8fd40ca43869fa8e6cf5e4d87c3fce88d21a109f7e07126ebd8369b494" +checksum = "efea5a41b9988b5ae41ea9b2375a52cfa0e483f0210357209caa8d361a24a368" dependencies = [ "bincode", "cactus", @@ -488,9 +498,9 @@ dependencies = [ [[package]] name = "lrtable" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee337773c4a85c7a270fbc4ca500ece4abb288cd9c3ac60f642441b96b9f53a7" +checksum = "ff5668c3bfd279ed24d5b0d24568c48dc993f9beabd51f74d1865a78c1d206ab" dependencies = [ "cfgrammar", "fnv", @@ -502,9 +512,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "minimal-lexical" @@ -522,17 +532,48 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -565,6 +606,48 @@ dependencies = [ "serde", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "postcard" version = "1.0.8" @@ -591,18 +674,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -661,7 +744,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] @@ -672,15 +755,9 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.3" @@ -710,9 +787,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "scopeguard" @@ -722,30 +799,36 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "sparsevec" version = "0.2.0" @@ -781,15 +864,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.55" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -810,9 +893,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -833,9 +916,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -849,9 +932,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "utf8parse" @@ -898,13 +981,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -913,45 +997,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "wyz" diff --git a/juno_frontend/Cargo.toml b/juno_frontend/Cargo.toml index 2332cfea777b3fdf4d64a4a45c925ce771c022f6..31d938ed271dd5e3c6bcb54db79e34c90a1e89f0 100644 --- a/juno_frontend/Cargo.toml +++ b/juno_frontend/Cargo.toml @@ -19,5 +19,8 @@ cfgrammar = "0.13" lrlex = "0.13" lrpar = "0.13" ordered-float = "*" +num-rational = "*" +num-traits = "*" +phf = { version = "0.11", features = ["macros"] } hercules_ir = { path = "../hercules_ir" } hercules_opt = { path = "../hercules_opt" } diff --git a/juno_frontend/examples/cava.jn b/juno_frontend/examples/cava.jn index ea2b65e1842afe439808c750d0125895c30ddc16..6c5bdfe9085c77585c34ae5c3fdc4a988ebd8729 100644 --- a/juno_frontend/examples/cava.jn +++ b/juno_frontend/examples/cava.jn @@ -52,7 +52,7 @@ fn descale<row : usize, col : usize>(input : f32[CHAN, row, col]) -> u8[CHAN, ro for chan = 0 to CHAN { for r = 0 to row { for c = 0 to col { - res[chan, r, c] = min(max(input[chan, r, c] * 255, 0), 255) as u8; + res[chan, r, c] = min::<f32>(max::<f32>(input[chan, r, c] * 255, 0), 255) as u8; } } } @@ -66,10 +66,10 @@ fn demosaic<row : usize, col : usize>(input : f32[CHAN, row, col]) -> f32[CHAN, for r = 1 to row-1 { for c = 1 to col-1 { if r % 2 == 0 && col % 2 == 0 { - let R1 : f32 = input[0, r, c-1]; - let R2 : f32 = input[0, r, c+1]; - let B1 : f32 = input[2, r-1, c]; - let B2 : f32 = input[2, r+1, c]; + let R1 = input[0, r, c-1]; + let R2 = input[0, r, c+1]; + let B1 = input[2, r-1, c]; + let B2 = input[2, r+1, c]; res[0, r, c] = (R1 + R2) / 2; res[1, r, c] = input[1, r, c] * 2; res[2, r, c] = (B1 + B2) / 2; @@ -125,7 +125,7 @@ fn denoise<row : usize, col : usize>(input : f32[CHAN, row, col]) -> f32[CHAN, r filter[i+1, j+1] = input[chan, r + i, c + j]; } } - result[chan, r, c] = medianMatrix(filter); + res[chan, r, c] = medianMatrix::<f32, 3, 3>(filter); } else { res[chan, r, c] = input[chan, r, c]; } @@ -144,9 +144,11 @@ fn transform<row : usize, col : usize> for chan = 0 to CHAN { for r = 0 to row { for c = 0 to col { - result[chan, r, c] = max(input[0, r, c] * tstw_trans[0, chan] - + input[1, r, c] * tstw_trans[1, chan] - + input[2, r, c] * tstw_trans[2, chan], 0); + result[chan, r, c] = max::<f32>( + input[0, r, c] * tstw_trans[0, chan] + + input[1, r, c] * tstw_trans[1, chan] + + input[2, r, c] * tstw_trans[2, chan] + , 0); } } } @@ -163,11 +165,11 @@ fn gamut<row : usize, col : usize> for r = 0 to row { for c = 0 to col { for cp = 0 to CTRL_PTS { - let v1 : f32 = input[0, r, c] - ctrl_pts[cp, 0]; - let v2 : f32 = input[1, r, c] - ctrl_pts[cp, 1]; - let v3 : f32 = input[2, r, c] - ctrl_pts[cp, 2]; - let v : f32 = v1 * v1 + v2 * v2 + v3 * v3; - l2_dist[cp] = math::sqrt(v); // NOTE: Somehow some libraries will likely have to be external + let v1 = input[0, r, c] - ctrl_pts[cp, 0]; + let v2 = input[1, r, c] - ctrl_pts[cp, 1]; + let v3 = input[2, r, c] - ctrl_pts[cp, 2]; + let v = v1 * v1 + v2 * v2 + v3 * v3; + l2_dist[cp] = sqrt!::<f32>(v); } for chan = 0 to CHAN { @@ -179,7 +181,7 @@ fn gamut<row : usize, col : usize> chan_val += coefs[0, chan] + coefs[1, chan] * input[0, r, c] + coefs[2, chan] * input[1, r, c] + coefs[3, chan] * input[2, r, c]; - result[chan, row, col] = max(chan_val, 0); + result[chan, row, col] = max::<f32>(chan_val, 0); } } } @@ -195,7 +197,7 @@ fn tone_map<row : usize, col:usize> for r = 0 to row { for c = 0 to col { let x = (input[chan, r, c] * 255) as u8; - result[chan, r, c] = tone_map[x, chan]; + result[chan, r, c] = tone_map[x as usize, chan]; } } } @@ -205,14 +207,14 @@ fn tone_map<row : usize, col:usize> fn cava<r, c : usize>(input : u8[CHAN, r, c], TsTw : f32[CHAN, CHAN], ctrl_pts : f32[CTRL_PTS, CHAN], - weights : f32[CTRl_PTHS, CHAN], - coefs : f32[4, CHAN], tone_map : f32[255, CHAN]) - -> u8[CHAN, row, col] { + weights : f32[CTRL_PTS, CHAN], + coefs : f32[4, CHAN], tonemap : f32[255, CHAN]) + -> u8[CHAN, r, c] { let scaled = scale::<r, c>(input); let demosc = demosaic::<r, c>(scaled); let denosd = denoise::<r, c>(demosc); let transf = transform::<r, c>(denosd, TsTw); let gamutd = gamut::<r, c>(transf, ctrl_pts, weights, coefs); - let tonemd = tone_map::<r, c>(gamutd, tone_map); + let tonemd = tone_map::<r, c>(gamutd, tonemap); return descale::<r, c>(tonemd); } diff --git a/juno_frontend/src/codegen.rs b/juno_frontend/src/codegen.rs index c48c188e9ad96e177cff1d85e7ff6e285a9fba79..d7821c95658fef671ba40f135685bc89f437af97 100644 --- a/juno_frontend/src/codegen.rs +++ b/juno_frontend/src/codegen.rs @@ -271,10 +271,10 @@ impl CodeGenerator<'_> { (ssa.read_variable(*var, cur_block, &mut self.builder), cur_block) }, - Expr::DynConst { idx, .. } => { + Expr::DynConst { val, .. } => { let mut node = self.builder.allocate_node(func_id); let node_id = node.id(); - let dyn_const = self.builder.create_dynamic_constant_parameter(*idx); + let dyn_const = val.build(&mut self.builder); node.build_dynamicconstant(dyn_const); let _ = self.builder.add_node(node); (node_id, cur_block) @@ -496,6 +496,9 @@ impl CodeGenerator<'_> { (read_id, block) }, + Expr::Intrinsic { .. } => { + todo!("intrinsic function codegen") + }, } } diff --git a/juno_frontend/src/dynconst.rs b/juno_frontend/src/dynconst.rs new file mode 100644 index 0000000000000000000000000000000000000000..2fcd637fb8aee2fbb7feebe334085301d4cd8380 --- /dev/null +++ b/juno_frontend/src/dynconst.rs @@ -0,0 +1,300 @@ +/* A data structure for normalizing and performing computation over dynamic constant expressions */ +use std::collections::HashMap; +use std::fmt; +use hercules_ir::{Builder, DynamicConstantID}; + +use num_rational::Ratio; +use num_traits::identities::{Zero, One}; + +// A dynamic constant is represented as a map from a vector of the powers of the variables to the +// coefficient for that term +#[derive(Eq, Clone)] +pub struct DynConst { + terms : HashMap<Vec<i64>, Ratio<i64>>, + vars : usize, +} + +// Two dynamic constants are equal if all terms in each polynomial with non-zero +// coefficients have an equivalent term in the other polynomial +impl PartialEq for DynConst { + fn eq(&self, other : &Self) -> bool { + if self.vars != other.vars { return false; } + + for (t, c) in self.terms.iter() { + if !c.is_zero() { + if let Some(q) = other.terms.get(t) { + if c != q { return false; } + } else { + return false; + } + } + } + + for (t, c) in other.terms.iter() { + if !c.is_zero() { + if let Some(q) = other.terms.get(t) { + if c != q { return false; } + } else { + return false; + } + } + } + + return true; + } +} + +impl fmt::Debug for DynConst { + fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.to_string(&|i| format!("v{}", i))) + } +} + +impl DynConst { + // Construct a dynamic constant whose value is a constant integer + pub fn constant(val : i64, num_dyn : usize) -> DynConst { + Self::constant_ratio(Ratio::from_integer(val), num_dyn) + } + + // Construct a dynamic constant whose value is a constant rational value + pub fn constant_ratio(val : Ratio<i64>, num_dyn : usize) -> DynConst { + // Create the vector of powers for each variable, all these powers are + // just 0 + let powers = vec![0; num_dyn]; + DynConst { + terms : HashMap::from([(powers, val)]), + vars : num_dyn, + } + } + + // Construct the zero dynamic constant + pub fn zero(dc : &DynConst) -> DynConst { + Self::constant(0, dc.vars) + } + + // Construct the dynamic constant value for a single particular dynamic + // constant + pub fn dynamic_constant(idx : usize, num_dyn : usize) -> DynConst { + let mut powers = vec![0; num_dyn]; + powers[idx] = 1; + DynConst { + terms : HashMap::from([(powers, Ratio::one())]), + vars : num_dyn, + } + } + + // Adds a term (defined by the powers in t and coefficient c) to the + // dynamic constant dc + // This is used in implementing other operations + fn add_term(dc : &mut DynConst, t : &Vec<i64>, c : Ratio<i64>) { + if !c.is_zero() { + if let Some(cur_coeff) = dc.terms.get_mut(t) { + *cur_coeff += c; + } else { + dc.terms.insert(t.clone(), c); + } + } + } + + // Same as add_term except the vector of powers is owned (which allows us + // to avoid a clone that might otherwise be necessary) + fn add_term_owned(dc : &mut DynConst, t : Vec<i64>, c : Ratio<i64>) { + if !c.is_zero() { + if let Some(cur_coeff) = dc.terms.get_mut(&t) { + *cur_coeff += c; + } else { + dc.terms.insert(t, c); + } + } + } + + // Adds two dynamic constants + pub fn add(lhs : &DynConst, rhs : &DynConst) -> DynConst { + let mut res = lhs.clone(); + assert!(lhs.vars == rhs.vars); + + for (term, coeff) in rhs.terms.iter() { + Self::add_term(&mut res, term, *coeff); + } + + res + } + + // Subtracts a dynamic constant from another + pub fn sub(lhs : &DynConst, rhs : &DynConst) -> DynConst { + let mut res = lhs.clone(); + assert!(lhs.vars == rhs.vars); + + // Works like add except the coefficients we add are negated + for (term, coeff) in rhs.terms.iter() { + Self::add_term(&mut res, term, - *coeff); + } + + res + } + + // Multiplies two dynamic constants + pub fn mul(lhs : &DynConst, rhs : &DynConst) -> DynConst { + let mut res = DynConst::zero(lhs); + assert!(lhs.vars == rhs.vars); + + // Loop through each pair of terms in the left and right-hand sides + // We multiply each of pairs and add all of those results together + for (ltrm, lcoeff) in lhs.terms.iter() { + for (rtrm, rcoeff) in rhs.terms.iter() { + // Add the powers from the two terms together + let term = ltrm.iter() + .zip(rtrm.iter()).map(|(lp, rp)| lp + rp) + .collect::<Vec<_>>(); + // Multiply their coefficients + let coeff = *lcoeff * *rcoeff; + + Self::add_term_owned(&mut res, term, coeff); + } + } + + res + } + + // Our division at least currently only supports division by a single term + // This also returns None if we try to divide by zero + pub fn div(lhs : &DynConst, rhs : &DynConst) -> Option<DynConst> { + assert!(lhs.vars == rhs.vars); + + if rhs.terms.len() != 1 { return None; } + let (dterm, dcoeff) = rhs.terms.iter().nth(0).expect("From above"); + if dcoeff.is_zero() { return None; } + + let mut res = DynConst::zero(lhs); + + for (t, c) in lhs.terms.iter() { + let term = t.iter().zip(dterm.iter()).map(|(lp, rp)| lp - rp) + .collect::<_>(); + let coeff = c / dcoeff; + Self::add_term_owned(&mut res, term, coeff); + } + + Some(res) + } + + // Computes the negation of a dynamic constant + pub fn negate(val : &DynConst) -> DynConst { + DynConst { + terms : val.terms.iter().map(|(t, c)| (t.clone(), - c)).collect::<_>(), + vars : val.vars + } + } + + // Raises a dynamic constant to a particular power + fn power(val : &DynConst, power : i64) -> Option<DynConst> { + let mut res = DynConst::constant(1, val.vars); + + if power > 0 { + for _ in 0..power { + res = DynConst::mul(&res, val); + } + } else if power < 0 { + let times = -power; + for _ in 0..times { + res = DynConst::div(&res, val)?; + } + } + + Some(res) + } + + // Substitutes the variables in this dynamic constant for the dynamic + // constant expressions vars + pub fn subst(&self, vars : &Vec<DynConst>) -> Option<DynConst> { + assert!(self.vars == vars.len()); + + // Only a constant, so we can just clone + if self.vars == 0 { + return Some(self.clone()); + } + + // Otherwise, we have at least one variable and can use this to determine the number of + // variables in the resulting polynomial + let num_dyns = vars[0].vars; + let mut res = DynConst::constant(0, num_dyns); + + for (term, coeff) in self.terms.iter() { + let mut product = DynConst::constant_ratio(*coeff, num_dyns); + for (var, power) in term.iter().enumerate() { + product = DynConst::mul(&product, + &DynConst::power(&vars[var], *power)?); + } + res = DynConst::add(&res, &product); + } + + Some(res) + } + + fn term_to_string(term : &Vec<i64>, stringtab : &dyn Fn(usize) -> String) -> String { + term.iter().enumerate() + .map(|(i, p)| if *p == 0 { "".to_string() } + else { format!("{}^{}", stringtab(i), p) }) + .filter(|s| !s.is_empty()).collect::<Vec<_>>().join(" ") + } + + // Converts the dynamic constant into a string using a function which maps + // variable numbers into names + // Useful for debugging and error messages + pub fn to_string(&self, stringtab : &dyn Fn(usize) -> String) -> String { + let mut vec = self.terms.iter().collect::<Vec<_>>(); + vec.sort(); + vec.iter() + .map(|(t, c)| format!("{} {}", c.to_string(), + Self::term_to_string(*t, stringtab))) + .collect::<Vec<_>>().join(" + ") + } + + // Builds a dynamic constant in the IR + pub fn build(&self, builder : &mut Builder) -> DynamicConstantID { + // Identify the terms with non-zero coefficients + let non_zero_coeff = self.terms.iter().filter(|(_, c)| !c.is_zero()) + .collect::<Vec<_>>(); + if non_zero_coeff.len() != 1 { + // Once the IR supports dynamic constant expressions, we'll need to + // sort the terms with non-zero coefficients and generate in a + // standardized manner to ensure that equivalent expressions always + // generate the same dynamic constant expression in the IR + todo!("Dynamic constant expression generation: {:?}", self) + } else { + let (dterm, dcoeff) = non_zero_coeff[0]; + // If the term with non-zero coefficient has a coefficient that is + // not 1, then this (currently) must just be a constant expression + // which must be a non-negative integer + if !dcoeff.is_one() { + if dterm.iter().all(|p| *p == 0) { + if !dcoeff.is_integer() { + panic!("Dynamic constant is a non-integer constant") + } else { + let val : i64 = dcoeff.to_integer(); + if val < 0 { + panic!("Dynamic constant is a negative constant") + } else { + builder.create_dynamic_constant_constant( + dcoeff.to_integer() as usize) + } + } + } else { + todo!("Dynamic constant expression generation: {:?}", self) + } + } else { + if dterm.iter().all(|p| *p == 0) { + // Constant value 1 + builder.create_dynamic_constant_constant(1) + } else { + let present = dterm.iter().enumerate().filter(|(_, p)| **p != 0) + .collect::<Vec<_>>(); + if present.len() != 1 || *present[0].1 != 1 { + todo!("Dynamic constant expression generation: {:?}", self) + } else { + builder.create_dynamic_constant_parameter(present[0].0) + } + } + } + } + } +} diff --git a/juno_frontend/src/env.rs b/juno_frontend/src/env.rs index 3985a69a108c3c04f27f92b65b2c083c94006398..f8e5fda696de4fe5cbf426240647c08f2cd697d8 100644 --- a/juno_frontend/src/env.rs +++ b/juno_frontend/src/env.rs @@ -16,7 +16,7 @@ impl<K : Eq + Hash + Copy, V> Env<K, V> { pub fn lookup(&self, k : &K) -> Option<&V> { match self.table.get(k) { None => None, - Some(l) => Some(&l[l.len()-1]), + Some(l) => l.last(), } } diff --git a/juno_frontend/src/intrinsics.rs b/juno_frontend/src/intrinsics.rs new file mode 100644 index 0000000000000000000000000000000000000000..3d9b5459a184e935264bb164945de56b1e74d019 --- /dev/null +++ b/juno_frontend/src/intrinsics.rs @@ -0,0 +1,39 @@ +/* Definitions of the set of intrinsic functions in Juno */ +use phf::phf_map; + +use crate::types::{Type, TypeSolver}; +use crate::parser; + +// How intrinsics are identified in the Hercules IR +pub type IntrinsicIdentity = usize; + +// Information about a single intrinsic, including its type information and how it will be +// identified in the Hercules IR +#[derive(Clone)] +pub struct IntrinsicInfo { + pub id : IntrinsicIdentity, + pub kinds : &'static [parser::Kind], + pub args : fn(&Vec<Type>, &mut TypeSolver) -> Vec<(Type, bool)>, + pub ret_typ : fn(&Vec<Type>, &mut TypeSolver) -> Type, +} + +fn sqrt_args(ty_args : &Vec<Type>, _ : &mut TypeSolver) -> Vec<(Type, bool)> { + vec![(ty_args[0], false)] +} + +fn sqrt_return(ty_args : &Vec<Type>, _ : &mut TypeSolver) -> Type { + ty_args[0] +} + +static INTRINSICS : phf::Map<&'static str, IntrinsicInfo> = phf_map! { + "sqrt" => IntrinsicInfo { + id : 0, + kinds : &[parser::Kind::Number], + args : sqrt_args, + ret_typ : sqrt_return, + }, +}; + +pub fn lookup(nm : &str) -> Option<&IntrinsicInfo> { + INTRINSICS.get(nm) +} diff --git a/juno_frontend/src/lang.y b/juno_frontend/src/lang.y index 2f63f998eb62e305163a3ad24977c9efbcd5afdc..1530981cb26828f46ce2c11000f86d48a8178a62 100644 --- a/juno_frontend/src/lang.y +++ b/juno_frontend/src/lang.y @@ -432,6 +432,10 @@ Expr -> Result<Expr, ()> { Ok(Expr::CallExpr{ span : $span, name : $1?, ty_args : vec![], args: $3? }) } | PackageName '::' '<' TypeExprs '>' '(' Params ')' { Ok(Expr::CallExpr{ span : $span, name : $1?, ty_args : $4?, args: $7? }) } + | PackageName '!' '(' Params ')' + { Ok(Expr::IntrinsicExpr{ span : $span, name : $1?, ty_args : vec![], args: $4? }) } + | PackageName '!' '::' '<' TypeExprs '>' '(' Params ')' + { Ok(Expr::IntrinsicExpr{ span : $span, name : $1?, ty_args : $5?, args: $8? }) } ; IdExprs -> Result<Vec<(Id, Expr)>, ()> : 'ID' '=' Expr { Ok(vec![(span_of_tok($1)?, $3?)]) } @@ -699,6 +703,8 @@ pub enum Expr { CondExpr { span : Span, cond : Box<Expr>, thn : Box<Expr>, els : Box<Expr> }, CallExpr { span : Span, name : PackageName, ty_args : Vec<TypeExpr>, args : Vec<(bool, Expr)> }, // bool indicates & (for inouts) + IntrinsicExpr { span : Span, name : PackageName, ty_args : Vec<TypeExpr>, + args : Vec<(bool, Expr)> }, } #[derive(Debug)] @@ -736,6 +742,7 @@ impl Spans for Expr { | Expr::CastExpr { span, .. } | Expr::CondExpr { span, .. } | Expr::CallExpr { span, .. } + | Expr::IntrinsicExpr { span, .. } => *span } } diff --git a/juno_frontend/src/main.rs b/juno_frontend/src/main.rs index f8e267eb3d2f2eb9bc8e7555cd313af0cc4c857d..ad50b66821fac2d93e79d0ae3591cf344a9bc97e 100644 --- a/juno_frontend/src/main.rs +++ b/juno_frontend/src/main.rs @@ -3,7 +3,10 @@ extern crate clap; use clap::Parser; mod codegen; +mod dynconst; mod env; +mod intrinsics; +mod parser; mod semant; mod ssa; mod types; diff --git a/juno_frontend/src/parser.rs b/juno_frontend/src/parser.rs new file mode 100644 index 0000000000000000000000000000000000000000..d5885d3e15225ee70f5157f868f016755a5f32cd --- /dev/null +++ b/juno_frontend/src/parser.rs @@ -0,0 +1,8 @@ +use lrlex::lrlex_mod; +use lrpar::lrpar_mod; + +lrlex_mod!("lang.l"); +lrpar_mod!("lang.y"); + +pub use lang_y::*; +pub mod lexer { pub use super::lang_l::*; } diff --git a/juno_frontend/src/semant.rs b/juno_frontend/src/semant.rs index 324ef5b9f9519a61ae73b2e782c3b82f813c15eb..7c4338bfb134c2ccef854eba5ced74b21d54ff11 100644 --- a/juno_frontend/src/semant.rs +++ b/juno_frontend/src/semant.rs @@ -5,19 +5,19 @@ use std::fs::File; use std::io::Read; use std::fmt; -use lrlex::{lrlex_mod, DefaultLexerTypes}; -use lrpar::{lrpar_mod, NonStreamingLexer}; +use lrlex::DefaultLexerTypes; +use lrpar::NonStreamingLexer; use cfgrammar::Span; use ordered_float::OrderedFloat; -lrlex_mod!("lang.l"); -lrpar_mod!("lang.y"); - -use lang_y::*; +use crate::dynconst::DynConst; use crate::env::Env; +use crate::intrinsics; +use crate::parser::*; +use crate::parser; +use crate::types::{Either, Type, TypeSolver}; use crate::types; -use crate::types::{DynamicConstant, Either, Type, TypeSolver}; // Definitions and data structures for semantic analysis @@ -25,12 +25,12 @@ use crate::types::{DynamicConstant, Either, Type, TypeSolver}; enum Entity { // A variable has a variable number to distinguish shadowing Variable { variable : usize, typ : Type, is_const : bool }, - Type { type_args : Vec<lang_y::Kind>, value : Type }, - DynConst { value : usize }, // dynamic constant number + Type { type_args : Vec<parser::Kind>, value : Type }, + DynConst { value : DynConst }, Constant { value : Constant }, // For functions we track an index, its type parameters, its argument types and if they are // inout, and its return type - Function { index : usize, type_args : Vec<lang_y::Kind>, + Function { index : usize, type_args : Vec<parser::Kind>, args : Vec<(types::Type, bool)>, return_type : types::Type }, } @@ -270,7 +270,7 @@ pub enum Stmt { #[derive(Clone, Debug)] pub enum Expr { Variable { var : usize, typ : Type }, - DynConst { idx : usize, typ : Type }, + DynConst { val : DynConst, typ : Type }, Read { index : Vec<Index>, val : Box<Expr>, typ : Type }, Write { index : Vec<Index>, val : Box<Expr>, rep : Box<Expr>, typ : Type }, Tuple { vals : Vec<Expr>, typ : Type }, @@ -281,7 +281,10 @@ pub enum Expr { BinaryExp { op : BinaryOp, lhs : Box<Expr>, rhs : Box<Expr>, typ : Type }, CastExpr { expr : Box<Expr>, typ : Type }, CondExpr { cond : Box<Expr>, thn : Box<Expr>, els : Box<Expr>, typ : Type }, - CallExpr { func : usize, ty_args : Vec<Type>, dyn_consts : Vec<DynamicConstant>, + CallExpr { func : usize, ty_args : Vec<Type>, dyn_consts : Vec<DynConst>, + args : Vec<Either<Expr, usize>>, typ : Type }, + Intrinsic { id : intrinsics::IntrinsicIdentity, + ty_args : Vec<Type>, dyn_consts : Vec<DynConst>, args : Vec<Either<Expr, usize>>, typ : Type }, } @@ -296,7 +299,7 @@ pub enum BinaryOp { Add, Sub, Mul, Div, Mod, Lt, Le, Gt, Ge, Eq, Neq, LShift, RShift } -fn convert_assign_op(op : lang_y::AssignOp) -> BinaryOp { +fn convert_assign_op(op : parser::AssignOp) -> BinaryOp { match op { AssignOp::None => panic!("Do not call convert_assign_op on AssignOp::None"), AssignOp::Add => BinaryOp::Add, @@ -314,26 +317,26 @@ fn convert_assign_op(op : lang_y::AssignOp) -> BinaryOp { } } -fn convert_binary_op(op : lang_y::BinaryOp) -> BinaryOp { +fn convert_binary_op(op : parser::BinaryOp) -> BinaryOp { match op { - lang_y::BinaryOp::Add => BinaryOp::Add, - lang_y::BinaryOp::Sub => BinaryOp::Sub, - lang_y::BinaryOp::Mul => BinaryOp::Mul, - lang_y::BinaryOp::Div => BinaryOp::Div, - lang_y::BinaryOp::Mod => BinaryOp::Mod, - lang_y::BinaryOp::BitAnd => BinaryOp::BitAnd, - lang_y::BinaryOp::BitOr => BinaryOp::BitOr, - lang_y::BinaryOp::Xor => BinaryOp::Xor, - lang_y::BinaryOp::Lt => BinaryOp::Lt, - lang_y::BinaryOp::Le => BinaryOp::Le, - lang_y::BinaryOp::Gt => BinaryOp::Gt, - lang_y::BinaryOp::Ge => BinaryOp::Ge, - lang_y::BinaryOp::Eq => BinaryOp::Eq, - lang_y::BinaryOp::Neq => BinaryOp::Neq, - lang_y::BinaryOp::LShift => BinaryOp::LShift, - lang_y::BinaryOp::RShift => BinaryOp::RShift, - lang_y::BinaryOp::LogAnd => panic!("Do not call convert_binary_op on BinaryOp::LogAnd"), - lang_y::BinaryOp::LogOr => panic!("Do not call convert_binary_op on BinaryOp::LogOr"), + parser::BinaryOp::Add => BinaryOp::Add, + parser::BinaryOp::Sub => BinaryOp::Sub, + parser::BinaryOp::Mul => BinaryOp::Mul, + parser::BinaryOp::Div => BinaryOp::Div, + parser::BinaryOp::Mod => BinaryOp::Mod, + parser::BinaryOp::BitAnd => BinaryOp::BitAnd, + parser::BinaryOp::BitOr => BinaryOp::BitOr, + parser::BinaryOp::Xor => BinaryOp::Xor, + parser::BinaryOp::Lt => BinaryOp::Lt, + parser::BinaryOp::Le => BinaryOp::Le, + parser::BinaryOp::Gt => BinaryOp::Gt, + parser::BinaryOp::Ge => BinaryOp::Ge, + parser::BinaryOp::Eq => BinaryOp::Eq, + parser::BinaryOp::Neq => BinaryOp::Neq, + parser::BinaryOp::LShift => BinaryOp::LShift, + parser::BinaryOp::RShift => BinaryOp::RShift, + parser::BinaryOp::LogAnd => panic!("Do not call convert_binary_op on BinaryOp::LogAnd"), + parser::BinaryOp::LogOr => panic!("Do not call convert_binary_op on BinaryOp::LogOr"), } } @@ -341,7 +344,7 @@ fn convert_binary_op(op : lang_y::BinaryOp) -> BinaryOp { impl Expr { pub fn get_type(&self) -> Type { match self { - Expr::Variable { var : _, typ } | Expr::DynConst { idx : _, typ } + Expr::Variable { var : _, typ } | Expr::DynConst { val : _, typ } | Expr::Read { index : _, val : _, typ } | Expr::Write { index : _, val : _, rep : _, typ } | Expr::Tuple { vals : _, typ } | Expr::Union { tag : _, val : _, typ } @@ -350,6 +353,7 @@ impl Expr { | Expr::CastExpr { expr : _, typ } | Expr::CondExpr { cond : _, thn : _, els : _, typ } | Expr::CallExpr { func : _, ty_args : _, dyn_consts : _, args : _, typ } + | Expr::Intrinsic { id : _, ty_args : _, dyn_consts : _, args : _, typ } | Expr::Zero { typ } => *typ } @@ -368,9 +372,9 @@ pub fn parse_and_analyze(src_file : String) -> Result<Prg, ErrorMessages> { if let Ok(mut file) = File::open(src_file) { let mut contents = String::new(); if let Ok(_) = file.read_to_string(&mut contents) { - let lexerdef = lang_l::lexerdef(); + let lexerdef = lexer::lexerdef(); let lexer = lexerdef.lexer(&contents); - let (res, errs) = lang_y::parse(&lexer); + let (res, errs) = parser::parse(&lexer); if errs.is_empty() { match res { @@ -383,7 +387,7 @@ pub fn parse_and_analyze(src_file : String) -> Result<Prg, ErrorMessages> { } else { Err(errs.iter() .map(|e| ErrorMessage::SyntaxError( - e.pp(&lexer, &lang_y::token_epp))) + e.pp(&lexer, &parser::token_epp))) .collect()) } } else { @@ -395,7 +399,7 @@ pub fn parse_and_analyze(src_file : String) -> Result<Prg, ErrorMessages> { } fn analyze_program( - prg : lang_y::Prg, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>) + prg : parser::Prg, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>) -> Result<Prg, ErrorMessages> { let mut stringtab = StringTable::new(); @@ -408,13 +412,13 @@ fn analyze_program( for top in prg { match top { - lang_y::Top::Import { span, name: _ } => { + parser::Top::Import { span, name: _ } => { Err(singleton_error( ErrorMessage::NotImplemented( span_to_loc(span, lexer), "imports".to_string())))? }, - lang_y::Top::TypeDecl { span : _, public: _, name, ty_vars, body } => { + parser::Top::TypeDecl { span : _, public: _, name, ty_vars, body } => { // TODO: Handle public env.open_scope(); // Create a new scope for the body (for type variables) @@ -424,6 +428,8 @@ fn analyze_program( // Track the kinds of the variables let mut kinds = vec![]; + let mut dyn_const_names = vec![]; + for TypeVar { span : _, name, kind } in ty_vars { let nm = intern_id(&name, lexer, &mut stringtab); kinds.push(kind); @@ -435,7 +441,7 @@ fn analyze_program( num_type += 1; }, Kind::USize => { - env.insert(nm, Entity::DynConst { value : num_dyn_const }); + dyn_const_names.push(nm); num_dyn_const += 1; }, Kind::Number => { @@ -451,22 +457,28 @@ fn analyze_program( } } + for (idx, nm) in dyn_const_names.into_iter().enumerate() { + env.insert(nm, Entity::DynConst { + value : DynConst::dynamic_constant(idx, num_dyn_const) + }); + } + let nm = intern_id(&name, lexer, &mut stringtab); - let typ = process_type_def(body, nm, lexer, &mut stringtab, - &mut env, &mut types)?; + let typ = process_type_def(body, nm, num_dyn_const, lexer, + &mut stringtab, &mut env, &mut types)?; // Insert information into the global scope env.close_scope(); env.insert(nm, Entity::Type { type_args : kinds, value : typ }); }, - lang_y::Top::ConstDecl { span : _, public: _, name, ty: _, body } => { + parser::Top::ConstDecl { span : _, public: _, name, ty: _, body } => { // TODO: Handle public let nm = intern_id(&name, lexer, &mut stringtab); - let val = process_expr_as_constant(body, lexer, &mut stringtab, + let val = process_expr_as_constant(body, 0, lexer, &mut stringtab, &mut env, &mut types)?; env.insert(nm, Entity::Constant { value : val }); }, - lang_y::Top::FuncDecl { span, public: _, attr: _, name, ty_vars, args, ty, body } => { + parser::Top::FuncDecl { span, public: _, attr: _, name, ty_vars, args, ty, body } => { // TODO: Handle public, attributes env.open_scope(); // Open a new scope immediately to put type variables in @@ -474,15 +486,16 @@ fn analyze_program( let mut num_dyn_const = 0; let mut num_type_var = 0; let mut type_kinds = vec![]; + + let mut dyn_const_names = vec![]; + for TypeVar { span : _, name, kind } in ty_vars { type_kinds.push(kind); let nm = intern_id(&name, lexer, &mut stringtab); match kind { Kind::USize => { - let num = num_dyn_const; + dyn_const_names.push(nm); num_dyn_const += 1; - - env.insert(nm, Entity::DynConst { value : num }); }, Kind::Type => { let typ = types.new_type_var(nm, num_type_var, false, false); @@ -501,6 +514,11 @@ fn analyze_program( }, } } + for (idx, nm) in dyn_const_names.into_iter().enumerate() { + env.insert(nm, Entity::DynConst { + value : DynConst::dynamic_constant(idx, num_dyn_const) + }); + } // Process arguments let mut arg_types : Vec<(usize, Type, bool)> = vec![]; // list of name, type, and @@ -530,8 +548,8 @@ fn analyze_program( } let nm = intern_package_name(&name, lexer, &mut stringtab)[0]; - match process_type(typ.expect("FROM ABOVE"), lexer, - &mut stringtab, &env, &mut types) { + match process_type(typ.expect("FROM ABOVE"), num_dyn_const, + lexer, &mut stringtab, &env, &mut types) { Ok(ty) => { if inout.is_some() { inout_args.push(arg_types.len()); @@ -560,8 +578,8 @@ fn analyze_program( types.new_primitive(types::Primitive::Unit) }, Some(ty) => { - match process_type(ty, lexer, &mut stringtab, &env, - &mut types) { + match process_type(ty, num_dyn_const, lexer, + &mut stringtab, &env, &mut types) { Ok(ty) => ty, Err(mut errs) => { errors.append(&mut errs); @@ -604,7 +622,7 @@ fn analyze_program( // Finally, we have a properly built environment and we can // start processing the body let (mut body, end_reachable) - = process_stmt(body, lexer, &mut stringtab, &mut env, &mut types, + = process_stmt(body, num_dyn_const, lexer, &mut stringtab, &mut env, &mut types, false, return_type, &inout_variables, &inout_types)?; if end_reachable { @@ -652,7 +670,7 @@ fn analyze_program( return_type : pure_return_type, body : body }); }, - lang_y::Top::ModDecl { span, public: _, name: _, body: _ } => { + parser::Top::ModDecl { span, public: _, name: _, body: _ } => { Err(singleton_error( ErrorMessage::NotImplemented( span_to_loc(span, lexer), @@ -664,16 +682,16 @@ fn analyze_program( Ok((types, res)) } -fn process_type_def(def : lang_y::TyDef, name : usize, +fn process_type_def(def : parser::TyDef, name : usize, num_dyn_const : usize, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &mut Env<usize, Entity>, types : &mut TypeSolver) -> Result<Type, ErrorMessages> { match def { - lang_y::TyDef::TypeAlias { span: _, body } => { - process_type(body, lexer, stringtab, env, types) + parser::TyDef::TypeAlias { span: _, body } => { + process_type(body, num_dyn_const, lexer, stringtab, env, types) }, - lang_y::TyDef::Struct { span: _, public: _, fields } => { + parser::TyDef::Struct { span: _, public: _, fields } => { // TODO: handle public correctly (and field public) let mut field_list = vec![]; @@ -690,7 +708,8 @@ fn process_type_def(def : lang_y::TyDef, name : usize, "struct fields must have a type".to_string())); }, Some(ty) => { - match process_type(ty, lexer, stringtab, env, types) { + match process_type(ty, num_dyn_const, lexer, stringtab, + env, types) { Ok(typ) => { let idx = field_list.len(); field_list.push(typ); @@ -708,7 +727,7 @@ fn process_type_def(def : lang_y::TyDef, name : usize, Ok(types.new_struct(name, env.uniq(), field_list, field_map)) } }, - lang_y::TyDef::Union { span : _, public: _, fields } => { + parser::TyDef::Union { span : _, public: _, fields } => { // TODO: handle public correctly let mut constr_list = vec![]; let mut constr_map = HashMap::new(); @@ -729,7 +748,8 @@ fn process_type_def(def : lang_y::TyDef, name : usize, constr_map.insert(nm, idx); }, Some(ty) => { - match process_type(ty, lexer, stringtab, env, types) { + match process_type(ty, num_dyn_const, lexer, + stringtab, env, types) { Ok(typ) => { let idx = constr_list.len(); constr_list.push(typ); @@ -750,20 +770,22 @@ fn process_type_def(def : lang_y::TyDef, name : usize, } } -fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, +fn process_type(typ : parser::Type, num_dyn_const : usize, + lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &Env<usize, Entity>, types : &mut TypeSolver) -> Result<Type, ErrorMessages> { match typ { - lang_y::Type::PrimType { span: _, typ } => { + parser::Type::PrimType { span: _, typ } => { Ok(types.new_primitive(convert_primitive(typ))) }, - lang_y::Type::TupleType { span: _, tys } => { + parser::Type::TupleType { span: _, tys } => { let mut fields = vec![]; let mut errors = LinkedList::new(); for ty in tys { - match process_type(ty, lexer, stringtab, env, types) { + match process_type(ty, num_dyn_const, lexer, stringtab, env, + types) { Ok(t) => fields.push(t), Err(mut errs) => errors.append(&mut errs), } @@ -779,7 +801,7 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT } } }, - lang_y::Type::NamedType { span, name, args } => { + parser::Type::NamedType { span, name, args } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -806,23 +828,23 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT for (arg, kind) in args.into_iter().zip(type_args.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dynamic_constants.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -837,9 +859,9 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -862,7 +884,15 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT if type_vars.len() == 0 && dynamic_constants.len() == 0 { Ok(*value) } else { - Ok(types.instantiate(*value, &type_vars, &dynamic_constants)) + if let Some(res) + = types.instantiate(*value, &type_vars, &dynamic_constants) { + Ok(res) + } else { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))) + } } }, Some(_) => @@ -879,14 +909,16 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT } } }, - lang_y::Type::ArrayType { span: _, elem, dims } => { + parser::Type::ArrayType { span: _, elem, dims } => { let mut dimensions = vec![]; let mut errors = LinkedList::new(); - let element = process_type(*elem, lexer, stringtab, env, types); + let element = process_type(*elem, num_dyn_const, lexer, stringtab, + env, types); for dim in dims { - match process_type_expr_as_expr(dim, lexer, stringtab, env, types) { + match process_type_expr_as_expr(dim, num_dyn_const, lexer, + stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(ex) => dimensions.push(ex), } @@ -917,23 +949,23 @@ fn process_type(typ : lang_y::Type, lexer : &dyn NonStreamingLexer<DefaultLexerT } } -fn process_type_expr_as_expr(exp : lang_y::TypeExpr, +fn process_type_expr_as_expr(exp : parser::TypeExpr, num_dyn_const : usize, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &Env<usize, Entity>, types : &mut TypeSolver) - -> Result<DynamicConstant, ErrorMessages> { + -> Result<DynConst, ErrorMessages> { match exp { - lang_y::TypeExpr::PrimType { span, .. } - | lang_y::TypeExpr::TupleType { span, .. } - | lang_y::TypeExpr::ArrayTypeExpr { span, .. } => + parser::TypeExpr::PrimType { span, .. } + | parser::TypeExpr::TupleType { span, .. } + | parser::TypeExpr::ArrayTypeExpr { span, .. } => Err(singleton_error( ErrorMessage::KindError( span_to_loc(span, lexer), "dynamic constant expression".to_string(), "type".to_string()))), - lang_y::TypeExpr::NamedTypeExpr { span, name, args } => { + parser::TypeExpr::NamedTypeExpr { span, name, args } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -950,13 +982,13 @@ fn process_type_expr_as_expr(exp : lang_y::TypeExpr, span_to_loc(span, lexer), format!("No type arguments exists on dynamic constants")))) } else { - Ok(DynamicConstant::DynConst(nm, *value)) + Ok(value.clone()) } }, Some(Entity::Constant { value : (val, typ) }) => { match val { Literal::Integer(val) => - Ok(DynamicConstant::Constant(*val as usize)), + Ok(DynConst::constant(*val as i64, num_dyn_const)), _ => Err(singleton_error( ErrorMessage::TypeError( @@ -991,51 +1023,80 @@ fn process_type_expr_as_expr(exp : lang_y::TypeExpr, } } }, - lang_y::TypeExpr::IntLiteral { span, base } => { - let res = usize::from_str_radix(lexer.span_str(span), base.base()); + parser::TypeExpr::IntLiteral { span, base } => { + let res = i64::from_str_radix(lexer.span_str(span), base.base()); assert!(res.is_ok(), "Internal Error: Int literal is not an integer"); - Ok(DynamicConstant::Constant(res.unwrap())) + Ok(DynConst::constant(res.unwrap(), num_dyn_const)) + }, + parser::TypeExpr::Negative { span : _, expr } => + Ok(DynConst::negate( + &process_type_expr_as_expr(*expr, num_dyn_const, lexer, + stringtab, env, types)?)), + parser::TypeExpr::Add { span : _, lhs, rhs } => { + let lhs_res = process_type_expr_as_expr(*lhs, num_dyn_const, lexer, + stringtab, env, types)?; + let rhs_res = process_type_expr_as_expr(*rhs, num_dyn_const, lexer, + stringtab, env, types)?; + Ok(DynConst::add(&lhs_res, &rhs_res)) + }, + parser::TypeExpr::Sub { span : _, lhs, rhs } => { + let lhs_res = process_type_expr_as_expr(*lhs, num_dyn_const, lexer, + stringtab, env, types)?; + let rhs_res = process_type_expr_as_expr(*rhs, num_dyn_const, lexer, + stringtab, env, types)?; + Ok(DynConst::sub(&lhs_res, &rhs_res)) + }, + parser::TypeExpr::Mul { span : _, lhs, rhs } => { + let lhs_res = process_type_expr_as_expr(*lhs, num_dyn_const, lexer, + stringtab, env, types)?; + let rhs_res = process_type_expr_as_expr(*rhs, num_dyn_const, lexer, + stringtab, env, types)?; + Ok(DynConst::mul(&lhs_res, &rhs_res)) + }, + parser::TypeExpr::Div { span, lhs, rhs } => { + let lhs_res = process_type_expr_as_expr(*lhs, num_dyn_const, lexer, + stringtab, env, types)?; + let rhs_res = process_type_expr_as_expr(*rhs, num_dyn_const, lexer, + stringtab, env, types)?; + if let Some(res) = DynConst::div(&lhs_res, &rhs_res) { + Ok(res) + } else { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Division by dynamic constant expression failed".to_string()))) + } }, - - lang_y::TypeExpr::Negative { span, .. } - | lang_y::TypeExpr::Add { span, .. } - | lang_y::TypeExpr::Sub { span, .. } - | lang_y::TypeExpr::Mul { span, .. } - | lang_y::TypeExpr::Div { span, .. } => - Err(singleton_error( - ErrorMessage::NotImplemented( - span_to_loc(span, lexer), - "expressions of dynamic constants".to_string()))), } } -fn process_type_expr_as_type(exp : lang_y::TypeExpr, +fn process_type_expr_as_type(exp : parser::TypeExpr, num_dyn_const : usize, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &Env<usize, Entity>, types : &mut TypeSolver) -> Result<Type, ErrorMessages> { match exp { - lang_y::TypeExpr::IntLiteral { span, .. } - | lang_y::TypeExpr::Negative { span, .. } - | lang_y::TypeExpr::Add { span, .. } - | lang_y::TypeExpr::Sub { span, .. } - | lang_y::TypeExpr::Mul { span, .. } - | lang_y::TypeExpr::Div { span, .. } => { + parser::TypeExpr::IntLiteral { span, .. } + | parser::TypeExpr::Negative { span, .. } + | parser::TypeExpr::Add { span, .. } + | parser::TypeExpr::Sub { span, .. } + | parser::TypeExpr::Mul { span, .. } + | parser::TypeExpr::Div { span, .. } => { Err(singleton_error( ErrorMessage::KindError( span_to_loc(span, lexer), "type".to_string(), "expression".to_string()))) }, - lang_y::TypeExpr::PrimType { span : _, typ } => { + parser::TypeExpr::PrimType { span : _, typ } => { Ok(types.new_primitive(convert_primitive(typ))) }, - lang_y::TypeExpr::TupleType { span : _, tys } => { + parser::TypeExpr::TupleType { span : _, tys } => { let mut fields = vec![]; let mut errors = LinkedList::new(); for ty in tys { - match process_type_expr_as_type(ty, lexer, stringtab, env, types) { + match process_type_expr_as_type(ty, num_dyn_const, lexer, stringtab, env, types) { Ok(t) => fields.push(t), Err(mut errs) => errors.append(&mut errs), } @@ -1051,14 +1112,14 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, } } }, - lang_y::TypeExpr::ArrayTypeExpr { span : _, elem, dims } => { + parser::TypeExpr::ArrayTypeExpr { span : _, elem, dims } => { let mut dimensions = vec![]; let mut errors = LinkedList::new(); - let element = process_type_expr_as_type(*elem, lexer, stringtab, env, types); + let element = process_type_expr_as_type(*elem, num_dyn_const, lexer, stringtab, env, types); for dim in dims { - match process_type_expr_as_expr(dim, lexer, stringtab, env, types) { + match process_type_expr_as_expr(dim, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(ex) => dimensions.push(ex), } @@ -1086,7 +1147,7 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, } } }, - lang_y::TypeExpr::NamedTypeExpr { span, name, args } => { + parser::TypeExpr::NamedTypeExpr { span, name, args } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -1113,23 +1174,23 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, for (arg, kind) in args.into_iter().zip(type_args.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dynamic_constants.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -1144,9 +1205,9 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -1169,7 +1230,15 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, if type_vars.len() == 0 && dynamic_constants.len() == 0 { Ok(*value) } else { - Ok(types.instantiate(*value, &type_vars, &dynamic_constants)) + if let Some(res) + = types.instantiate(*value, &type_vars, &dynamic_constants) { + Ok(res) + } else { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))) + } } }, Some(_) => @@ -1191,23 +1260,23 @@ fn process_type_expr_as_type(exp : lang_y::TypeExpr, // Normalizes the given statement, and returns the normalized statement plus whether a statement // after the analyzed one is reachable or not -fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, +fn process_stmt(stmt : parser::Stmt, num_dyn_const : usize, + lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &mut Env<usize, Entity>, types : &mut TypeSolver, in_loop : bool, return_type : Type, inout_vars : &Vec<usize>, inout_types : &Vec<Type>) -> Result<(Stmt, bool), ErrorMessages> { match stmt { - lang_y::Stmt::LetStmt { span: _, var : VarBind { span : v_span, pattern, typ }, init } => { + parser::Stmt::LetStmt { span: _, var : VarBind { span : v_span, pattern, typ }, init } => { match pattern { Pattern::Variable { span, name } => { - if typ.is_none() { - return Err(singleton_error( - ErrorMessage::NotImplemented( - span_to_loc(v_span, lexer), - "variable type inference".to_string()))); + if typ.is_none() && init.is_none() { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Must specify either type or initial value".to_string())))? } - if name.len() != 1 { Err(singleton_error( ErrorMessage::SemanticError( @@ -1216,7 +1285,13 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer } let nm = intern_package_name(&name, lexer, stringtab)[0]; - let ty = process_type(typ.expect("FROM ABOVE"), lexer, stringtab, env, types)?; + let ty = + match typ { + None => None, + Some(t) => + Some(process_type(t, num_dyn_const, lexer, + stringtab, env, types)?), + }; let var = env.uniq(); @@ -1224,25 +1299,28 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer match init { Some(exp) => { let loc = span_to_loc(exp.span(), lexer); - (process_expr(exp, lexer, stringtab, env, types)?, loc) + (process_expr(exp, num_dyn_const, lexer, stringtab, env, types)?, loc) }, None => { - (Expr::Zero { typ : ty }, Location::fake()) + (Expr::Zero { typ : ty.expect("From Above") }, + Location::fake()) }, }; let typ = val.get_type(); env.insert(nm, - Entity::Variable { variable : var, typ : ty, is_const : false }); + Entity::Variable { variable : var, typ : typ, + is_const : false }); - if !types.equal(ty, typ) { - Err(singleton_error( - ErrorMessage::TypeError( - exp_loc, - unparse_type(types, ty, stringtab), - unparse_type(types, typ, stringtab)))) - } else { - Ok((Stmt::AssignStmt { var : var, val : val }, true)) + match ty { + Some(ty) if !types.equal(ty, typ) => { + Err(singleton_error( + ErrorMessage::TypeError( + exp_loc, + unparse_type(types, ty, stringtab), + unparse_type(types, typ, stringtab))))? + }, + _ => Ok((Stmt::AssignStmt { var : var, val : val }, true)), } }, _ => { @@ -1253,16 +1331,15 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Stmt::ConstStmt { span: _, var : VarBind { span : v_span, pattern, typ }, init } => { + parser::Stmt::ConstStmt { span: _, var : VarBind { span : v_span, pattern, typ }, init } => { match pattern { Pattern::Variable { span, name } => { - if typ.is_none() { - return Err(singleton_error( - ErrorMessage::NotImplemented( - span_to_loc(v_span, lexer), - "variable type inference".to_string()))); + if typ.is_none() && init.is_none() { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Must specify either type or initial value".to_string())))? } - if name.len() != 1 { Err(singleton_error( ErrorMessage::SemanticError( @@ -1271,7 +1348,13 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer } let nm = intern_package_name(&name, lexer, stringtab)[0]; - let ty = process_type(typ.expect("FROM ABOVE"), lexer, stringtab, env, types)?; + let ty = + match typ { + None => None, + Some(t) => + Some(process_type(t, num_dyn_const, lexer, + stringtab, env, types)?), + }; let var = env.uniq(); @@ -1279,25 +1362,28 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer match init { Some(exp) => { let loc = span_to_loc(exp.span(), lexer); - (process_expr(exp, lexer, stringtab, env, types)?, loc) + (process_expr(exp, num_dyn_const, lexer, stringtab, env, types)?, loc) }, None => { - (Expr::Zero { typ : ty }, Location::fake()) + (Expr::Zero { typ : ty.expect("From Above") }, + Location::fake()) }, }; let typ = val.get_type(); env.insert(nm, - Entity::Variable { variable : var, typ : ty, is_const : true }); + Entity::Variable { variable : var, typ : typ, + is_const : true }); - if !types.equal(ty, typ) { - Err(singleton_error( - ErrorMessage::TypeError( - exp_loc, - unparse_type(types, ty, stringtab), - unparse_type(types, typ, stringtab)))) - } else { - Ok((Stmt::AssignStmt { var : var, val : val }, true)) + match ty { + Some(ty) if !types.equal(ty, typ) => { + Err(singleton_error( + ErrorMessage::TypeError( + exp_loc, + unparse_type(types, ty, stringtab), + unparse_type(types, typ, stringtab)))) + }, + _ => Ok((Stmt::AssignStmt { var : var, val : val }, true)), } }, _ => { @@ -1308,9 +1394,9 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Stmt::AssignStmt { span: _, lhs, assign, assign_span, rhs } => { - let lhs_res = process_lexpr(lhs, lexer, stringtab, env, types); - let rhs_res = process_expr(rhs, lexer, stringtab, env, types); + parser::Stmt::AssignStmt { span: _, lhs, assign, assign_span, rhs } => { + let lhs_res = process_lexpr(lhs, num_dyn_const, lexer, stringtab, env, types); + let rhs_res = process_expr(rhs, num_dyn_const, lexer, stringtab, env, types); let (((var, var_typ), (exp_typ, index)), val) = append_errors2(lhs_res, rhs_res)?; let typ = val.get_type(); @@ -1446,12 +1532,12 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer var : var, val : write_exp }, true)) }, - lang_y::Stmt::IfStmt { span: _, cond, thn, els } => { + parser::Stmt::IfStmt { span: _, cond, thn, els } => { let cond_span = cond.span(); - let cond_res = process_expr(cond, lexer, stringtab, env, types); + let cond_res = process_expr(cond, num_dyn_const, lexer, stringtab, env, types); env.open_scope(); - let thn_res = process_stmt(*thn, lexer, stringtab, env, types, + let thn_res = process_stmt(*thn, num_dyn_const, lexer, stringtab, env, types, in_loop, return_type, inout_vars, inout_types); env.close_scope(); @@ -1459,7 +1545,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer let els_res = match els { None => Ok((None, true)), Some(stmt) => - process_stmt(*stmt, lexer, stringtab, env, types, + process_stmt(*stmt, num_dyn_const, lexer, stringtab, env, types, in_loop, return_type, inout_vars, inout_types) .map(|(s, b)| (Some(s), b)), }; env.close_scope(); @@ -1482,13 +1568,13 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer els : els_body.map(|s| Box::new(s)) }, thn_fall || els_fall)) }, - lang_y::Stmt::MatchStmt { span, expr: _, body: _ } => { + parser::Stmt::MatchStmt { span, expr: _, body: _ } => { Err(singleton_error( ErrorMessage::NotImplemented( span_to_loc(span, lexer), "match statements".to_string()))) }, - lang_y::Stmt::ForStmt { span: _, var : VarBind { span : v_span, pattern, typ }, + parser::Stmt::ForStmt { span: _, var : VarBind { span : v_span, pattern, typ }, init, bound, step, body } => { let (var, var_name, var_type) = match pattern { @@ -1505,7 +1591,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer match typ { None => types.new_primitive(types::Primitive::U64), Some(t) => { - let ty = process_type(t, lexer, stringtab, env, types)?; + let ty = process_type(t, num_dyn_const, lexer, stringtab, env, types)?; if !types.is_integer(ty) { return Err(singleton_error( ErrorMessage::SemanticError( @@ -1531,8 +1617,8 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer let init_span = init.span(); let bound_span = bound.span(); - let init_res = process_expr(init, lexer, stringtab, env, types); - let bound_res = process_expr(bound, lexer, stringtab, env, types); + let init_res = process_expr(init, num_dyn_const, lexer, stringtab, env, types); + let bound_res = process_expr(bound, num_dyn_const, lexer, stringtab, env, types); // The step is tracked as a pair of the step's amount (always positive) and whether the // step should be positive or negative @@ -1588,7 +1674,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer // Process the body let (body, _) - = process_stmt(*body, lexer, stringtab, env, types, true, + = process_stmt(*body, num_dyn_const, lexer, stringtab, env, types, true, return_type, inout_vars, inout_types)?; env.close_scope(); @@ -1640,12 +1726,12 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer ] }, true)) }, - lang_y::Stmt::WhileStmt { span: _, cond, body } => { + parser::Stmt::WhileStmt { span: _, cond, body } => { let cond_span = cond.span(); - let cond_res = process_expr(cond, lexer, stringtab, env, types); + let cond_res = process_expr(cond, num_dyn_const, lexer, stringtab, env, types); env.open_scope(); - let body_res = process_stmt(*body, lexer, stringtab, env, types, + let body_res = process_stmt(*body, num_dyn_const, lexer, stringtab, env, types, true, return_type, inout_vars, inout_types); env.close_scope(); @@ -1667,7 +1753,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer update : None, body : Box::new(body_stmt) }, true)) }, - lang_y::Stmt::ReturnStmt { span, expr } => { + parser::Stmt::ReturnStmt { span, expr } => { let return_val = if expr.is_none() && types.is_void(return_type) { Expr::Constant { @@ -1680,7 +1766,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer format!("Expected return of type {} found no return value", unparse_type(types, return_type, stringtab)))))? } else { - let val = process_expr(expr.unwrap(), lexer, stringtab, env, + let val = process_expr(expr.unwrap(), num_dyn_const, lexer, stringtab, env, types)?; let typ = val.get_type(); if !types.equal(return_type, typ) { @@ -1698,7 +1784,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer Ok((generate_return(return_val, inout_vars, inout_types, types), false)) }, - lang_y::Stmt::BreakStmt { span } => { + parser::Stmt::BreakStmt { span } => { if !in_loop { Err(singleton_error( ErrorMessage::SemanticError( @@ -1709,7 +1795,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer // Code after a break is unreachable Ok((Stmt::BreakStmt {}, false)) }, - lang_y::Stmt::ContinueStmt { span } => { + parser::Stmt::ContinueStmt { span } => { if !in_loop { Err(singleton_error( ErrorMessage::SemanticError( @@ -1720,7 +1806,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer // Code after a continue is unreachable Ok((Stmt::ContinueStmt {}, false)) }, - lang_y::Stmt::BlockStmt { span: _, body } => { + parser::Stmt::BlockStmt { span: _, body } => { // Blocks create a new scope for variables declared in them env.open_scope(); @@ -1736,7 +1822,7 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer "Unreachable statement".to_string())))? } - match process_stmt(stmt, lexer, stringtab, env, types, in_loop, + match process_stmt(stmt, num_dyn_const, lexer, stringtab, env, types, in_loop, return_type, inout_vars, inout_types) { Err(mut errs) => { errors.append(&mut errs); }, Ok((stmt, post_reachable)) => { @@ -1754,14 +1840,14 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer Ok((Stmt::BlockStmt { body : res }, reachable)) } }, - lang_y::Stmt::CallStmt { span, name, ty_args, args } => { + parser::Stmt::CallStmt { span, name, ty_args, args } => { // Call statements are lowered to call expressions which is made a statment using the // ExprStmt constructor // Code after a call is always reachable Ok((Stmt::ExprStmt { expr : process_expr( - lang_y::Expr::CallExpr { span, name, ty_args, args }, - lexer, stringtab, env, types)? }, + parser::Expr::CallExpr { span, name, ty_args, args }, + num_dyn_const, lexer, stringtab, env, types)? }, true)) }, } @@ -1772,13 +1858,13 @@ fn process_stmt(stmt : lang_y::Stmt, lexer : &dyn NonStreamingLexer<DefaultLexer // piece // This should only be used for the left-hand side of an assignment since it will return an error // if the variable that is accessed is marked as constant -fn process_lexpr(expr : lang_y::LExpr, +fn process_lexpr(expr : parser::LExpr, num_dyn_const : usize, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &mut Env<usize, Entity>, types : &mut TypeSolver) -> Result<((usize, Type), (Type, Vec<Index>)), ErrorMessages> { match expr { - lang_y::LExpr::VariableLExpr { span } => { + parser::LExpr::VariableLExpr { span } => { let nm = intern_id(&span, lexer, stringtab); match env.lookup(&nm) { Some(Entity::Variable { variable, typ, is_const }) => { @@ -1828,9 +1914,9 @@ fn process_lexpr(expr : lang_y::LExpr, }, } }, - lang_y::LExpr::FieldLExpr { span, lhs, rhs } => { + parser::LExpr::FieldLExpr { span, lhs, rhs } => { let ((var, var_typ), (idx_typ, mut idx)) - = process_lexpr(*lhs, lexer, stringtab, env, types)?; + = process_lexpr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let field_nm = intern_id(&rhs, lexer, stringtab); match types.get_field(idx_typ, field_nm) { @@ -1846,9 +1932,9 @@ fn process_lexpr(expr : lang_y::LExpr, }, } }, - lang_y::LExpr::NumFieldLExpr { span, lhs, rhs } => { + parser::LExpr::NumFieldLExpr { span, lhs, rhs } => { let ((var, var_typ), (idx_typ, mut idx)) - = process_lexpr(*lhs, lexer, stringtab, env, types)?; + = process_lexpr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; // Identify the field number; to do this we remove the first character of the string of // the right-hand side since the ".###" is lexed as a single token @@ -1868,15 +1954,15 @@ fn process_lexpr(expr : lang_y::LExpr, }, } }, - lang_y::LExpr::IndexLExpr { span, lhs, index } => { + parser::LExpr::IndexLExpr { span, lhs, index } => { let ((var, var_typ), (idx_typ, mut idx)) - = process_lexpr(*lhs, lexer, stringtab, env, types)?; + = process_lexpr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let mut indices = vec![]; let mut errors = LinkedList::new(); for idx in index { let idx_span = idx.span(); - match process_expr(idx, lexer, stringtab, env, types) { + match process_expr(idx, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(exp) => { let typ = exp.get_type(); @@ -1927,14 +2013,14 @@ fn process_lexpr(expr : lang_y::LExpr, } } -fn process_expr_as_constant(expr : lang_y::Expr, +fn process_expr_as_constant(expr : parser::Expr, num_dyn_const : usize, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &mut Env<usize, Entity>, types : &mut TypeSolver) -> Result<Constant, ErrorMessages> { match expr { - lang_y::Expr::Variable { span, name } => { + parser::Expr::Variable { span, name } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -1972,9 +2058,9 @@ fn process_expr_as_constant(expr : lang_y::Expr, stringtab.lookup_id(nm).unwrap()))) } }, - lang_y::Expr::Field { span, lhs, rhs } => { + parser::Expr::Field { span, lhs, rhs } => { let field_name = intern_id(&rhs, lexer, stringtab); - let (lit, typ) = process_expr_as_constant(*lhs, lexer, stringtab, env, types)?; + let (lit, typ) = process_expr_as_constant(*lhs, num_dyn_const, lexer, stringtab, env, types)?; match types.get_field(typ, field_name) { None => Err(singleton_error( @@ -1989,8 +2075,8 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Expr::NumField { span, lhs, rhs } => { - let (lit, typ) = process_expr_as_constant(*lhs, lexer, stringtab, env, types)?; + parser::Expr::NumField { span, lhs, rhs } => { + let (lit, typ) = process_expr_as_constant(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let num = lexer.span_str(rhs)[1..].parse::<usize>() .expect("From lexical analysis"); @@ -2008,15 +2094,15 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Expr::ArrIndex { span, .. } => { + parser::Expr::ArrIndex { span, .. } => { Err(singleton_error( ErrorMessage::SemanticError( span_to_loc(span, lexer), format!("Arrays are not allowed in constants")))) }, - lang_y::Expr::Tuple { span : _, mut exprs } => { + parser::Expr::Tuple { span : _, mut exprs } => { if exprs.len() == 1 { - return process_expr_as_constant(exprs.pop().unwrap(), lexer, stringtab, env, types); + return process_expr_as_constant(exprs.pop().unwrap(), num_dyn_const, lexer, stringtab, env, types); } if exprs.len() == 0 { return Ok((Literal::Unit, types.new_primitive(types::Primitive::Unit))); @@ -2027,7 +2113,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, let mut errors = LinkedList::new(); for exp in exprs { - match process_expr_as_constant(exp, lexer, stringtab, env, types) { + match process_expr_as_constant(exp, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok((lit, typ)) => { typs.push(typ); @@ -2042,7 +2128,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, Ok((Literal::Tuple(vals), types.new_tuple(typs))) } }, - lang_y::Expr::Struct { span, name, ty_args, exprs } => { + parser::Expr::Struct { span, name, ty_args, exprs } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -2111,23 +2197,23 @@ fn process_expr_as_constant(expr : lang_y::Expr, for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dyn_consts.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -2142,9 +2228,9 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -2168,7 +2254,15 @@ fn process_expr_as_constant(expr : lang_y::Expr, if type_vars.len() == 0 && dyn_consts.len() == 0 { *typ } else { - types.instantiate(*typ, &type_vars, &dyn_consts) + if let Some(res) + = types.instantiate(*typ, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + } }; // Check each field and construct the appropriate tuple @@ -2200,7 +2294,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, format!("Field {} defined multiple times", stringtab.lookup_id(field_nm).unwrap()))); } else { - match process_expr_as_constant(expr, lexer, stringtab, env, types) { + match process_expr_as_constant(expr, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok((lit, typ)) => { if !types.equal(field_typ, typ) { @@ -2242,30 +2336,30 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Expr::BoolLit { span : _, value } => { + parser::Expr::BoolLit { span : _, value } => { let bool_typ = types.new_primitive(types::Primitive::Bool); Ok((Literal::Bool(value), bool_typ)) }, - lang_y::Expr::IntLit { span, base } => { + parser::Expr::IntLit { span, base } => { let res = u64::from_str_radix(lexer.span_str(span), base.base()); assert!(res.is_ok(), "Internal Error: Int literal is not an integer"); let num_typ = types.new_number(); Ok((Literal::Integer(res.unwrap()), num_typ)) }, - lang_y::Expr::FloatLit { span } => { + parser::Expr::FloatLit { span } => { let res = lexer.span_str(span).parse::<f64>(); assert!(res.is_ok(), "Internal Error: Float literal is not a float"); let float_typ = types.new_float(); Ok((Literal::Float(res.unwrap()), float_typ)) }, - lang_y::Expr::UnaryExpr { span, op, expr } => { + parser::Expr::UnaryExpr { span, op, expr } => { let (expr_lit, expr_typ) - = process_expr_as_constant(*expr, lexer, stringtab, env, types)?; + = process_expr_as_constant(*expr, num_dyn_const, lexer, stringtab, env, types)?; match op { - lang_y::UnaryOp::Negation => { + parser::UnaryOp::Negation => { if !types.is_number(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -2280,7 +2374,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, expr_typ)) } }, - lang_y::UnaryOp::BitwiseNot => { + parser::UnaryOp::BitwiseNot => { if !types.is_integer(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -2293,7 +2387,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, Ok((Literal::Integer(! i), expr_typ)) } }, - lang_y::UnaryOp::LogicalNot => { + parser::UnaryOp::LogicalNot => { if !types.is_bool(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -2308,12 +2402,12 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Expr::BinaryExpr { span : _, op, lhs, rhs } => { + parser::Expr::BinaryExpr { span : _, op, lhs, rhs } => { let lhs_span = lhs.span(); let rhs_span = rhs.span(); - let lhs_res = process_expr_as_constant(*lhs, lexer, stringtab, env, types); - let rhs_res = process_expr_as_constant(*rhs, lexer, stringtab, env, types); + let lhs_res = process_expr_as_constant(*lhs, num_dyn_const, lexer, stringtab, env, types); + let rhs_res = process_expr_as_constant(*rhs, num_dyn_const, lexer, stringtab, env, types); let ((lhs_lit, lhs_typ), (rhs_lit, rhs_typ)) = append_errors2(lhs_res, rhs_res)?; @@ -2321,7 +2415,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, // First, type-check match op { // Equality and inequality work on any types - lang_y::BinaryOp::Eq | lang_y::BinaryOp::Neq => { + parser::BinaryOp::Eq | parser::BinaryOp::Neq => { if !types.equal(lhs_typ, rhs_typ) { return Err(singleton_error( ErrorMessage::TypeError( @@ -2331,9 +2425,9 @@ fn process_expr_as_constant(expr : lang_y::Expr, } }, // These work on any numbers - lang_y::BinaryOp::Add | lang_y::BinaryOp::Sub | lang_y::BinaryOp::Mul - | lang_y::BinaryOp::Div | lang_y::BinaryOp::Lt | lang_y::BinaryOp::Le - | lang_y::BinaryOp::Gt | lang_y::BinaryOp::Ge => { + parser::BinaryOp::Add | parser::BinaryOp::Sub | parser::BinaryOp::Mul + | parser::BinaryOp::Div | parser::BinaryOp::Lt | parser::BinaryOp::Le + | parser::BinaryOp::Gt | parser::BinaryOp::Ge => { let mut errors = LinkedList::new(); let lhs_number = types.is_number(lhs_typ); let rhs_number = types.is_number(rhs_typ); @@ -2371,8 +2465,8 @@ fn process_expr_as_constant(expr : lang_y::Expr, if !errors.is_empty() { return Err(errors); } }, - lang_y::BinaryOp::Mod | lang_y::BinaryOp::BitAnd | lang_y::BinaryOp::BitOr - | lang_y::BinaryOp::Xor | lang_y::BinaryOp::LShift | lang_y::BinaryOp::RShift + parser::BinaryOp::Mod | parser::BinaryOp::BitAnd | parser::BinaryOp::BitOr + | parser::BinaryOp::Xor | parser::BinaryOp::LShift | parser::BinaryOp::RShift => { let mut errors = LinkedList::new(); let lhs_integer = types.is_integer(lhs_typ); @@ -2411,7 +2505,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, if !errors.is_empty() { return Err(errors); } }, - lang_y::BinaryOp::LogAnd | lang_y::BinaryOp::LogOr => { + parser::BinaryOp::LogAnd | parser::BinaryOp::LogOr => { let mut errors = LinkedList::new(); let lhs_bool = types.is_bool(lhs_typ); let rhs_bool = types.is_bool(rhs_typ); @@ -2452,7 +2546,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, }; match op { - lang_y::BinaryOp::Add => { + parser::BinaryOp::Add => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i + j), lhs_typ)), @@ -2465,7 +2559,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Sub => { + parser::BinaryOp::Sub => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer((i as i64 - j as i64) as u64), lhs_typ)), @@ -2478,7 +2572,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Mul => { + parser::BinaryOp::Mul => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i * j), lhs_typ)), @@ -2491,7 +2585,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Div => { + parser::BinaryOp::Div => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i / j), lhs_typ)), @@ -2504,35 +2598,35 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Mod => { + parser::BinaryOp::Mod => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i % j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::BitAnd => { + parser::BinaryOp::BitAnd => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i & j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::BitOr => { + parser::BinaryOp::BitOr => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i | j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Xor => { + parser::BinaryOp::Xor => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i ^ j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Lt => { + parser::BinaryOp::Lt => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2546,7 +2640,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Le => { + parser::BinaryOp::Le => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2560,7 +2654,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Gt => { + parser::BinaryOp::Gt => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2574,7 +2668,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Ge => { + parser::BinaryOp::Ge => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2588,7 +2682,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::Eq => { + parser::BinaryOp::Eq => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2603,7 +2697,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, => Ok((Literal::Bool(lhs_lit == rhs_lit), bool_typ)), } }, - lang_y::BinaryOp::Neq => { + parser::BinaryOp::Neq => { let bool_typ = types.new_primitive(types::Primitive::Bool); match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) @@ -2618,28 +2712,28 @@ fn process_expr_as_constant(expr : lang_y::Expr, => Ok((Literal::Bool(lhs_lit != rhs_lit), bool_typ)), } }, - lang_y::BinaryOp::LShift => { + parser::BinaryOp::LShift => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i << j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::RShift => { + parser::BinaryOp::RShift => { match (lhs_lit, rhs_lit) { (Literal::Integer(i), Literal::Integer(j)) => Ok((Literal::Integer(i >> j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::LogAnd => { + parser::BinaryOp::LogAnd => { match (lhs_lit, rhs_lit) { (Literal::Bool(i), Literal::Bool(j)) => Ok((Literal::Bool(i && j), lhs_typ)), _ => panic!("Incorrect literal constructor"), } }, - lang_y::BinaryOp::LogOr => { + parser::BinaryOp::LogOr => { match (lhs_lit, rhs_lit) { (Literal::Bool(i), Literal::Bool(j)) => Ok((Literal::Bool(i || j), lhs_typ)), @@ -2648,10 +2742,10 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Expr::CastExpr { span, expr, typ } => { + parser::Expr::CastExpr { span, expr, typ } => { // Cast between numeric types - let expr_res = process_expr_as_constant(*expr, lexer, stringtab, env, types); - let type_res = process_type(typ, lexer, stringtab, env, types); + let expr_res = process_expr_as_constant(*expr, num_dyn_const, lexer, stringtab, env, types); + let type_res = process_type(typ, num_dyn_const, lexer, stringtab, env, types); let ((expr_lit, expr_typ), to_typ) = append_errors2(expr_res, type_res)?; @@ -2678,12 +2772,12 @@ fn process_expr_as_constant(expr : lang_y::Expr, } } }, - lang_y::Expr::CondExpr { span, cond, thn, els } => { + parser::Expr::CondExpr { span, cond, thn, els } => { let cond_span = cond.span(); - let cond_res = process_expr_as_constant(*cond, lexer, stringtab, env, types); - let thn_res = process_expr_as_constant(*thn, lexer, stringtab, env, types); - let els_res = process_expr_as_constant(*els, lexer, stringtab, env, types); + let cond_res = process_expr_as_constant(*cond, num_dyn_const, lexer, stringtab, env, types); + let thn_res = process_expr_as_constant(*thn, num_dyn_const, lexer, stringtab, env, types); + let els_res = process_expr_as_constant(*els, num_dyn_const, lexer, stringtab, env, types); let ((cond_lit, cond_typ), (thn_lit, thn_typ), (els_lit, els_typ)) = append_errors3(cond_res, thn_res, els_res)?; @@ -2713,7 +2807,7 @@ fn process_expr_as_constant(expr : lang_y::Expr, if condition { Ok((thn_lit, thn_typ)) } else { Ok((els_lit, els_typ)) } } }, - lang_y::Expr::CallExpr { span, name, ty_args, args } => { + parser::Expr::CallExpr { span, name, ty_args, args } => { // While calls cannot be evaluated as constants, enum values can be, so we need to // distinguish whether this is actually a call or the construction of some enum value if name.len() > 2 { @@ -2810,23 +2904,23 @@ fn process_expr_as_constant(expr : lang_y::Expr, for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dyn_consts.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -2841,9 +2935,9 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -2867,7 +2961,15 @@ fn process_expr_as_constant(expr : lang_y::Expr, if type_vars.len() == 0 && dyn_consts.len() == 0 { *typ } else { - types.instantiate(*typ, &type_vars, &dyn_consts) + if let Some(res) + = types.instantiate(*typ, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + } }; let Some((constr_idx, constr_typ)) = types.get_constructor_info(union_type, nm[1]) @@ -2888,10 +2990,10 @@ fn process_expr_as_constant(expr : lang_y::Expr, let (body_lit, body_typ) = process_expr_as_constant( - lang_y::Expr::Tuple { + parser::Expr::Tuple { span : span, exprs : args.into_iter().map(|(_, a)| a).collect::<Vec<_>>() }, - lexer, stringtab, env, types)?; + num_dyn_const, lexer, stringtab, env, types)?; if !types.equal(constr_typ, body_typ) { Err(singleton_error( @@ -2906,16 +3008,23 @@ fn process_expr_as_constant(expr : lang_y::Expr, }, } }, + parser::Expr::IntrinsicExpr { span, .. } => { + Err(singleton_error( + ErrorMessage::NotImplemented( + span_to_loc(span, lexer), + "Intrinsics evaluated as constants".to_string()))) + }, } } -fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, +fn process_expr(expr : parser::Expr, num_dyn_const : usize, + lexer : &dyn NonStreamingLexer<DefaultLexerTypes<u32>>, stringtab : &mut StringTable, env : &mut Env<usize, Entity>, types : &mut TypeSolver) -> Result<Expr, ErrorMessages> { match expr { - lang_y::Expr::Variable { span, name } => { + parser::Expr::Variable { span, name } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -2930,7 +3039,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, Some(Entity::DynConst { value }) => { let typ = types.new_primitive(types::Primitive::U64); - Ok(Expr::DynConst { idx : *value, typ : typ }) + Ok(Expr::DynConst { val : value.clone(), typ : typ }) }, Some(Entity::Constant { value : (lit, typ) }) => { Ok(Expr::Constant { val : (lit.clone(), *typ), typ : *typ }) @@ -2954,9 +3063,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer stringtab.lookup_id(nm).unwrap()))) } }, - lang_y::Expr::Field { span, lhs, rhs } => { + parser::Expr::Field { span, lhs, rhs } => { let field_name = intern_id(&rhs, lexer, stringtab); - let exp = process_expr(*lhs, lexer, stringtab, env, types)?; + let exp = process_expr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let exp_typ = exp.get_type(); match types.get_field(exp_typ, field_name) { @@ -2973,8 +3082,8 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : field_type }), } }, - lang_y::Expr::NumField { span, lhs, rhs } => { - let exp = process_expr(*lhs, lexer, stringtab, env, types)?; + parser::Expr::NumField { span, lhs, rhs } => { + let exp = process_expr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let exp_typ = exp.get_type(); let num = lexer.span_str(rhs)[1..].parse::<usize>() @@ -2994,15 +3103,15 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : field_type }), } }, - lang_y::Expr::ArrIndex { span, lhs, index } => { - let exp = process_expr(*lhs, lexer, stringtab, env, types)?; + parser::Expr::ArrIndex { span, lhs, index } => { + let exp = process_expr(*lhs, num_dyn_const, lexer, stringtab, env, types)?; let exp_typ = exp.get_type(); let mut indices = vec![]; let mut errors = LinkedList::new(); for idx in index { let idx_span = idx.span(); - match process_expr(idx, lexer, stringtab, env, types) { + match process_expr(idx, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(exp) => { let typ = exp.get_type(); @@ -3051,9 +3160,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : types.get_element_type(exp_typ).unwrap() }) } }, - lang_y::Expr::Tuple { span : _, mut exprs } => { + parser::Expr::Tuple { span : _, mut exprs } => { if exprs.len() == 1 { - return process_expr(exprs.pop().unwrap(), lexer, stringtab, env, types); + return process_expr(exprs.pop().unwrap(), num_dyn_const, lexer, stringtab, env, types); } if exprs.len() == 0 { let unit_type = types.new_primitive(types::Primitive::Unit); @@ -3067,7 +3176,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer let mut errors = LinkedList::new(); for exp in exprs { - match process_expr(exp, lexer, stringtab, env, types) { + match process_expr(exp, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => { typs.push(val.get_type()); @@ -3084,7 +3193,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : types.new_tuple(typs) }) } }, - lang_y::Expr::Struct { span, name, ty_args, exprs } => { + parser::Expr::Struct { span, name, ty_args, exprs } => { if name.len() != 1 { Err(singleton_error( ErrorMessage::NotImplemented( @@ -3153,23 +3262,23 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dyn_consts.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -3184,9 +3293,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -3210,7 +3319,15 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer if type_vars.len() == 0 && dyn_consts.len() == 0 { *typ } else { - types.instantiate(*typ, &type_vars, &dyn_consts) + if let Some(res) + = types.instantiate(*typ, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + } }; // Check each field and construct the appropriate tuple @@ -3242,7 +3359,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer format!("Field {} defined multiple times", stringtab.lookup_id(field_nm).unwrap()))); } else { - match process_expr(expr, lexer, stringtab, env, types) { + match process_expr(expr, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => { let val_typ = val.get_type(); @@ -3281,13 +3398,13 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Expr::BoolLit { span : _, value } => { + parser::Expr::BoolLit { span : _, value } => { let bool_typ = types.new_primitive(types::Primitive::Bool); Ok(Expr::Constant { val : (Literal::Bool(value), bool_typ), typ : bool_typ }) }, - lang_y::Expr::IntLit { span, base } => { + parser::Expr::IntLit { span, base } => { let res = u64::from_str_radix(lexer.span_str(span), base.base()); assert!(res.is_ok(), "Internal Error: Int literal is not an integer"); @@ -3296,7 +3413,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer val : (Literal::Integer(res.unwrap()), num_typ), typ : num_typ }) }, - lang_y::Expr::FloatLit { span } => { + parser::Expr::FloatLit { span } => { let res = lexer.span_str(span).parse::<f64>(); assert!(res.is_ok(), "Internal Error: Float literal is not a float"); @@ -3305,12 +3422,12 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer val : (Literal::Float(res.unwrap()), float_typ), typ : float_typ }) }, - lang_y::Expr::UnaryExpr { span, op, expr } => { - let expr_val = process_expr(*expr, lexer, stringtab, env, types)?; + parser::Expr::UnaryExpr { span, op, expr } => { + let expr_val = process_expr(*expr, num_dyn_const, lexer, stringtab, env, types)?; let expr_typ = expr_val.get_type(); match op { - lang_y::UnaryOp::Negation => { + parser::UnaryOp::Negation => { if !types.is_number(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -3324,7 +3441,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : expr_typ }) } }, - lang_y::UnaryOp::BitwiseNot => { + parser::UnaryOp::BitwiseNot => { if !types.is_integer(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -3338,7 +3455,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : expr_typ }) } }, - lang_y::UnaryOp::LogicalNot => { + parser::UnaryOp::LogicalNot => { if !types.is_bool(expr_typ) { Err(singleton_error( ErrorMessage::TypeError( @@ -3364,12 +3481,12 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Expr::BinaryExpr { span : _, op, lhs, rhs } => { + parser::Expr::BinaryExpr { span : _, op, lhs, rhs } => { let lhs_span = lhs.span(); let rhs_span = rhs.span(); - let lhs_res = process_expr(*lhs, lexer, stringtab, env, types); - let rhs_res = process_expr(*rhs, lexer, stringtab, env, types); + let lhs_res = process_expr(*lhs, num_dyn_const, lexer, stringtab, env, types); + let rhs_res = process_expr(*rhs, num_dyn_const, lexer, stringtab, env, types); let (lhs_val, rhs_val) = append_errors2(lhs_res, rhs_res)?; let lhs_typ = lhs_val.get_type(); @@ -3378,7 +3495,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer // First, type-check match op { // Equality and inequality work on any types - lang_y::BinaryOp::Eq | lang_y::BinaryOp::Neq => { + parser::BinaryOp::Eq | parser::BinaryOp::Neq => { if !types.equal(lhs_typ, rhs_typ) { return Err(singleton_error( ErrorMessage::TypeError( @@ -3388,9 +3505,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer } }, // These work on any numbers - lang_y::BinaryOp::Add | lang_y::BinaryOp::Sub | lang_y::BinaryOp::Mul - | lang_y::BinaryOp::Div | lang_y::BinaryOp::Lt | lang_y::BinaryOp::Le - | lang_y::BinaryOp::Gt | lang_y::BinaryOp::Ge => { + parser::BinaryOp::Add | parser::BinaryOp::Sub | parser::BinaryOp::Mul + | parser::BinaryOp::Div | parser::BinaryOp::Lt | parser::BinaryOp::Le + | parser::BinaryOp::Gt | parser::BinaryOp::Ge => { let mut errors = LinkedList::new(); let lhs_number = types.is_number(lhs_typ); let rhs_number = types.is_number(rhs_typ); @@ -3429,8 +3546,8 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer if !errors.is_empty() { return Err(errors); } }, // These work on integer inputs - lang_y::BinaryOp::Mod | lang_y::BinaryOp::BitAnd | lang_y::BinaryOp::BitOr - | lang_y::BinaryOp::Xor | lang_y::BinaryOp::LShift | lang_y::BinaryOp::RShift + parser::BinaryOp::Mod | parser::BinaryOp::BitAnd | parser::BinaryOp::BitOr + | parser::BinaryOp::Xor | parser::BinaryOp::LShift | parser::BinaryOp::RShift => { let mut errors = LinkedList::new(); let lhs_integer = types.is_integer(lhs_typ); @@ -3470,7 +3587,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer if !errors.is_empty() { return Err(errors); } }, // These work on boolean inputs - lang_y::BinaryOp::LogAnd | lang_y::BinaryOp::LogOr => { + parser::BinaryOp::LogAnd | parser::BinaryOp::LogOr => { let mut errors = LinkedList::new(); let lhs_bool = types.is_bool(lhs_typ); let rhs_bool = types.is_bool(rhs_typ); @@ -3514,7 +3631,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer // The binary operations are compiled into conditional expressions: // x && y = if x then y else false // x || y = if x then true else y - lang_y::BinaryOp::LogAnd => { + parser::BinaryOp::LogAnd => { let false_val = Expr::Constant { val : (Literal::Bool(false), lhs_typ), @@ -3525,7 +3642,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer els : Box::new(false_val), typ : lhs_typ }) }, - lang_y::BinaryOp::LogOr => { + parser::BinaryOp::LogOr => { let true_val = Expr::Constant { val : (Literal::Bool(true), lhs_typ), @@ -3538,9 +3655,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, // For comparison operators, the resulting type is a boolean, while for all other // operations the result is the same as the two operands - lang_y::BinaryOp::Lt | lang_y::BinaryOp::Le - | lang_y::BinaryOp::Gt | lang_y::BinaryOp::Ge - | lang_y::BinaryOp::Eq | lang_y::BinaryOp::Neq => { + parser::BinaryOp::Lt | parser::BinaryOp::Le + | parser::BinaryOp::Gt | parser::BinaryOp::Ge + | parser::BinaryOp::Eq | parser::BinaryOp::Neq => { Ok(Expr::BinaryExp { op : convert_binary_op(op), lhs : Box::new(lhs_val), @@ -3556,11 +3673,11 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Expr::CastExpr { span, expr, typ } => { + parser::Expr::CastExpr { span, expr, typ } => { // For the moment at least, casting is only supported between numeric types, and all // numeric types can be cast to each other - let expr_res = process_expr(*expr, lexer, stringtab, env, types); - let type_res = process_type(typ, lexer, stringtab, env, types); + let expr_res = process_expr(*expr, num_dyn_const, lexer, stringtab, env, types); + let type_res = process_type(typ, num_dyn_const, lexer, stringtab, env, types); let (expr_val, to_typ) = append_errors2(expr_res, type_res)?; let expr_typ = expr_val.get_type(); @@ -3577,12 +3694,12 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : to_typ }) } }, - lang_y::Expr::CondExpr { span, cond, thn, els } => { + parser::Expr::CondExpr { span, cond, thn, els } => { let cond_span = cond.span(); - let cond_res = process_expr(*cond, lexer, stringtab, env, types); - let thn_res = process_expr(*thn, lexer, stringtab, env, types); - let els_res = process_expr(*els, lexer, stringtab, env, types); + let cond_res = process_expr(*cond, num_dyn_const, lexer, stringtab, env, types); + let thn_res = process_expr(*thn, num_dyn_const, lexer, stringtab, env, types); + let els_res = process_expr(*els, num_dyn_const, lexer, stringtab, env, types); let (cond_val, thn_val, els_val) = append_errors3(cond_res, thn_res, els_res)?; @@ -3619,7 +3736,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer typ : thn_typ }) } }, - lang_y::Expr::CallExpr { span, name, ty_args, args } => { + parser::Expr::CallExpr { span, name, ty_args, args } => { // In the AST from the parser we have no way to distinguish between function calls and // union construction. We have to identify which case we're in here. We do this by // identifying whether the name (looking for the moment at just the first part of the @@ -3714,23 +3831,23 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dyn_consts.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -3745,9 +3862,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -3771,7 +3888,15 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer if type_vars.len() == 0 && dyn_consts.len() == 0 { *typ } else { - types.instantiate(*typ, &type_vars, &dyn_consts) + if let Some(res) + = types.instantiate(*typ, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + } }; let Some((constr_idx, constr_typ)) = types.get_constructor_info(union_type, nm[1]) @@ -3791,10 +3916,10 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer } let body = process_expr( - lang_y::Expr::Tuple { + parser::Expr::Tuple { span : span, exprs : args.into_iter().map(|(_, a)| a).collect::<Vec<_>>() }, - lexer, stringtab, env, types)?; + num_dyn_const, lexer, stringtab, env, types)?; let body_typ = body.get_type(); if !types.equal(constr_typ, body_typ) { @@ -3830,23 +3955,23 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { let arg_span = arg.span(); match kind { - lang_y::Kind::USize => { + parser::Kind::USize => { match process_type_expr_as_expr( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(val) => dyn_consts.push(val), } }, - lang_y::Kind::Type => { + parser::Kind::Type => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => type_vars.push(typ), } }, - lang_y::Kind::Number => { + parser::Kind::Number => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_number(typ) { @@ -3861,9 +3986,9 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, - lang_y::Kind::Integer => { + parser::Kind::Integer => { match process_type_expr_as_type( - arg, lexer, stringtab, env, types) { + arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(typ) => { if types.is_integer(typ) { @@ -3890,13 +4015,29 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer let mut tys = vec![]; for (t, inout) in func_args { tys.push(( - types.instantiate(*t, &type_vars, &dyn_consts), + if let Some(res) + = types.instantiate(*t, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + }, *inout)); } tys }; let return_typ = - types.instantiate(*return_type, &type_vars, &dyn_consts); + if let Some(res) + = types.instantiate(*return_type, &type_vars, &dyn_consts) { + res + } else { + return Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + "Failure in variable substitution".to_string()))); + }; // Now, process the arguments to ensure they has the type needed by this // constructor @@ -3920,7 +4061,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer format!("Argument should not be inout"))); } else if is_inout { // If the argument is an inout then it needs to just be a variable - match process_expr(arg, lexer, stringtab, env, types) { + match process_expr(arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(Expr::Variable { var, typ }) => { if !types.equal(arg_typ, typ) { @@ -3941,7 +4082,7 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } } else { - match process_expr(arg, lexer, stringtab, env, types) { + match process_expr(arg, num_dyn_const, lexer, stringtab, env, types) { Err(mut errs) => errors.append(&mut errs), Ok(exp) => { if !types.equal(arg_typ, exp.get_type()) { @@ -3971,6 +4112,167 @@ fn process_expr(expr : lang_y::Expr, lexer : &dyn NonStreamingLexer<DefaultLexer }, } }, + parser::Expr::IntrinsicExpr { span, name, ty_args, args } => { + if name.len() != 1 { + Err(singleton_error( + ErrorMessage::NotImplemented( + span_to_loc(span, lexer), + "packages".to_string())))? + } + + let nm = lexer.span_str(name[0]); + match intrinsics::lookup(nm) { + None => + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + format!("Undefined intrinsic {}", nm)))), + Some(intrinsic) => { + let kinds = intrinsic.kinds; + if ty_args.len() != kinds.len() { + Err(singleton_error( + ErrorMessage::SemanticError( + span_to_loc(span, lexer), + format!("Expected {} type arguments, provided {}", + kinds.len(), ty_args.len()))))? + } + + let mut type_vars = vec![]; + let mut dyn_consts = vec![]; + let mut errors = LinkedList::new(); + + for (arg, kind) in ty_args.into_iter().zip(kinds.iter()) { + let arg_span = arg.span(); + match kind { + parser::Kind::USize => { + match process_type_expr_as_expr( + arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(val) => dyn_consts.push(val), + } + }, + parser::Kind::Type => { + match process_type_expr_as_type( + arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(typ) => type_vars.push(typ), + } + }, + parser::Kind::Number => { + match process_type_expr_as_type( + arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(typ) => { + if types.is_number(typ) { + type_vars.push(typ); + } else { + errors.push_back( + ErrorMessage::KindError( + span_to_loc(arg_span, lexer), + "number".to_string(), + unparse_type(types, typ, stringtab))); + } + }, + } + }, + parser::Kind::Integer => { + match process_type_expr_as_type( + arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(typ) => { + if types.is_integer(typ) { + type_vars.push(typ); + } else { + errors.push_back( + ErrorMessage::KindError( + span_to_loc(arg_span, lexer), + "integer".to_string(), + unparse_type(types, typ, stringtab))); + } + }, + } + }, + } + } + + if !errors.is_empty() { return Err(errors); } + + let arg_types = (intrinsic.args)(&type_vars, types); + let return_typ = (intrinsic.ret_typ)(&type_vars, types); + + // Now, process the arguments to ensure they has the type needed by this + // constructor + let mut arg_vals : Vec<Either<Expr, usize>> = vec![]; + let mut errors = LinkedList::new(); + + for ((is_inout, arg), (arg_typ, expect_inout)) + in args.into_iter().zip(arg_types.into_iter()) { + + let arg_span = arg.span(); + + if is_inout && !expect_inout { + errors.push_back( + ErrorMessage::SemanticError( + span_to_loc(arg_span, lexer), + format!("Argument should be inout"))); + } else if !is_inout && expect_inout { + errors.push_back( + ErrorMessage::SemanticError( + span_to_loc(arg_span, lexer), + format!("Argument should not be inout"))); + } else if is_inout { + // If the argument is an inout then it needs to just be a variable + match process_expr(arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(Expr::Variable { var, typ }) => { + if !types.equal(arg_typ, typ) { + errors.push_back( + ErrorMessage::TypeError( + span_to_loc(arg_span, lexer), + unparse_type(types, arg_typ, stringtab), + unparse_type(types, typ, stringtab))); + } else { + arg_vals.push(Either::Right(var)); + } + }, + Ok(_) => { + errors.push_back( + ErrorMessage::SemanticError( + span_to_loc(arg_span, lexer), + format!("An inout argument must just be a variable"))); + }, + } + } else { + match process_expr(arg, num_dyn_const, lexer, stringtab, env, types) { + Err(mut errs) => errors.append(&mut errs), + Ok(exp) => { + if !types.equal(arg_typ, exp.get_type()) { + errors.push_back( + ErrorMessage::TypeError( + span_to_loc(arg_span, lexer), + unparse_type(types, arg_typ, stringtab), + unparse_type(types, exp.get_type(), stringtab))); + } else { + arg_vals.push(Either::Left(exp)); + } + }, + } + } + } + + if !errors.is_empty() { + Err(errors) + } else { + Ok(Expr::Intrinsic { + id : intrinsic.id, + ty_args : type_vars, + dyn_consts : dyn_consts, + args : arg_vals, + typ : return_typ }) + } + }, + } + }, } } @@ -3991,20 +4293,20 @@ fn generate_return(expr : Expr, vars : &Vec<usize>, var_types : &Vec<Type>, Stmt::ReturnStmt { expr : val } } -fn convert_primitive(prim : lang_y::Primitive) -> types::Primitive { +fn convert_primitive(prim : parser::Primitive) -> types::Primitive { match prim { - lang_y::Primitive::Bool => types::Primitive::Bool, - lang_y::Primitive::I8 => types::Primitive::I8, - lang_y::Primitive::U8 => types::Primitive::U8, - lang_y::Primitive::I16 => types::Primitive::I16, - lang_y::Primitive::U16 => types::Primitive::U16, - lang_y::Primitive::I32 => types::Primitive::I32, - lang_y::Primitive::U32 => types::Primitive::U32, - lang_y::Primitive::I64 => types::Primitive::I64, - lang_y::Primitive::U64 => types::Primitive::U64, - lang_y::Primitive::USize=> types::Primitive::U64, - lang_y::Primitive::F32 => types::Primitive::F32, - lang_y::Primitive::F64 => types::Primitive::F64, - lang_y::Primitive::Void => types::Primitive::Unit, + parser::Primitive::Bool => types::Primitive::Bool, + parser::Primitive::I8 => types::Primitive::I8, + parser::Primitive::U8 => types::Primitive::U8, + parser::Primitive::I16 => types::Primitive::I16, + parser::Primitive::U16 => types::Primitive::U16, + parser::Primitive::I32 => types::Primitive::I32, + parser::Primitive::U32 => types::Primitive::U32, + parser::Primitive::I64 => types::Primitive::I64, + parser::Primitive::U64 => types::Primitive::U64, + parser::Primitive::USize=> types::Primitive::U64, + parser::Primitive::F32 => types::Primitive::F32, + parser::Primitive::F64 => types::Primitive::F64, + parser::Primitive::Void => types::Primitive::Unit, } } diff --git a/juno_frontend/src/types.rs b/juno_frontend/src/types.rs index 03702f360d7a3cbeb9f9aa4a178b8b74c163f221..d6e87666f4d9f4f32538be9efd92f157dee95492 100644 --- a/juno_frontend/src/types.rs +++ b/juno_frontend/src/types.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use crate::hercules_ir::ir::*; use crate::hercules_ir::build::*; +use crate::dynconst::DynConst; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Either<A, B> { @@ -9,38 +10,6 @@ pub enum Either<A, B> { Right(B) } -#[derive(Copy, Clone, Eq, Debug)] -pub enum DynamicConstant { - Constant(usize), // constant value - DynConst(usize, usize) // name and dynamic constant number -} - -impl PartialEq for DynamicConstant { - fn eq(&self, other : &Self) -> bool { - match (self, other) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => x == y, - (DynamicConstant::DynConst(_, n), DynamicConstant::DynConst(_, m)) => n == m, - (_, _) => false, - } - } -} - -impl DynamicConstant { - fn subst(&self, dyn_consts : &Vec<DynamicConstant>) -> DynamicConstant { - match self { - DynamicConstant::Constant(val) => DynamicConstant::Constant(*val), - DynamicConstant::DynConst(_, idx) => dyn_consts[*idx], - } - } - - fn to_string(&self, stringtab : &dyn Fn(usize) -> String) -> String { - match self { - DynamicConstant::Constant(val) => val.to_string(), - DynamicConstant::DynConst(nm, _) => stringtab(*nm), - } - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Primitive { Bool, U8, I8, U16, I16, U32, I32, U64, I64, F32, F64, Unit } @@ -100,7 +69,7 @@ pub struct Type { val : usize } enum TypeForm { Primitive(Primitive), Tuple(Vec<Type>), - Array(Type, Vec<DynamicConstant>), + Array(Type, Vec<DynConst>), // This type is the same type as another type OtherType(Type), @@ -158,7 +127,7 @@ impl TypeSolver { self.create_type(TypeForm::Tuple(fields)) } - pub fn new_array(&mut self, element : Type, dims : Vec<DynamicConstant>) -> Type { + pub fn new_array(&mut self, element : Type, dims : Vec<DynConst>) -> Type { self.create_type(TypeForm::Array(element, dims)) } @@ -351,7 +320,7 @@ impl TypeSolver { } } - pub fn get_dimensions(&self, Type { val } : Type) -> Option<Vec<DynamicConstant>> { + pub fn get_dimensions(&self, Type { val } : Type) -> Option<Vec<DynConst>> { match &self.types[val] { TypeForm::Array(_, dims) => Some(dims.to_vec()), TypeForm::OtherType(t) => self.get_dimensions(*t), @@ -419,10 +388,20 @@ impl TypeSolver { self.types[ty2] = TypeForm::OtherType(Type { val : ty1 }); true }, + (TypeForm::TypeVar { name : _, index : _, is_num, .. }, TypeForm::AnyNumber) if is_num => { + self.types[ty2] = TypeForm::OtherType(Type { val : ty1 }); + true + }, + (TypeForm::Primitive(p), TypeForm::AnyInteger) if p.is_integer() => { self.types[ty2] = TypeForm::OtherType(Type { val : ty1 }); true }, + (TypeForm::TypeVar { name : _, index : _, is_num : _, is_int }, TypeForm::AnyInteger) if is_int => { + self.types[ty2] = TypeForm::OtherType(Type { val : ty1 }); + true + }, + (TypeForm::Primitive(p), TypeForm::AnyFloat) if p.is_float() => { self.types[ty2] = TypeForm::OtherType(Type { val : ty1 }); true @@ -432,10 +411,20 @@ impl TypeSolver { self.types[ty1] = TypeForm::OtherType(Type { val : ty2 }); true }, + (TypeForm::AnyNumber, TypeForm::TypeVar { name : _, index : _, is_num, .. }) if is_num => { + self.types[ty1] = TypeForm::OtherType(Type { val : ty2 }); + true + }, + (TypeForm::AnyInteger, TypeForm::Primitive(p)) if p.is_number() => { self.types[ty1] = TypeForm::OtherType(Type { val : ty2 }); true }, + (TypeForm::AnyInteger, TypeForm::TypeVar { name : _, index : _, is_num : _, is_int }) if is_int => { + self.types[ty1] = TypeForm::OtherType(Type { val : ty2 }); + true + }, + (TypeForm::AnyFloat, TypeForm::Primitive(p)) if p.is_float() => { self.types[ty1] = TypeForm::OtherType(Type { val : ty2 }); true @@ -513,11 +502,11 @@ impl TypeSolver { // Instantiate a type using the provided list of type variables and dynamic constants // This is useful for instantiating the return type of a function and parametric types pub fn instantiate(&mut self, Type { val } : Type, type_vars : &Vec<Type>, - dynamic_constants : &Vec<DynamicConstant>) -> Type { + dynamic_constants : &Vec<DynConst>) -> Option<Type> { match self.types[val].clone() { - TypeForm::Primitive(_) => Type { val }, + TypeForm::Primitive(_) => Some(Type { val }), TypeForm::AnyNumber | TypeForm::AnyInteger | TypeForm::AnyFloat => { - self.create_type(self.types[val].clone()) + Some(self.create_type(self.types[val].clone())) }, TypeForm::OtherType(t) => self.instantiate(t, type_vars, dynamic_constants), @@ -525,55 +514,58 @@ impl TypeSolver { let mut types = vec![]; let mut changed = false; for typ in fields { - let inst = self.instantiate(typ, type_vars, dynamic_constants); + let inst = self.instantiate(typ, type_vars, dynamic_constants)?; changed = changed || typ.val != inst.val; types.push(inst); } - if changed { self.create_type(TypeForm::Tuple(types)) } - else { Type { val } } + if changed { Some(self.create_type(TypeForm::Tuple(types))) } + else { Some(Type { val }) } }, TypeForm::Array(elem, dims) => { - let elem_typ = self.instantiate(elem, type_vars, dynamic_constants); - let subst_dims = - dims.iter().map(|c| c.subst(dynamic_constants)).collect::<Vec<_>>(); + let elem_typ = self.instantiate(elem, type_vars, dynamic_constants)?; + let mut subst_dims = vec![]; + + for c in dims.iter() { + subst_dims.push(c.subst(dynamic_constants)?); + } - self.create_type(TypeForm::Array(elem_typ, subst_dims)) + Some(self.create_type(TypeForm::Array(elem_typ, subst_dims))) }, TypeForm::TypeVar { name : _, index, is_num, is_int } => { let typ = type_vars[index]; assert!(!is_num || self.is_number(typ)); assert!(!is_int || self.is_integer(typ)); - typ + Some(typ) }, TypeForm::Struct { name, id, fields, names } => { let mut new_fields = vec![]; let mut changed = false; for typ in fields { - let inst = self.instantiate(typ, type_vars, dynamic_constants); + let inst = self.instantiate(typ, type_vars, dynamic_constants)?; changed = changed || typ.val != inst.val; new_fields.push(inst); } - if changed { self.create_type(TypeForm::Struct { + if changed { Some(self.create_type(TypeForm::Struct { name : name, id : id, fields : new_fields, - names : names.clone() }) } - else { Type { val } } + names : names.clone() })) } + else { Some(Type { val }) } }, TypeForm::Union { name, id, constr, names } => { let mut new_constr = vec![]; let mut changed = false; for typ in constr { - let inst = self.instantiate(typ, type_vars, dynamic_constants); + let inst = self.instantiate(typ, type_vars, dynamic_constants)?; changed = changed || typ.val != inst.val; new_constr.push(inst); } - if changed { self.create_type(TypeForm::Union { + if changed { Some(self.create_type(TypeForm::Union { name : name, id : id, constr : new_constr, - names : names.clone() }) } - else { Type { val } } + names : names.clone() })) } + else { Some(Type { val }) } }, } } @@ -741,23 +733,16 @@ impl TypeSolverInst<'_> { builder.create_type_sum(tys.into()) } - fn build_array(builder : &mut Builder, elem : TypeID, dims : &Vec<DynamicConstant>) -> TypeID { + fn build_array(builder : &mut Builder, elem : TypeID, dims : &Vec<DynConst>) -> TypeID { let extents = Self::build_dyn_consts(builder, dims); builder.create_type_array(elem, extents.into()) } - pub fn build_dyn_consts(builder : &mut Builder, vals : &Vec<DynamicConstant>) -> Vec<DynamicConstantID> { + pub fn build_dyn_consts(builder : &mut Builder, vals : &Vec<DynConst>) -> Vec<DynamicConstantID> { let mut res = vec![]; for val in vals { - res.push(Self::build_dyn_const(builder, val)); + res.push(val.build(builder)); } res } - - pub fn build_dyn_const(builder : &mut Builder, val : &DynamicConstant) -> DynamicConstantID { - match val { - DynamicConstant::Constant(val) => builder.create_dynamic_constant_constant(*val), - DynamicConstant::DynConst(_, num) => builder.create_dynamic_constant_parameter(*num), - } - } }