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),
-        }
-    }
 }