From 7663c7ad4e36be2e16af2b53f2c7c844f8a9aded Mon Sep 17 00:00:00 2001 From: sebastianselander Date: Fri, 5 May 2023 15:20:55 +0200 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 677a200a15b19e293467c73b14b7a9b13b3038a6 Author: sebastianselander Date: Fri May 5 15:12:37 2023 +0200 Removed GC, merge it into main to save correct commit history commit a720b9ffd8c347c7bda56eb752c62b1588e9b614 Author: sebastianselander Date: Fri May 5 15:09:51 2023 +0200 Peano commit 22d9dd8efa1a965294bae210094a87fda2947ab8 Author: sebastianselander Date: Fri May 5 14:28:05 2023 +0200 Fixed incorrect constructor name with Gilliam commit 63fef958a78f5abb21c917358783398e65dbe060 Author: sebastianselander Date: Fri May 5 14:09:54 2023 +0200 Improved prelude commit 7562949909c12b736afe6d88e3d0ceae89a61cad Author: Rakarake Date: Fri May 5 12:24:13 2023 +0200 Finally, bug nr4 fixed commit 513cb34eb51de1e7edc5b99b9dcb3f1c96d140cb Author: sebastianselander Date: Fri May 5 12:22:36 2023 +0200 back to inj commit 47cbf12cd18cf90abdb980baf02f879e5f784b63 Merge: 010ca29 747de6a Author: Rakarake Date: Fri May 5 11:44:17 2023 +0200 Merge branch 'pattern-matching-with-typechecking' of github.com:bachelor-group-66-systemf/churf into pattern-matching-with-typechecking commit 010ca29ced7f58a51cfd396d7036cff5d63886c0 Author: Rakarake Date: Fri May 5 11:44:08 2023 +0200 Fixed wrong name bug -- samuel commit 747de6a34e6d89e9e423563d9950f5707f4dcc64 Author: sebastianselander Date: Fri May 5 11:43:17 2023 +0200 Renaming symbols in desugar, removed incorrect comment in emits commit fe25f18eb7847d3983fe98de7f7a905d800cbea9 Author: Rakarake Date: Fri May 5 11:28:40 2023 +0200 Fixed naming-cons bug in monomorphizer commit 4aa72beccb1953a1ec47a59367a6ec1d7628837f Author: Martin Fredin Date: Fri May 5 09:02:10 2023 +0200 Add missing clauses. Still broken commit 1d551e5874a908b2583fdf0959f5f585f2315e07 Author: sebastian Date: Fri May 5 00:35:48 2023 +0200 added alternative better implemenatation of checkBind commit 0a588c4e14ea89dfdadd1f2750791cf9f29df623 Author: Martin Fredin Date: Thu May 4 23:54:19 2023 +0200 Revert AnnForall change commit 15025a67f996b967093d0f4adac624acca3be60c Author: sebastian Date: Thu May 4 23:15:24 2023 +0200 removed unused imports commit 988d0dbb533d3c33249f3a1a54d60352fd892299 Author: sebastian Date: Thu May 4 23:03:11 2023 +0200 moved stuff commit 4f21a58200b67290ec351ba1530f5a2fb646bb67 Author: sebastian Date: Thu May 4 23:00:51 2023 +0200 more symbols and changed err msg commit 0dc06eaf80989087682211dc44f0485b5386893d Author: sebastian Date: Thu May 4 22:50:15 2023 +0200 Parens removed on types and infix symbols work almost, just need to adapt in LLVM commit c309c439cb5228e65103c17f3077766791ce3b18 Author: sebastianselander Date: Thu May 4 21:30:19 2023 +0200 Fixed bug when freshening types commit 122bff7436674950fb49a0089c38147f7edacfe7 Author: sebastian Date: Thu May 4 21:29:24 2023 +0200 Sugar has arrived commit c7b76cbbb4f9d118ee2cb13c17eb5e2164d5f77e Author: sebastianselander Date: Wed May 3 18:56:16 2023 +0200 Fixed a bug of repeated application of same function to arguments of differing types. More bufs appeared commit 5a28f9d90945197e8e93c37fe61e472260996d6c Author: sebastianselander Date: Wed May 3 17:59:09 2023 +0200 Bind now does correct subtype check. commit f8a70b4cf400f817b51617b68878c71468690582 Author: sebastianselander Date: Wed May 3 17:58:50 2023 +0200 Improved error messages commit 4038f34cc53db2146acd42c2d1cd16580dc50704 Author: Rakarake Date: Wed May 3 15:08:07 2023 +0200 Fixed woring order of monomorphization in ECase commit e70eae776a274dffb4bb2269a682267f13185ae1 Author: Rakarake Date: Tue May 2 17:25:22 2023 +0200 Maybe made lets work in monomorphizer πŸ™ƒ commit eba91ec6462192102c28c0a9f3acb00bef0c879d Author: Samuel Hammersberg Date: Mon May 1 22:50:37 2023 +0200 The log folder is now created as well. commit 22dcbc6a1315c1faa085bf44560e72d30547f2fc Author: Samuel Hammersberg Date: Mon May 1 22:50:22 2023 +0200 Various codegen fixes commit 45578a79b1fdf56e93231eb6ac0a0a60e4aa1b0a Merge: 59da6d8 0452a30 Author: Rakarake Date: Mon May 1 16:14:10 2023 +0200 Merge branch 'pattern-matching-with-typechecking' of github.com:bachelor-group-66-systemf/churf into pattern-matching-with-typechecking commit 59da6d8864f94b43c974472909c5777e0c6419e1 Author: Rakarake Date: Mon May 1 16:14:01 2023 +0200 Fixed printing bug in MorbIr, fixed Monomorphizer forgetting to output constructors on EInj commit 0452a30409e6a598041eb23f3492054d6b6937c9 Author: Samuel Hammersberg Date: Mon May 1 16:01:39 2023 +0200 Yoinked newer GC. commit 3377879dd0380751c4ec14431552afc9e74f2672 Author: Rakarake Date: Mon May 1 11:57:06 2023 +0200 Small fix in morphBind commit 0af2aac61e6dca5d2654d76533e1d1a4bc7e17e5 Author: Rakarake Date: Mon May 1 11:53:18 2023 +0200 Removed some warnings, better internal error commit 6b72d08b9446a901d773ed7c1535a4e254ebdbf8 Author: Samuel Hammersberg Date: Mon May 1 11:09:23 2023 +0200 Commented out `customHelperFunctionCuzPoorImplementation` as it is not needed with type annotations. commit 78af9431b98d40097554113c3cb328c221e19dc1 Author: Martin Fredin Date: Mon May 1 11:10:47 2023 +0200 Remove clang 11 commit 63d805fa13b46821e50e8185bf1f2fdf40d36d29 Author: Martin Fredin Date: Mon May 1 10:55:34 2023 +0200 Uncomment prelude commit 0fb13f59fbe2e781192042f91b7104bfba4f31f1 Author: Martin Fredin Date: Mon May 1 10:47:07 2023 +0200 Remove bad program commit 8463dc28875114971f8608b096c5251d13b5f7a3 Author: Martin Fredin Date: Sat Apr 29 21:58:39 2023 +0200 Small fix to lambda lifter commit d7a09a720be8daa1960bd5b5dd06cd7ffae52ec8 Author: sebastianselander Date: Sat Apr 29 17:55:18 2023 +0200 Fixed more precise type annotation for monomorphizer commit a87862a99f818d3dff0f8f6aaa3ab3e00b29019a Author: Martin Fredin Date: Sat Apr 29 16:02:51 2023 +0200 Fix sample programs commit a2f61ea91042ac0b3835d3efc738ac380a1ee979 Author: Martin Fredin Date: Sat Apr 29 15:56:01 2023 +0200 Fix missing pattern synonym commit 619242ccaf74877141c040dc821e2165f2131a8c Author: Martin Fredin Date: Sat Apr 29 15:52:37 2023 +0200 Fix lambda lifter commit df1a5de04a52e25d609a1855b874ab7cc478a621 Author: Martin Fredin Date: Fri Apr 28 19:45:15 2023 +0200 Add module to sort definitions commit de03a2cc34d04df776823424e71a5b49ca2f3055 Author: Samuel Hammersberg Date: Fri Apr 28 14:52:47 2023 +0200 The code generator can now compile without the GC. commit f9d28028b5d3210637132c93a156275b474ad319 Author: Samuel Hammersberg Date: Fri Apr 28 14:24:44 2023 +0200 The GC argument is now passed to the compiler and codegen. commit ddffe7913c4a4c9fac77e84ee1b448488a23679b Author: Samuel Hammersberg Date: Fri Apr 28 14:22:02 2023 +0200 Added an option to disable the garbage collector (this feature is not implemented fully yet.). commit 38b88d36b596edae1688e9c6b04f00ab4ccc1854 Author: Martin Fredin Date: Fri Apr 28 14:20:24 2023 +0200 Use throwError instead of error commit e8d37c77cb2d700ff5ce497fe1351e553fcc80d8 Author: Samuel Hammersberg Date: Fri Apr 28 14:10:39 2023 +0200 Fixed a typo. commit cb619c96a86e8f182ce5367a7253f1adb8499cda Author: Samuel Hammersberg Date: Fri Apr 28 14:10:22 2023 +0200 Removed a stupid file commit 1723796006522aa5e6f725fb01eab9f909bbf3e8 Author: sebastianselander Date: Fri Apr 28 14:01:05 2023 +0200 renamed and fixed const in prelude commit b27988b4d89cbca0ef0c252274dc0698c8be82af Author: Martin Fredin Date: Fri Apr 28 14:04:47 2023 +0200 Add checking for case commit 22ffdffa5a9d8f3c74e85f82fae8af5b2bbbf617 Author: Martin Fredin Date: Thu Apr 27 18:59:16 2023 +0200 Fix pretty printer commit 072f2206e6889f6fb1b6d795c79134fbe7f1cc18 Author: sebastianselander Date: Fri Apr 28 12:53:29 2023 +0200 added const body again commit e42c77513534771b05b626578de2113a10c76ddc Author: Martin Fredin Date: Thu Apr 27 17:29:13 2023 +0200 Fix prelude commit 37292780418f7bd9d068954a509400b3e0a7528b Author: Rakarake Date: Thu Apr 27 16:44:30 2023 +0200 Unreachable branhces are removed, fixed a nasty bug in monomorphizer 😸 commit 46a4d3d25247f7822d21fe2b222fde659f1904d2 Author: Samuel Hammersberg Date: Thu Apr 27 16:01:22 2023 +0200 Fixed a bug with penums commit e19c809d5ebc71ab4713d45cdbbe7ecef05ad0ca Merge: 509b51d 39d0650 Author: Rakarake Date: Thu Apr 27 15:09:45 2023 +0200 Merge branch 'pattern-matching-with-typechecking' of github.com:bachelor-group-66-systemf/churf into pattern-matching-with-typechecking commit 509b51d2deb867cc2ac8a0741c01c0309a29076a Author: Rakarake Date: Thu Apr 27 15:09:39 2023 +0200 No output of wrongly typed cons commit 39d0650115d61386512ecef4cecf4fe57794fb9a Author: Samuel Hammersberg Date: Thu Apr 27 15:06:42 2023 +0200 Fixed a booleans not being outputted as literals. commit 579153b6794ae61e61076a279f5998355377802e Merge: 60e12b6 d026dca Author: Rakarake Date: Thu Apr 27 14:02:10 2023 +0200 Merged commit 60e12b622e7c0f58d0d22bf95046110e46456a80 Author: Rakarake Date: Thu Apr 27 13:55:54 2023 +0200 Using type annotations in case expressions, monomorphizer now handles case expressions without crashing commit d026dca42f7c07f3644eb0a1b3f546ebb16dff51 Author: Samuel Hammersberg Date: Thu Apr 27 13:49:00 2023 +0200 Attacked the code generator and added bool support. commit 1a21698772af18d01841aa536b3c0a2d003a9da9 Author: sebastianselander Date: Thu Apr 27 12:57:36 2023 +0200 mono fixier commit 55fd35d66183f6371b38d092fb27d6e0a38dedfc Author: sebastianselander Date: Thu Apr 27 12:49:29 2023 +0200 mono fix commit e9852079ab039bb42f4cdcb1609dc77759331590 Author: sebastianselander Date: Thu Apr 27 12:43:02 2023 +0200 bool now lit commit 87825566039b51ef4a202be46115a541ac189402 Author: Martin Fredin Date: Thu Apr 27 12:22:20 2023 +0200 Fix types in pattersgit add .git add . commit fc306d5f25be99c90b001ac2a47beeb5cb62752f Author: Martin Fredin Date: Thu Apr 27 11:43:56 2023 +0200 Fix pattern types commit fd418faa5fe3c65b31a4bdb4ad779bf307765e58 Author: sebastianselander Date: Thu Apr 27 12:18:56 2023 +0200 introduced lt in prelude commit 2cb852784844eb2c8451b25e2f7df5a4d9c11db7 Author: Martin Fredin Date: Tue Apr 25 23:02:56 2023 +0200 Rename variables commit e138cb27ecb0201098f0a98cafb5232f3e6d5397 Author: Martin Fredin Date: Tue Apr 25 22:59:33 2023 +0200 Simplify pattern matching commit 9ffcbf66b99adbfc72639b7ce3d1e13d8f1af302 Author: Samuel Hammersberg Date: Tue Apr 18 15:28:03 2023 +0200 Added support for running GC profiller. commit b5384bf2c356c8ac8339c380e5f3cd331167306d Author: Martin Fredin Date: Tue Apr 25 13:22:33 2023 +0200 Fix typo commit 2d96a50219f883344e00a1f23f275b2a141ffc4e Author: Martin Fredin Date: Mon Apr 24 10:47:33 2023 +0200 Change name commit 804d0da167dedf327fc5ff557c1b17038bd39661 Author: Martin Fredin Date: Mon Apr 24 10:10:15 2023 +0200 Check number of arguments in pattern match commit 25075ccaacb5361d78d5014711aec15e56bb996f Author: sebastianselander Date: Thu Apr 20 15:36:36 2023 +0200 added simple script for running benchmarks commit 4bd5801c97d8c20c6602c6a40529433fe421db8c Author: Rakarake Date: Tue Apr 18 15:52:33 2023 +0200 Removed traces commit 2611ddc2b2e5330b5afd3a45ec30c737cd97e932 Author: Rakarake Date: Tue Apr 18 15:48:25 2023 +0200 Fixed wrong handeling of EAdd in monomorphizer, as well as more documentation and cleanup commit 7ab0e659812e3b116a316db83f7dd8698e666d25 Author: sebastianselander Date: Mon Apr 17 16:05:23 2023 +0200 removed minor thing in EAdd commit a23269f907a49d5fb01af14a3db6c2bd0e089ac4 Author: Rakarake Date: Mon Apr 17 15:53:16 2023 +0200 Fixed small bug in monomorphizer commit c2bf6312f652df2bc6901ac75e804ae8aee39ba3 Author: Rakarake Date: Wed Apr 12 16:36:22 2023 +0200 Monomorphizer now outputs constructors that are matched on but not created commit 0ab13e597950d3ad3d389e83df1c3b48f8e2e808 Author: Samuel Hammersberg Date: Wed Apr 12 15:15:38 2023 +0200 Fixed the ordering of data types. commit 2b7715714e5e14e72b1e9e3b8a18b13674599fbc Author: Martin Fredin Date: Tue Apr 11 18:56:53 2023 +0200 Use better names commit 9730552eab1c559695a00695e4cae1c75afde521 Author: Martin Fredin Date: Tue Apr 11 13:46:54 2023 +0200 Remove parenthesis from EAnn commit a109b3010df5782edd475e5673c2f11c29348127 Author: Martin Fredin Date: Sat Apr 8 21:52:57 2023 +0200 Fix bad inference on case expression, and make pretty for report commit 29de6c49e4914e79119fdf1d418ef3bcb451461a Author: Martin Fredin Date: Sat Apr 8 13:39:00 2023 +0200 Fix naming commit 9cb4a620bbe3a98506ae6cf5856534915b939595 Author: Martin Fredin Date: Sat Apr 8 13:38:30 2023 +0200 Fix redundant print paren commit 21b1ba7b1f9defa2ebcbb3704dec30e701e47d6d Author: Samuel Hammersberg Date: Fri Apr 7 16:01:23 2023 +0200 Replaced # with $ commit 9c699ecb63b66caac296efeb01cbe4b8f5463aec Author: Rakarake Date: Thu Apr 6 14:29:30 2023 +0200 Fixed output of monomorphizer in main commit 0d30cb80e02daae74c62206ace6667deb26d38a8 Author: sebastian Date: Thu Apr 6 14:19:54 2023 +0200 removed pretty printing of tvars commit e7cd3b2c3a913ac6be768f6e6a20ae0fb505ffe3 Author: Rakarake <51128488+Rakarake@users.noreply.github.com> Date: Thu Apr 6 14:12:45 2023 +0200 Added README section about Nix commit 90352449f42c45a7563a8a73a83bde3dc6e05d22 Author: sebastianselander Date: Wed Apr 5 18:25:41 2023 +0200 added todo for semi monomorphization commit 05ea23d22ca3945f5c8aa4f83743e6cbe15ea94e Author: Martin Fredin Date: Wed Apr 5 17:41:17 2023 +0200 Fix test error message commit 9870802371b82668e55718ac3e8be651bbb465f1 Author: Martin Fredin Date: Mon Apr 3 17:34:33 2023 +0200 Add implicit foralls for bidir, update and unify pipeline commit 12bca1c32d6655ed612938bfd4031ea488cef7e3 Author: sebastianselander Date: Wed Apr 5 12:56:57 2023 +0200 Added small comment about incorrect subtyping commit c6e0e40ef16b83b9ff2b98c52779d5297af32706 Author: Rakarake Date: Wed Apr 5 03:03:42 2023 +0200 Monomorphizer now monomorphizes data commit 5e5d258bb16531675b11b1c67bb533317c035f42 Author: Martin Fredin Date: Mon Apr 3 12:31:29 2023 +0200 Update readme with identation syntax commit 077f76eb12d74535c3a0c91af11538d03b303253 Author: Martin Fredin Date: Mon Apr 3 12:24:22 2023 +0200 Separate make file actions commit e5dc28b28226c65ad5cb886883aaf254d1b77288 Author: Martin Fredin Date: Mon Apr 3 12:11:21 2023 +0200 Add pdf of grammar commit a1b1343d6794caaa8c77920592f8ce16161cc5e8 Author: Martin Fredin Date: Mon Apr 3 12:04:52 2023 +0200 Add latex file commit 03bb6a8534324c24154297e6d62b6b437433c4a6 Author: Martin Fredin Date: Mon Apr 3 09:42:14 2023 +0200 Fix sample-program commit c998241c65807d676ceca6b95a3563bb6dfe67f4 Author: Martin Fredin Date: Mon Apr 3 09:39:24 2023 +0200 Fix tests commit 0d6c5920a99bbd865215570d6eeef319a31b1bf0 Author: Martin Fredin Date: Mon Apr 3 09:24:27 2023 +0200 Fix type checker commit cc5755c3a91055b3d9fb01f0281440945cb63e13 Author: Martin Fredin Date: Mon Apr 3 09:24:13 2023 +0200 Add layout grammar commit bd02f527956dafca0c3f1002cb700f38fd310b2c Author: sebastian Date: Sun Apr 2 13:48:11 2023 +0200 Fixed structure a bit morer commit faffb2744ebd6c11f9f40fd9181b0110eb2ee409 Author: sebastian Date: Sun Apr 2 13:47:35 2023 +0200 Fixed structure a bit more commit 6a2ebf4ecd95eadc57067bfa047f001bde70e9a2 Author: sebastian Date: Sun Apr 2 13:46:46 2023 +0200 Fixed structure a bit commit 03a486410f24fb3adb72672529276448119d99a0 Author: sebastian Date: Sun Apr 2 13:42:47 2023 +0200 Added somewhat detailed README commit aaaff776e0f4f07dceb9b5b921f1bd4b8f4c30d8 Author: sebastian Date: Sun Apr 2 00:42:42 2023 +0200 Add some boiler plate for warnings commit 6c180554ecb9950a6c5409b01c6adcb980ab91e5 Author: sebastian Date: Sun Apr 2 00:04:33 2023 +0200 Reworked order of inference, added prettifier for tvars etc etc. commit ec8d554af1e7d8cf5f7527145dba925b6f8db663 Author: sebastian Date: Sat Apr 1 18:45:08 2023 +0200 Disabled shadowing in pattern match with nice error message, added aux functions commit 4b14cbdebf9d94b27296bf531f12303ae885de37 Author: sebastian Date: Sat Apr 1 17:10:26 2023 +0200 reverted Hindley-Milner type checker to before mutual recursion merge commit ec57712eec6d533021440426ff6638cd832b19de Author: Rakarake Date: Fri Mar 31 19:43:05 2023 +0200 Fixed bad names after monomorphizer commit c6173c007756c2705455a77e56fb03aa9c5bedec Author: Rakarake Date: Fri Mar 31 19:25:48 2023 +0200 Plus now working in monomorphizer commit b8f717f39fa246749cd9aa7db041d8d49cf61bd3 Merge: 0749ca0 00e23a1 Author: Rakarake Date: Fri Mar 31 18:59:05 2023 +0200 Merge branch 'monomorphizer-data' into pattern-matching-with-typechecking commit 00e23a16dd1bdef713e53bff6db7f7ba1560c5ae Author: Rakarake Date: Fri Mar 31 18:58:33 2023 +0200 Monomorphization of datatypes done! commit 0749ca062d7a73b2444af8f1b19163945d8135b3 Author: sebastianselander Date: Fri Mar 31 18:28:04 2023 +0200 Merge in mutual recursion handling commit b7420b5adb9534a6012fe3d7f8962ef0a03bcacd Author: sebastianselander Date: Fri Mar 31 18:27:30 2023 +0200 Merge in mutual recursion handling commit c4f78ca37d713975043f43c415052a1990a10333 Author: sebastianselander Date: Fri Mar 31 18:26:58 2023 +0200 Merge in mutual recursion handling commit e2e469d84ea5b434697b2ccca49e5b1c2912ef5a Author: Samuel Hammersberg Date: Fri Mar 31 18:17:28 2023 +0200 Added some examples that were shown to our handledare. commit b0ec5a2333275e50e993cb2efa5902d91f515417 Author: Samuel Hammersberg Date: Fri Mar 31 18:16:26 2023 +0200 Started working on a Case Desugar phase. commit 15c18271bac5ed8571bae76c69bd5dc4c72fbbae Author: Rakarake Date: Fri Mar 31 17:53:56 2023 +0200 Monomorphizer, fixed problem with type of bind commit d097cd28e8d384990d3a172d55de2e2e6b94b85d Author: Rakarake Date: Fri Mar 31 17:02:54 2023 +0200 New morb tree for internal use in monomorphizer, data types implemented commit 7d2a0e60d8b0c4d453ef5ffed0ca4bf886534336 Author: Martin Fredin Date: Thu Mar 30 19:07:12 2023 +0200 Fixes commit 72352d9619e862484f16ee12140e0b3a5d23f32e Author: Martin Fredin Date: Thu Mar 30 18:46:37 2023 +0200 Use use tevars for bind without type signatures, fix recursive functions commit 4831205e6793f62a2f731394a51b63f53eff9754 Author: Martin Fredin Date: Thu Mar 30 12:49:27 2023 +0200 Remove incorrect test commit 5d2c0e787ef2610efce08f5bebf2a0b67864a6c4 Author: Samuel Hammersberg Date: Thu Mar 30 15:08:40 2023 +0200 The compiler is now compiled with O3. commit 9b38c6d8046b044b47cdc232f8bf809318c1366b Author: Samuel Hammersberg Date: Thu Mar 30 12:37:24 2023 +0200 Main now prints the exit code of the program, as Haskell likes to hide segfaults. commit b3525db7fd756b0cb691199ba0a336da10fb45bd Author: Samuel Hammersberg Date: Thu Mar 30 12:31:03 2023 +0200 Integrated the garbage collector. commit bbe0d77a19e88055b597ed597c8da27ca6f490ca Author: Martin Fredin Date: Thu Mar 30 12:35:47 2023 +0200 Add signature of inferred bind to allow some mutually defined definitions commit a37a52d9f8cf9321b2efdadddd0b5cb1e67805b2 Author: Martin Fredin Date: Thu Mar 30 11:49:13 2023 +0200 Apply env to return type. fixes #14 commit 2851c408d1c4ae2bce66ac2d42b93d50772ed501 Author: Samuel Hammersberg Date: Thu Mar 30 11:41:10 2023 +0200 Added the updated GC. commit c4477d3df4bb263e86fce271285949d669e05538 Author: sebastianselander Date: Thu Mar 30 11:38:06 2023 +0200 moved some funcs to aux, added a universal definition of int and char, updated usages in both tcs commit 59676605cdb5b623f0dc8298435525684f48f633 Author: sebastianselander Date: Thu Mar 30 10:55:01 2023 +0200 moved injections back to state commit c34041860dad36c298f6031be4d181c90440af14 Author: sebastianselander Date: Thu Mar 30 10:21:04 2023 +0200 duplicate signatures / declarations correct commit c4931c39968f80e89d16baead217c2d567b6db8c Author: sebastian Date: Wed Mar 29 22:59:21 2023 +0200 Fixed bug in EApp, cleaned a bit, added todo for disallowing mutual recursion commit aa1ff630a5f56d8a2cc357aa0b37511a932e784b Author: Martin Fredin Date: Wed Mar 29 22:48:26 2023 +0200 Fix double vars commit 343be08a4a799f7ee735b3caa11fc115a206c8e9 Author: sebastianselander Date: Wed Mar 29 18:47:14 2023 +0200 Tried solving bug, failed, added todo message, fixed printing commit 61f364cd759d793926c2f7165264170398a6f622 Author: Samuel Hammersberg Date: Wed Mar 29 17:34:47 2023 +0200 Splat up the codegenerator a bit. commit 36b6a8f78171b376a78096f7f673c05905bb5186 Author: sebastianselander Date: Wed Mar 29 17:32:21 2023 +0200 removed trace commit 4efe7cf9a2f47e386d229b4774d813c8f98ac3fa Author: sebastianselander Date: Wed Mar 29 17:30:31 2023 +0200 inference does not depend on order. mutual recursion still not working correctly commit 29fcddf44c1222b07ea0e6e58358d4640ad55d54 Author: Rakarake Date: Wed Mar 29 17:05:56 2023 +0200 Data defs in monomorphizer output environment commit 53589e8d5071e8d067eec8b36b0b40ec8b449cec Author: Samuel Hammersberg Date: Wed Mar 29 16:54:30 2023 +0200 Made the output from running the compiler a bit clearer. commit d26bde6a7fd95fb3c61d488471673a1f336ac7c0 Author: Samuel Hammersberg Date: Wed Mar 29 16:47:52 2023 +0200 Added a fun Maybe example! commit d4115fd2f5ac5392601876365dd3a760ca80e880 Author: Rakarake Date: Wed Mar 29 16:45:30 2023 +0200 Monomoprhizer handles new types commit c59cd02361f7371d1583b324e001fcf7849c059e Author: Martin Fredin Date: Wed Mar 29 16:37:52 2023 +0200 Lift lambdas in the scrutinized expression commit 2f12fdd7e224f94b5404ffc293b82c1e97c23ce7 Author: Samuel Hammersberg Date: Wed Mar 29 15:29:53 2023 +0200 Removed a trace. commit f69151a7ce6f1c435053557ba16f7fbba9aa80ef Author: Samuel Hammersberg Date: Wed Mar 29 15:12:33 2023 +0200 Fixed a bug with pattern matching on literals. commit 82f1b38f1b51a78b2b085117576c99ffcf303cbb Author: Samuel Hammersberg Date: Wed Mar 29 14:41:52 2023 +0200 Removed the Tjabatjena comment that the compiler generated. commit 100b7b113a271192e14054da9dc558dd49531331 Author: Samuel Hammersberg Date: Wed Mar 29 14:31:24 2023 +0200 We got pattern matching on data types! commit 2860d47f11cfcadca8a47c611a09a2d671f49e3b Author: Rakarake Date: Wed Mar 29 13:48:00 2023 +0200 Case expressions implemented in monomorphizer commit 4755f434fd5290f562d9c303b6e08da21ded13b4 Author: Martin Fredin Date: Wed Mar 29 11:25:45 2023 +0200 Add test for pattern matching on recursive data types, and remove traces commit 52db1943bb6d6a422df9ecfeb35648acff790ded Author: Martin Fredin Date: Wed Mar 29 11:12:33 2023 +0200 Finished new check pattern commit 76b1c55065cd9f62c782595edf1792af6c5384ec Author: Martin Fredin Date: Tue Mar 28 15:33:03 2023 +0200 Progress commit 133cc31e77d67677ae0454e6dff528f2da9eb1d7 Author: Martin Fredin Date: Tue Mar 28 14:36:43 2023 +0200 Fix lambda lifter commit 528369c95ca0484f4adfcfd4650c57ba0820c7c1 Author: Martin Fredin Date: Mon Mar 27 23:55:04 2023 +0200 Progress on new checkPattern commit f20b80cab328fed5c1a35040f46493f0166a22a6 Author: sebastian Date: Tue Mar 28 23:19:04 2023 +0200 added skomeliation on given type signatures commit 7c5041d2703df2d9fd729d8f0ab8aa500cf82e08 Author: sebastian Date: Tue Mar 28 21:52:09 2023 +0200 added this stupid complex bug to Bugs.md commit 9e6fe454ce8fde57a6b123a1d951f4eb690db738 Author: sebastianselander Date: Tue Mar 28 17:57:44 2023 +0200 reverted back to most close to correct version commit d8a75d66437510c110c502428d7fdfbfeb929eb9 Author: Samuel Hammersberg Date: Tue Mar 28 17:49:47 2023 +0200 Solved 30+ WARNINGS!! 😎 commit c77139dfa8eb7921a8bc60639cc65bb8e2145a7e Author: Samuel Hammersberg Date: Tue Mar 28 17:47:43 2023 +0200 Added a Malloc instruction. commit 230a205965854266c2c38d5421866d2d6934846d Author: Samuel Hammersberg Date: Tue Mar 28 17:37:29 2023 +0200 Fixed wrongly typed functions in the code generator. commit e87e2d3870fd5edfc54dd1cfc23ae2b2252d9d2a Author: sebastianselander Date: Tue Mar 28 17:33:14 2023 +0200 sneaky buggy fixy commit 8910d8adc01eff7051fb89aa9c910d8de3ef1797 Author: sebastianselander Date: Tue Mar 28 17:13:51 2023 +0200 temporary commit incase of breakage commit 91d6332dc5096ad29d68cf51434380f12b59eb29 Author: Rakarake Date: Tue Mar 28 17:14:55 2023 +0200 Fixed removed args in tree after monomorphizer commit 92a2ff323565385a06652af12e4edfa81bbdc0bf Author: Samuel Hammersberg Date: Tue Mar 28 17:13:38 2023 +0200 Fixed a broken path. commit 4809cad1cbf97e9afce615b7b38033f731eeb717 Author: Samuel Hammersberg Date: Tue Mar 28 16:54:11 2023 +0200 Fixed chars. commit ba832ba288780c893f068bdb53ab9b0d19fc2b5e Author: sebastianselander Date: Tue Mar 28 16:07:39 2023 +0200 added printTree for monomorphizer commit cf12c3443d7aeab9785bf884d817f09dcb9d872a Author: Rakarake Date: Tue Mar 28 15:57:35 2023 +0200 Main had a weird look commit a7401f0ee3e9b465cf985fc0ad8f0fb1f87451b5 Author: Rakarake Date: Tue Mar 28 15:55:06 2023 +0200 Monomorphizer main fix commit 43a863c153fd11923862e28dbe8c4ab3e1b3320a Author: sebastianselander Date: Tue Mar 28 15:44:03 2023 +0200 fixed coerce type error commit cca2f853ea8ef128110eec307c09fe48812d68b8 Author: Samuel Hammersberg Date: Tue Mar 28 15:36:08 2023 +0200 Added a variable lookup. commit 5a70286802e5afc441d030c691e9bfdc17456e0a Author: Samuel Hammersberg Date: Tue Mar 28 15:35:34 2023 +0200 Added a files back. commit 7f0dab6dcbd096518ccef04347625701f6092f7a Author: sebastianselander Date: Tue Mar 28 15:35:48 2023 +0200 adapted changes to work commit 59d9be87cb51ef025288bfd10aa82d628086d9d2 Author: Martin Fredin Date: Tue Mar 28 15:35:01 2023 +0200 Add cases for lambda lifter commit 5986e2108e2f5874718f898d4969f3e4204e615b Author: Samuel Hammersberg Date: Tue Mar 28 15:32:54 2023 +0200 Added c output files to the gitignore commit b35c19572fc90e8a952e4741f980227419aa22cb Merge: b1d3e31 4a6c72f Author: Rakarake Date: Tue Mar 28 15:26:35 2023 +0200 Newer changes commit b1d3e31efd3f8d3e82e6d094fce529654c790005 Author: sebastianselander Date: Tue Mar 28 14:31:20 2023 +0200 Fixed previously incorrect type equality check, commented code, add test commit 85f31b129baf1d18d1c140d677af63498bd50314 Author: Samuel Hammersberg Date: Tue Mar 28 14:15:22 2023 +0200 Yoinked over the garbage collector. commit 2aff7a77438b0d219495b494951836bb46f033ec Author: Samuel Hammersberg Date: Tue Mar 28 13:50:19 2023 +0200 Fixed argumentless constructors being treated as variables. commit d7549d421c02292ff3b81e0573150c99c9c49afb Author: Samuel Hammersberg Date: Tue Mar 28 13:49:34 2023 +0200 Fixed a missing dependency. commit 66e419efa6837b1689d7f3ace246638e3955323e Author: Samuel Hammersberg Date: Tue Mar 28 11:53:25 2023 +0200 Fixed the unnamed temporary bugs. commit 58fe92affe75a25b8a19b5f29ad94fcf39ea7d14 Author: sebastianselander Date: Tue Mar 28 10:50:45 2023 +0200 Revert "restructured layout of code a bit" This reverts commit 0639489d280ffbbdb644e683de24719d9e76e470. commit 0639489d280ffbbdb644e683de24719d9e76e470 Author: sebastianselander Date: Tue Mar 28 10:50:05 2023 +0200 restructured layout of code a bit commit 1558c98d10854b537244ee6e1bdd3b2dc2bb9ff7 Author: sebastianselander Date: Tue Mar 28 10:46:04 2023 +0200 improved the idea of error messages, still not very clean commit 54f7d54bf91125fa52dabed56a9d38b53bc501d6 Author: sebastianselander Date: Tue Mar 28 10:10:26 2023 +0200 fixed EAdd conversion bug in RemoveTEVars commit 437c193ea8070139e9e23cb869f27cc7d4c8a124 Author: sebastianselander Date: Tue Mar 28 10:07:30 2023 +0200 fixed EAnn commit 4d3d90c6a382c4d5ce6794adcfea40f4f024fee6 Author: Samuel Hammersberg Date: Tue Mar 28 09:48:27 2023 +0200 Added some debug options to the just file. commit 0d2fe862e064e2cf428089aadab7ad0f2fd4995a Author: sebastian Date: Mon Mar 27 23:05:40 2023 +0200 fixed bug and additional test commit 4b24755b9324fd6bed5b22ce300c66bc72ab15e1 Author: sebastian Date: Mon Mar 27 22:38:39 2023 +0200 cleaned up implementations and added check for duplicate constructors commit e1633ea147d5d03945714f9a4d7cec9b0f2413db Author: sebastian Date: Mon Mar 27 21:16:48 2023 +0200 small fixed and added qualifiedDo commit a38e96a83bd7acd18706090bc71a4040ff3a5758 Author: Martin Fredin Date: Mon Mar 27 20:51:00 2023 +0200 Fix Ident print instance commit ad2bd645d9b2b699cf5c1e07b88f1654c771f589 Author: sebastian Date: Mon Mar 27 20:33:11 2023 +0200 tests are running now commit 4a6c72fce01ee88b1c18dd8d866e2fc7a31df205 Author: Rakarake Date: Mon Mar 27 20:11:49 2023 +0200 Removed codegen to compile, type seem to work for newly added example commit 0d23a59f0cf702b639597f4a226601464959766b Merge: 2137414 bef7821 Author: Rakarake Date: Mon Mar 27 19:14:35 2023 +0200 Merged into commit not compiling on codegen 😀 commit 506d8733d98a4f8078274298028013b7b000a8aa Author: sebastianselander Date: Mon Mar 27 16:54:10 2023 +0200 added old tests, still broken commit 2adc3dceeea5421b7590e29108ebc84481229df8 Author: sebastianselander Date: Mon Mar 27 16:53:29 2023 +0200 added old tests commit d5ce73beaeb53bf04cfe1ff78a3ba4c8f338e871 Author: sebastianselander Date: Mon Mar 27 16:52:22 2023 +0200 hm is compatible commit 6e54378327cbf6aa8c5b3d6cd53d1ba0c8b555a1 Author: sebastianselander Date: Mon Mar 27 16:48:23 2023 +0200 Fixed errors in tc hm commit 847ec37117147154c0bad98f0710a0ad8c7a08a3 Author: Samuel Hammersberg Date: Mon Mar 27 16:32:48 2023 +0200 Fixed the dependency on the Grammar Ident. commit 750503063a8800ab0714e30a73df2db4599e80cb Author: Samuel Hammersberg Date: Mon Mar 27 16:31:47 2023 +0200 Fixed the dependency on the Grammar Ident. commit 72f4f260783d8bc802646ece547676d701a6e3e3 Author: Samuel Hammersberg Date: Mon Mar 27 16:31:30 2023 +0200 Fixed the dependency on the Grammar Ident. commit db2f8cd197bbb860f2f0c1604e904ad611ac9218 Author: Martin Fredin Date: Mon Mar 27 16:21:01 2023 +0200 Fix Codegen commit 22783cf817d6dbb77648388fca5a274a1f216ea2 Author: sebastianselander Date: Mon Mar 27 16:14:40 2023 +0200 Removed custom Character in favor of BNFC Char commit b7be75aa1e135c9c7537cdb910a550ec29c31417 Author: Martin Fredin Date: Mon Mar 27 16:14:14 2023 +0200 Fix TypeCheckerIr commit 623c6d1e589799070e9966c36cf4356a1f53d201 Author: Samuel Hammersberg Date: Mon Mar 27 16:11:33 2023 +0200 Fixed language.cabal. commit aab75a10f255b189072ad38618af5b1afaae3e28 Author: sebastianselander Date: Mon Mar 27 16:10:13 2023 +0200 fixed justfile commit 45527abd50e67daaee560e0de725b54917f46e85 Author: Martin Fredin Date: Mon Mar 27 16:10:02 2023 +0200 Fix module name commit ac3f222753f642ee699b0e73228f9d1e89e974d7 Author: Martin Fredin Date: Sat Feb 18 14:49:33 2023 +0100 Add bidirectional type checker, lambda lifter. commit 2fa30faa8784c2c276f5bc1c4620bf472410c397 Author: sebastianselander Date: Mon Mar 27 15:37:58 2023 +0200 renamed stuff commit aa4a615c2859e9ef9a453fe173b01f8072a2dc5c Author: sebastianselander Date: Mon Mar 27 14:44:21 2023 +0200 fixed one bug commit bd3cf3c3f12cd74aa0e02e3cad717aaf1473290e Author: Samuel Hammersberg Date: Mon Mar 27 13:40:18 2023 +0200 Fixed simple pattern matching. commit 582747a997d2c069f0fa9acdd5f0d030276cd042 Author: Samuel Hammersberg Date: Mon Mar 27 10:07:04 2023 +0200 The created binary is now saved in the output folder. commit 5062356cefe508bf395a15c19feab024e008d445 Author: Samuel Hammersberg Date: Mon Mar 27 10:05:39 2023 +0200 Fixed broken padding on datatypes. commit 91cfb21a356b1e2f5f3c1223e5df2496ca18d299 Author: Samuel Hammersberg Date: Sun Mar 26 22:21:44 2023 +0200 Almost got a lot of bugs fixed. commit 9952eb02796f36fda2e866761999f803721546bc Author: Samuel Hammersberg Date: Sun Mar 26 21:10:20 2023 +0200 Fixed the printing of TypeCheckerIr commit c37db414312d71123381e345d4bb9520012c335d Author: sebastian Date: Sun Mar 26 18:52:25 2023 +0200 fixed bug commit ccfae195416fa7e750a72a657f332f81266e37b2 Author: Samuel Hammersberg Date: Sun Mar 26 18:38:07 2023 +0200 Added .crf to every sample-program commit 9ea3a3dc56f1d12ac768bf1ffcd2dbf362f03d5e Author: Samuel Hammersberg Date: Sun Mar 26 18:37:55 2023 +0200 Added another bug. commit ebac8697618350345d002d7b1fc058b45c0555a2 Author: Samuel Hammersberg Date: Sun Mar 26 18:24:12 2023 +0200 Fixed a type error in teh codegen. commit 4e92f86d60fc25ac4968f61c8dd6eb5cae6748b9 Author: sebastian Date: Sun Mar 26 16:57:34 2023 +0200 added test for bug. experimented with solutions, none found commit 2af7855a77aebfb868246236831ee4f4eaa2de96 Author: sebastian Date: Sun Mar 26 14:12:09 2023 +0200 documented 3 bugs commit 213741407bb65499a673845247096d674f1eb346 Author: sebastian Date: Sun Mar 26 00:41:26 2023 +0100 small add to Justfile commit 2974c10c0c62cc8dbe03840b9ed9ff17278f47f0 Author: sebastian Date: Sun Mar 26 00:13:10 2023 +0100 moved tests commit d49e2401bfff517e65d6ee5ba3536e71b3620bba Author: sebastian Date: Sun Mar 26 00:09:47 2023 +0100 added file suffix and check commit ac43af8110a9563d074fd11209848acbb67bf5d7 Author: sebastian Date: Sat Mar 25 22:40:15 2023 +0100 fixed a substitution bug where `ap` was incorrectly inferred. also added cleaner fresh variables commit 975dd340630eaa2223144f1ecc276ee6bd17615c Author: sebastian Date: Sat Mar 25 20:43:19 2023 +0100 Better inference & stuff on pattern matches, added more tests for regression commit 88eaa466e49deef1626af522e115c3f07c826568 Author: sebastian Date: Sat Mar 25 19:17:46 2023 +0100 Nested pattern matching should work correctly, added more tests commit 30824443474e0124df2c86415ee523b225fc9d2d Author: sebastian Date: Sat Mar 25 18:42:11 2023 +0100 fixed bugs potentially. tests are working atleast commit 368413515bcfa125729e41c6f05ef93ea42e20e2 Author: sebastian Date: Sat Mar 25 12:04:00 2023 +0100 found incorrectly accepted program. added test commit 05333c568909ca694cf155ecba9f1740ff976f55 Author: sebastian Date: Sat Mar 25 00:02:38 2023 +0100 started on cleaner unit tests commit accbd4eea6d5d764b27b5233e111a58316783284 Author: sebastian Date: Fri Mar 24 22:03:43 2023 +0100 dummy monomorphizer complete commit 7e246a94e51d8e67f6e6445b59dc616ee85913df Author: Samuel Hammersberg Date: Fri Mar 24 19:57:49 2023 +0100 Fixed a segfault. commit f531afb3ab18a5236a5545a07e0c02b6c4a8f05f Author: sebastianselander Date: Fri Mar 24 19:04:29 2023 +0100 added comment when codegen ok commit 2566c53f58905b3a7accee35642e6b52f97e3e23 Author: sebastianselander Date: Fri Mar 24 19:01:33 2023 +0100 mono adapt commit 3e31fe0ea520fd28aa8678f095345b757a80045e Author: Samuel Hammersberg Date: Fri Mar 24 18:52:12 2023 +0100 The compiler now also runs the outputed program. commit b08ae7aef11967c2360ad3366874b4bb215c7d70 Author: sebastianselander Date: Fri Mar 24 18:48:40 2023 +0100 rewrote unification for data type and variable. could definitely be wrong. have to double check commit e500c7052973a3608ab4afd85b9e117cf9864592 Author: Samuel Hammersberg Date: Fri Mar 24 18:46:12 2023 +0100 Programs are now actually compiled all the way through. commit e0c78f5783f3f2b6b4be4a77784cd387fb1b5336 Author: sebastianselander Date: Fri Mar 24 18:32:33 2023 +0100 debug for parse tree commit b4cae11c0d9d02c963f3d0dfde5701b99d705ac7 Author: sebastianselander Date: Fri Mar 24 18:26:59 2023 +0100 added debug info commit 23c174607b9ddf62891427c1b7808d06692ad446 Author: Samuel Hammersberg Date: Fri Mar 24 18:22:37 2023 +0100 temp merge commit 56ccd793acb1dda0607cbc9cd289579a21b9edae Author: sebastianselander Date: Fri Mar 24 18:21:07 2023 +0100 more error messages and better unification commit 867485be125c4f367d87baf8a73873ae96e0f64d Author: sebastianselander Date: Fri Mar 24 17:40:57 2023 +0100 removed trace commit 41fc8636586b46d0d8563afc95e386104ed49236 Author: sebastianselander Date: Fri Mar 24 17:39:10 2023 +0100 added PEnum commit d6d0fb714657efaa693cfe02fd7c4bb3eef746dd Author: Samuel Hammersberg Date: Fri Mar 24 17:29:00 2023 +0100 Enabled compiling to llvm again. commit b1209b335370f9476758f3434a90b54442bdead0 Author: Samuel Hammersberg Date: Fri Mar 24 17:13:56 2023 +0100 Updated the monomorphizer to the new tree. commit 3c2cb1a713a023d90a15161b63392ac73f775357 Author: sebastianselander Date: Fri Mar 24 17:06:32 2023 +0100 new good version works commit f404acdbad76762ee101f5dfd0ef33e7ecf1556f Author: Samuel Hammersberg Date: Fri Mar 24 17:00:31 2023 +0100 Updated some more changes. commit 481667f2d8a04d72e1cb955da358972d5d60e9a6 Author: sebastianselander Date: Fri Mar 24 16:10:46 2023 +0100 added tc as well commit 38680a4dcbd6e183e8357193c6b83fec0bfadf6d Author: sebastianselander Date: Fri Mar 24 16:10:25 2023 +0100 adapted new tree to fuck with samuel commit 50bea83a186548adf7df9989dc7e1f2767045c5c Author: Samuel Hammersberg Date: Fri Mar 24 13:55:06 2023 +0100 Got some more stuff working. commit f4163bbb7d3d40b410349cb5b3802575a20f8995 Author: sebastianselander Date: Fri Mar 24 14:56:33 2023 +0100 formatting commit ce3971cf755212cb0a860644c3255678c95b8a39 Author: sebastianselander Date: Fri Mar 24 12:21:54 2023 +0100 renamed stuff commit 3f618e77f91a132f4677672d107c5bc645a52dfb Author: Samuel Hammersberg Date: Fri Mar 24 11:55:05 2023 +0100 Got most of the codegenerator working. commit 32f8a3e8a98bf898810ad4bad6e753d7ceaa99d8 Author: sebastianselander Date: Fri Mar 24 11:27:19 2023 +0100 duplicate signatures disallowed commit aa73f147f02449131da73fa8d93cfd489de00fc9 Author: sebastianselander Date: Fri Mar 24 11:21:46 2023 +0100 Remade lets with bind & improvements commit 3371c3a146b2626ffd803d757f9a39ba2af5a018 Author: sebastianselander Date: Fri Mar 24 11:21:25 2023 +0100 Remade lets with bind & improvements commit 30a79f34afc46fb31927354059496e8d0ca2c52d Author: Samuel Hammersberg Date: Fri Mar 24 10:57:21 2023 +0100 Added some missing functionality to the dummy monomorphizer. commit bef78217565ccc6583b63ee5e16dafd88c6421cc Author: Rakarake Date: Fri Mar 24 00:55:05 2023 +0100 ReaderT rewrite, recursive and cyclic calls should work commit fc60112877f344cb2ab14ab82c8aad23b2367b05 Author: sebastian Date: Thu Mar 23 22:07:55 2023 +0100 Made binds keep args instead of lambda converting commit 0012efabb7dbe93a875595f1fd3f86d43f758af8 Author: Samuel Hammersberg Date: Thu Mar 23 22:01:40 2023 +0100 Fixed some more stuff. commit 75fa232e214af552146968182533a14d6cf269c0 Author: Samuel Hammersberg Date: Thu Mar 23 21:35:52 2023 +0100 No more warnings, but everything to do with datatypes is outcommented. commit 6cbc83c5d9099ded84ffc2bacb5aa1fbe0cedd07 Author: Samuel Hammersberg Date: Thu Mar 23 20:22:36 2023 +0100 Fixed a miss. commit c85010a8a1cba12e59aa8dfe29c92d9f689fce2f Author: Samuel Hammersberg Date: Thu Mar 23 20:20:17 2023 +0100 Fixed ExpT commit c6e8305215c6657aeb9ed0ad2c5a1195f12e7b3b Author: sebastianselander Date: Thu Mar 23 18:15:25 2023 +0100 created dummy monomorphizer commit c19f82189228016eac76e6daaf59fb52cd225b16 Author: Samuel Hammersberg Date: Thu Mar 23 17:54:41 2023 +0100 Switched around EId. commit e283e83486d264031ec6e365d0fa2b6e30250161 Author: Samuel Hammersberg Date: Thu Mar 23 17:49:37 2023 +0100 Fixed some reexports. commit e3df4192bbfa19caac41765d9e971eb13aab6d09 Author: sebastianselander Date: Thu Mar 23 17:20:19 2023 +0100 created dummy monomorphizer commit 42c8ebc7b6f2ce4351285d182a9bde22d16ea384 Author: sebastianselander Date: Thu Mar 23 16:49:49 2023 +0100 Making progress towards finished product commit d3d173eb59ea47657adfd65e52dca90e981f15db Merge: bf0064d 519ed8a Author: Samuel Hammersberg Date: Thu Mar 23 16:33:05 2023 +0100 Merge remote-tracking branch 'origin/typechecking-merge' into pattern-matching-with-typechecking commit bf0064db865cf1bf66075b69d09671d6b26999d1 Author: Samuel Hammersberg Date: Thu Mar 23 16:13:59 2023 +0100 Added the trait ToIr. commit 519ed8af6c9d0a32536469100c49d9b9450b2f91 Author: sebastianselander Date: Thu Mar 23 16:06:09 2023 +0100 Added monadic fail to renamer commit 129a70e051c4a0ef6a810dd26464fcf805fa434d Author: Samuel Hammersberg Date: Thu Mar 23 15:29:25 2023 +0100 WIP Added support for more types of cases. commit 7fa677e3d3729b2755d35ba380905d6ea1deb43c Author: sebastianselander Date: Thu Mar 23 14:18:23 2023 +0100 typechecker working, still unsure of quality commit 8d1330ad4260b9ca046ea35076be95b8f411f500 Author: sebastianselander Date: Thu Mar 23 11:13:48 2023 +0100 typechecker is compatible with one extra addition to the spec commit 3335ab7a57c4420a65bce8f8de1f3692b86f417c Author: sebastian Date: Wed Mar 22 21:26:14 2023 +0100 compatible, EId rule for parsing is not working, testing not done yet commit 914855e20f6389ca52d563f90689963582c73f72 Author: sebastianselander Date: Wed Mar 22 17:52:39 2023 +0100 working on adapting the typechecker commit 936cb1301fd5d73e92726ec5bf86d465c0f6a125 Author: sebastianselander Date: Wed Mar 22 12:45:51 2023 +0100 new grammar and adapted renamer commit cd85297b859a8600f1f91175811d19d7fd590268 Author: Samuel Hammersberg Date: Wed Mar 22 11:48:40 2023 +0100 Removed the ear operator. commit 61c844a255a0615a52fc6beb0449de877fc9a844 Author: Samuel Hammersberg Date: Wed Mar 22 11:46:07 2023 +0100 Revamped getNewVar commit feeef18cfded47c0f776881799cdb1e664fddd7b Author: Samuel Hammersberg Date: Wed Mar 22 11:41:02 2023 +0100 Started implementing pattern matching on data types. commit 88a4a934b8f448d98947543c6e1fd00b822826d9 Author: sebastianselander Date: Wed Mar 22 10:32:22 2023 +0100 added more manual tests commit d36370329e64df702f5a26c143b7f6dd83ac8f1f Author: Samuel Hammersberg Date: Wed Mar 22 10:24:00 2023 +0100 Realized that getelementptr might be doing to right thing, and that the uninitialized data comes from padding. commit 24007313cb444f4ac5bc15c5e4979c4e4c1d6f81 Author: sebastianselander Date: Wed Mar 22 10:10:11 2023 +0100 added shadowing for ECase in Renamer commit 33b69a1895715e5d0d949c53df487ff65c6cf0de Author: sebastian Date: Tue Mar 21 22:07:21 2023 +0100 Improved formatting commit 57fe8cd0a69cd7594506029bc859152d7011f455 Author: sebastian Date: Tue Mar 21 22:02:28 2023 +0100 Fixed larger bug where pattern matching on `Just a` with type `Maybe b` could be used for any type. commit 8f151b7531eafdf69f25aa6a8abb110068672054 Author: Rakarake Date: Tue Mar 21 17:15:15 2023 +0100 Monomorphization of function applications should work commit 509de4415e967af55f3bbc349080cfe34d45016e Author: sebastianselander Date: Tue Mar 21 17:09:03 2023 +0100 progress on fixing bugs commit 71d07ebf0fbcb97377882eff6f1bdc0ac00a41ad Author: Rakarake Date: Tue Mar 21 15:59:47 2023 +0100 Fixed some internal errors commit 3026a96eb7e215ccdda1dd1fbc6d0ecf13d583d7 Author: sebastian Date: Tue Mar 21 14:51:06 2023 +0100 added todo for class commit 4c015a4aac7e184c0d3342ed9fddf4d2ac32f558 Author: sebastian Date: Tue Mar 21 14:33:18 2023 +0100 initial pattern matching implementation. should be somewhat correct commit ae34c494f5c333fc4c5f76a09956863122bbcb04 Author: Samuel Hammersberg Date: Tue Mar 21 10:14:00 2023 +0100 Improved the visibility checkup a little bit. commit 91816abfe6f1103347329ae454d82f1df5577725 Author: Samuel Hammersberg Date: Tue Mar 21 10:11:02 2023 +0100 Constructors are now seen as global functions. commit bbf7a47e74310bfa0344768fc0d2ad447f396b1c Author: Samuel Hammersberg Date: Tue Mar 21 09:39:05 2023 +0100 Started updating the Code Generator to the new monomorphizer tree. commit 9cd2cdb511fa0456a0f55cca08f6739617bb05b1 Author: sebastianselander Date: Mon Mar 20 17:40:09 2023 +0100 continued work on pattern matching v2 commit ec95e0d9ef78ea8461e7ba7bc621580d048d44c1 Author: Rakarake Date: Sun Mar 12 17:53:46 2023 +0100 Monomorphizer cleanup commit e2db863c3e016689f478fabf7d4568790d66cb7b Author: Rakarake Date: Fri Mar 10 17:24:03 2023 +0100 Fixed name clashes commit 96c4a2bddf183b4e45bdef4e20e081d4c877c1d0 Author: Rakarake Date: Fri Mar 10 17:20:23 2023 +0100 Added test of multiple instanciations of same polymorphic function commit c3ea343d0012e05b6aa9e4f495e1a6c82a6db396 Author: sebastianselander Date: Fri Mar 10 16:54:29 2023 +0100 unified top level type with expression type commit 224a165715ed8bed548ad7f178af13f17beb42fa Author: Rakarake Date: Thu Mar 9 18:52:35 2023 +0100 Unique names of new binds with different types commit f10919ac206e9add415cca6d6b11fbf42d4cc2af Author: Rakarake Date: Thu Mar 9 18:32:00 2023 +0100 Better tests commit 0e20670343d8c2a72f07be30c885624c2706f0fa Author: Rakarake Date: Wed Mar 8 17:52:41 2023 +0100 Added check for recursive calls commit d377ded7e10987e89422c70a85b0a20d2e72a712 Author: Rakarake Date: Wed Mar 8 17:38:50 2023 +0100 Deleted bad sample programs, added polymorphic call in polymorphic function test commit 62724964d7144256c1c456a71f50a7af7539b3bf Author: sebastian Date: Wed Mar 8 15:22:42 2023 +0100 fixed Maybe ('a -> 'a) bug. Pattern matching still wonky, will have to redo commit 350cd3b0e911888ee3497ab18e3a9479a2c8c87b Author: Samuel Hammersberg Date: Wed Mar 8 11:01:07 2023 +0100 Started importing Sebastian's new typechecker. commit d5dd7896d8ea1f948a54f2add15d438824508fbd Author: Samuel Hammersberg Date: Wed Mar 8 10:35:07 2023 +0100 Moved modules into a proper folder structure. commit ac0ac2dac7fcd763fc908b9947a4cd8c8062baee Author: Samuel Hammersberg Date: Wed Mar 8 10:27:39 2023 +0100 Removed a few imports. commit 2af00da48266b4bfc2cc560c4103bd4ea93b58a3 Author: Samuel Hammersberg Date: Wed Mar 8 10:25:53 2023 +0100 Renamed the `compile` function to generate `code` commit 832efbcdd8ea5164c7fa90008a60156d37d8e090 Author: Samuel Hammersberg Date: Wed Mar 8 10:24:52 2023 +0100 Gave the code generator a proper module name. commit bff75bb00bf44cd0d8bfa6d1cdb8b018d318495f Author: Samuel Hammersberg Date: Wed Mar 8 10:22:21 2023 +0100 Switched an Int to Integer. commit 63f9689f38cb17f88c1c0a775d851a15d48ec8ad Author: Rakarake Date: Tue Mar 7 18:49:21 2023 +0100 Simple polymorphic and monomorphic functions properly morphed in test demo. commit 887c3b83913bf5cf69d5c91f42d56bda239d512c Author: Rakarake Date: Tue Mar 7 16:42:56 2023 +0100 Working on bugs commit fce54e789996970dfe1bd71914f0c6f6669415a0 Author: sebastianselander Date: Mon Mar 6 16:41:59 2023 +0100 documented possible bad functions commit eef6fa76683fc3aab2aedcd6ad1b6dc6afef3a92 Author: sebastianselander Date: Mon Mar 6 16:25:03 2023 +0100 added new test and found another bug commit 6947614fba8aec3c85b7a367f06426ab0827703f Author: sebastianselander Date: Mon Mar 6 13:04:07 2023 +0100 Updated bug list & started working on more tests commit f5b5f11903bddff75e0b6236433db2027388d886 Author: sebastianselander Date: Mon Mar 6 11:38:25 2023 +0100 fixed formatting commit 9c2f52f8bb2b07dcf9750b813cb215023da8c6f3 Author: sebastianselander Date: Mon Mar 6 11:27:17 2023 +0100 fixed bug where bound variable didn't exist in case commit 8ca876a1014955a7ef6842537a722cc2ffe57a28 Author: Rakarake Date: Mon Mar 6 10:47:52 2023 +0100 Most code written, no tests yet commit 778fec3dc4b01d2011e21f0622a36009583e3786 Author: sebastianselander Date: Sun Mar 5 14:34:39 2023 +0100 Implemented potential fix for one of the bugs commit fe63fa62157048026a8c3778d39607b8a58c36a7 Author: sebastianselander Date: Sun Mar 5 13:24:56 2023 +0100 Improved error message and created document for known bugs. commit fecb71bc0799f0a6eb181d83cca53de5197ab3f7 Author: sebastianselander Date: Fri Mar 3 18:17:51 2023 +0100 Found a bug. commit 03d7080396bcd24b91506c5fb808e3759ef564e8 Author: sebastianselander Date: Fri Mar 3 11:46:54 2023 +0100 pattern matching works? have to test more commit 7656b46e3f052a7360b339b196e1c74b840bfc08 Author: sebastian Date: Thu Mar 2 22:07:38 2023 +0100 a bit more work on pattern match + case expr commit dbc77ec5f3153fc190f9f63a81d6095f0a9aa619 Author: Rakarake Date: Thu Mar 2 18:36:50 2023 +0100 Progress commit 2401b6437bc3f49f078b9cf19ec20ad0f9514c11 Author: sebastianselander Date: Thu Mar 2 16:05:43 2023 +0100 continued work pattern matching commit 514d79bd6ce0759450ac8481f817d66390c1f86e Author: Rakarake Date: Wed Mar 1 13:50:01 2023 +0100 Strucute in place, MonomorpherIr module created commit 05313652f9951a157bd9599118502a5f1793e620 Author: sebastianselander Date: Tue Feb 28 17:15:48 2023 +0100 unit tests, started on pattern matching commit d23d417ff36040a712f9b015741e46be86cba9b9 Author: Sebastian Selander <70573736+sebastianselander@users.noreply.github.com> Date: Mon Feb 27 19:38:45 2023 +0100 Update TypeChecker.hs commit bbf6e159c7790056bb816cf94e428e7542978cbc Author: sebastianselander Date: Mon Feb 27 17:22:42 2023 +0100 Type inference/checking on ADTs mostly complete(?). Still have to test commit 2f45f39435f207bfb5eb3a922ac33e86792a548e Author: sebastianselander Date: Mon Feb 27 11:12:05 2023 +0100 Incorporated most of main, as well as started on quickcheck commit 7cf6f308356d45fe1bdde18d42f113f6238849b1 Author: Samuel Hammersberg Date: Fri Feb 24 18:37:31 2023 +0100 Data type constructors now properly tag the data. commit 262543931c0704c8866d9f089668749d93784de5 Author: Samuel Hammersberg Date: Fri Feb 24 16:05:49 2023 +0100 Types for data types are now created. commit 272fbe350487beb6c700bede0312b2c52037b247 Author: Samuel Hammersberg Date: Fri Feb 24 09:29:55 2023 +0100 Removed some unused code. commit 5d004f4286a5101a1df1b996a3c1793fef031cd7 Author: Samuel Hammersberg Date: Fri Feb 24 09:00:29 2023 +0100 Added calling conventions to functions. commit 06e65de23574b53f2bd334af9a859357fe7e7051 Author: sebastianselander Date: Thu Feb 23 11:54:35 2023 +0100 started on a test suite commit 5daa5573f26c42a1db125758d2e229fa772a2cec Author: sebastianselander Date: Wed Feb 22 15:24:38 2023 +0100 Added more comments to the code commit 8065576c31a141e191dc9f3b55afa0348b70cba9 Author: sebastianselander Date: Mon Feb 20 20:38:36 2023 +0100 Let has a bug, otherwise probably(?) done commit a98135827c5fb1df1afeb5387df4199abe2dc50d Author: sebastianselander Date: Mon Feb 20 16:51:44 2023 +0100 EAdd is bugged. Mostly complete though. commit 4df3f705ed167bbd75c3bc4901c62c422ddabb20 Author: Samuel Hammersberg Date: Mon Feb 20 16:44:27 2023 +0100 LLVMIr code now has the fastcc flag to enable speeed 😎 commit afbc700db24f88e30c342413e4db60e285da3492 Author: Samuel Hammersberg Date: Mon Feb 20 16:43:54 2023 +0100 Fixed the type checker accidentally chucking cases in some cases. commit cd0f9dd456cd862b7cce953a6f0d43beaee9fa45 Author: Samuel Hammersberg Date: Mon Feb 20 15:27:13 2023 +0100 The output directory is now cleared when the program is ran. commit a36de2bde16ebf90cc670ffd93f7bc2d79d3ce10 Author: Samuel Hammersberg Date: Mon Feb 20 14:52:11 2023 +0100 Added support for the minus operator. commit fe4533c7aeb39055b4bbfcbfaab08aafad191cd6 Author: Samuel Hammersberg Date: Mon Feb 20 14:39:56 2023 +0100 Added an option to output some debug info. commit 6749650223f4f77d2fd5df71d54658c8661ff09d Author: Samuel Hammersberg Date: Mon Feb 20 14:39:43 2023 +0100 Added support for pattern matching on ints. Might need a lookover. commit 18e0a92fe023b67f17b1f2e9d21a95edaac1ec61 Author: Samuel Hammersberg Date: Mon Feb 20 14:39:00 2023 +0100 Added grammar for case matching. commit dfbdb6678edbb25083bcf2dc7515ac716e39a65e Author: sebastianselander Date: Mon Feb 20 12:09:31 2023 +0100 Working on non-ugly version of algorithm W (Hindley-Milner) commit 420fb107f0867ab86ed7532d17685e8ab4b7de2e Author: sebastianselander Date: Sun Feb 19 15:25:49 2023 +0100 Commented code and fixed some bugs I think. Still not complete id : Int -> Int id x = x does not type check commit db932048bab8d46070b6888b5d2427cb8f9309d4 Author: sebastianselander Date: Sun Feb 19 02:10:57 2023 +0100 Tried fixing bug. Failed. commit 8b5cd3cf9ae6b7de6d046ad50187fb7672e019bc Author: sebastianselander Date: Sat Feb 18 23:08:27 2023 +0100 Remade the algorithm myself. Still some bugs. commit a4c12ede79abcb3543f5c9f892992f0d4dd46a54 Merge: 287f843 4ab6681 Author: Samuel Hammersberg Date: Sat Feb 18 15:03:11 2023 +0100 Merge branch 'prep-tc-martin' of github.com:bachelor-group-66-systemf/language into prep-tc-martin commit 287f84377ce6e23043a7dca183376350bc20a4b3 Author: Samuel Hammersberg Date: Sat Feb 18 14:36:46 2023 +0100 Implemented case matching on ints in the code generator commit f188cffb8d373823c08a50af1b69303f4cd6a9e5 Author: sebastianselander Date: Fri Feb 17 18:42:50 2023 +0100 Unification part works (probably). Have a hard time understanding it. commit 764faa582ba1a6eacfc54a0a1510df6e9a56360f Author: sebastianselander Date: Fri Feb 17 12:01:57 2023 +0100 Remove hls pragmas commit f2e8a0225546d090b00b9afcf80274675040fcae Author: sebastianselander Date: Fri Feb 17 12:01:22 2023 +0100 Removed adhoc tests commit a9f54dbca1881adb3f364099a73369db52b26ca2 Author: sebastianselander Date: Fri Feb 17 11:09:48 2023 +0100 Simplified quite a bit. Made a unify function. Still bugs left commit eafe0fea0b40fc5adc6b6cee3e5f243c5f2a6490 Author: sebastianselander Date: Thu Feb 16 16:37:36 2023 +0100 Rewrote using unification-fd. Heavily inspired (aka copied) from: https://byorgey.wordpress.com/2021/09/08/implementing-hindley-milner-with-the-unification-fd-library/ commit f1b77a7efa60bc47d998c115f8dc125b600ecd17 Author: sebastianselander Date: Wed Feb 15 19:52:52 2023 +0100 Refactored. Cleaner version, ala Martin version commit b03df17e34621b40f8c5d6c222f5506a0415ef27 Author: sebastianselander Date: Wed Feb 15 18:10:28 2023 +0100 Minor changes. Added a comment commit 7619e36c60776f7b0a8ca2d77f02f601e85b06a8 Author: sebastianselander Date: Wed Feb 15 17:40:18 2023 +0100 Inference works better now. Still work to do. Should use proper library commit ad3f6b7011b9e2c91606a130425cb92d9963d68d Author: sebastianselander Date: Tue Feb 14 22:35:00 2023 +0100 Attempt at fixing EApp, failed. commit 5d247057f56fc2ecd18323f863d59e92f34924c2 Author: sebastianselander Date: Tue Feb 14 22:03:56 2023 +0100 Minor rewrite of tc. Some bugs still left commit 6218efac20481e794925bbd933eb4daa657b53cb Author: sebastianselander Date: Tue Feb 14 16:44:38 2023 +0100 Renamer done. It renames bound variables to numbers, converts let to lambda, and removes all variables from binds commit 53314551f53c4fbd647cd6970465425dfa1087b3 Author: sebastianselander Date: Tue Feb 14 12:56:07 2023 +0100 A bit cleaner code. A renamer is the focus to make the tc simpler commit 200a9e57ed5d8fb8f2d019fc0e218a0b480172cd Author: sebastianselander Date: Tue Feb 14 10:12:38 2023 +0100 Fixed EId, more work on other expressions needed commit c10d7703ad8e5bb3634b51f8aaf018b01dd5e85c Author: sebastianselander Date: Mon Feb 13 19:03:06 2023 +0100 Progression on type checker ;) commit 73dc2e4b6a28c20b21fac8bee958733fc67507eb Author: sebastianselander Date: Mon Feb 13 12:17:49 2023 +0100 Inference on most expressions. HM based. Still have to figure out how to infer type of lambda variables, as well as how function application on polymorphic should work commit a1e9624d5ee896fe0314591ad539db995bd3b21e Author: sebastianselander Date: Fri Feb 10 12:09:08 2023 +0100 TTGing the lambda lifter commit f4f1786be3e84dc0b5bf1a6099aec45bf1b61550 Author: sebastianselander Date: Fri Feb 10 10:41:16 2023 +0100 Revert "Merge branch 'typechecking' into codegen-martin-3" This reverts commit e000e5159f12f3ba8140ed372c7aa647fd62d506, reversing changes made to 3ac8377fa01259f91986d5833693c6911bd0e8ca. commit 771c73c0dbadf9169a9f138908188f48a60716a3 Merge: b6f03e9 e000e51 Author: Sebastian Selander <70573736+sebastianselander@users.noreply.github.com> Date: Fri Feb 10 10:33:50 2023 +0100 Merge pull request #5 from bachelor-group-66-systemf/codegen-martin-3 Codegen martin 3 commit e000e5159f12f3ba8140ed372c7aa647fd62d506 Merge: 3ac8377 b6f03e9 Author: sebastianselander Date: Fri Feb 10 10:33:15 2023 +0100 Merge branch 'typechecking' into codegen-martin-3 commit 3ac8377fa01259f91986d5833693c6911bd0e8ca Author: Martin Fredin Date: Thu Feb 9 20:25:00 2023 +0100 Fix auxiliary path commit 59fb773bc1cc3d8d37531a08df223a706d2dc7a2 Author: Martin Fredin Date: Thu Feb 9 20:24:25 2023 +0100 Some clean up and documenting commit 07bec3e7ef6111960e96c5ac8695624ee68bffa8 Author: Martin Fredin Date: Thu Feb 9 20:24:06 2023 +0100 Add auxiliary module commit 7c313b3faad5bb5b3a4439300c736e81c8140645 Author: Martin Fredin Date: Thu Feb 9 20:23:49 2023 +0100 Fix basic tests commit 23261ec380040a198eb9df626debfe23bc26fa85 Author: Martin Fredin Date: Thu Feb 9 20:23:20 2023 +0100 Add llvm dep commit ce31e4d49056c252d9295c07bf267a81de6a6882 Author: Martin Fredin Date: Thu Feb 9 17:53:39 2023 +0100 Fix first unnecessary supercombinator commit b6f03e953ba007f17c2f766ef0a1f2dee72a2474 Author: sebastianselander Date: Thu Feb 9 09:42:44 2023 +0100 deprecated branch commit 7a2404cf74b4fffcd649fab330c61b7158b5034e Author: Martin Fredin Date: Thu Feb 9 06:19:58 2023 +0100 Finish Lambda Lifter commit 1f47288fcffde023ee23d84aa188762246a57771 Author: Martin Fredin Date: Thu Feb 9 05:19:51 2023 +0100 Implement lambda lifting passes: freeVars, abstract, and rename commit b6693815726c08192d4a80761bfe8c1f0f4e3785 Author: Martin Fredin Date: Thu Feb 9 05:18:49 2023 +0100 Remove files from git commit 84eb430c41c8abd8a14e7d25197c600ee1b4ec37 Author: sebastianselander Date: Fri Feb 3 11:29:42 2023 +0100 relaxed base dependency and added overwrite commit 6607173b9353c8458967c097ea5bf4053ef5ba05 Author: Patrik Jansson Date: Fri Feb 3 11:12:44 2023 +0100 Typo fix (to check access). commit be3fcfc9e3c2394e5d6517cbeabbd19b38088420 Author: sebastianselander Date: Tue Jan 24 16:39:22 2023 +0100 Typeinference/checking on expressions done. Simplified the typechecker a bit, removed GADT solution for now. Still not fully working commit b6b2dfa25f40c2416503dfc3518a05b34d8ad878 Author: sebastianselander Date: Mon Jan 23 17:17:06 2023 +0100 Some work on a typechecker commit 43e0f67fe2dceb87a8669c2d412be9c5e445dd3a Author: Martin Fredin Date: Sun Jan 22 20:16:03 2023 +0100 Fix conflict --- .gitignore | 9 +- Grammar.cf | 112 +++- Grammar.pdf | Bin 0 -> 179560 bytes Justfile | 35 + Makefile | 28 +- README.md | 245 ++++++- benchmark.py | 21 + benchmark.txt | 9 + cabal.project.local | 2 - fourmolu.yaml | 13 - language.cabal | 94 ++- pipeline.txt | 27 + sample-programs/basic-1 | 21 - sample-programs/bubble-sort.chrf | 11 + sample-programs/insertion-sort.chrf | 30 + sample-programs/loop.crf | 18 + sample-programs/lt_testing.crf | 3 + sample-programs/mono-1.crf | 8 + sample-programs/mono-2.crf | 17 + sample-programs/mono-3.crf | 11 + sample-programs/mono-4.chrf | 12 + shell.nix | 23 +- spec.txt | 121 ++++ src/AnnForall.hs | 100 +++ src/Auxiliary.hs | 68 +- src/CaseDesugar/CaseDesugar.hs | 83 +++ src/CaseDesugar/CaseDesugarIr.hs | 226 +++++++ src/Codegen/Auxillary.hs | 51 ++ src/Codegen/Codegen.hs | 35 + src/Codegen/CompilerState.hs | 147 +++++ src/Codegen/Emits.hs | 392 +++++++++++ src/Codegen/LlvmIr.hs | 271 ++++++++ src/Compiler.hs | 297 ++------- src/Desugar/Desugar.hs | 117 ++++ src/Interpreter.hs | 116 ---- src/LambdaLifter.hs | 353 ++++++---- src/LlvmIr.hs | 204 ------ src/Main.hs | 243 +++++-- src/Monomorphizer/DataTypeRemover.hs | 60 ++ src/Monomorphizer/Monomorphizer.hs | 419 ++++++++++++ src/Monomorphizer/MonomorphizerIr.hs | 182 ++++++ src/Monomorphizer/MorbIr.hs | 184 ++++++ src/OrderDefs.hs | 43 ++ src/Renamer.hs | 84 --- src/Renamer/Renamer.hs | 112 ++++ src/ReportForall.hs | 68 ++ src/TreeConverter.hs | 13 + src/TypeChecker.hs | 178 ----- src/TypeChecker/Bugs.md | 48 ++ src/TypeChecker/RemoveForall.hs | 49 ++ src/TypeChecker/ReportTEVar.hs | 84 +++ src/TypeChecker/TypeChecker.hs | 20 + src/TypeChecker/TypeCheckerBidir.hs | 858 ++++++++++++++++++++++++ src/TypeChecker/TypeCheckerHm.hs | 945 +++++++++++++++++++++++++++ src/TypeChecker/TypeCheckerIr.hs | 196 ++++++ src/TypeCheckerIr.hs | 100 --- test_program.crf | 30 + tests/DoStrings.hs | 4 + tests/Main.hs | 16 + tests/TestAnnForall.hs | 128 ++++ tests/TestLambdaLifter.hs | 106 +++ tests/TestRenamer.hs | 114 ++++ tests/TestReportForall.hs | 54 ++ tests/TestTypeCheckerBidir.hs | 333 ++++++++++ tests/TestTypeCheckerHm.hs | 265 ++++++++ 65 files changed, 7018 insertions(+), 1248 deletions(-) create mode 100644 Grammar.pdf create mode 100644 Justfile create mode 100755 benchmark.py create mode 100644 benchmark.txt delete mode 100644 cabal.project.local create mode 100644 pipeline.txt delete mode 100644 sample-programs/basic-1 create mode 100644 sample-programs/bubble-sort.chrf create mode 100644 sample-programs/insertion-sort.chrf create mode 100644 sample-programs/loop.crf create mode 100644 sample-programs/lt_testing.crf create mode 100644 sample-programs/mono-1.crf create mode 100644 sample-programs/mono-2.crf create mode 100644 sample-programs/mono-3.crf create mode 100644 sample-programs/mono-4.chrf create mode 100644 spec.txt create mode 100644 src/AnnForall.hs create mode 100644 src/CaseDesugar/CaseDesugar.hs create mode 100644 src/CaseDesugar/CaseDesugarIr.hs create mode 100644 src/Codegen/Auxillary.hs create mode 100644 src/Codegen/Codegen.hs create mode 100644 src/Codegen/CompilerState.hs create mode 100644 src/Codegen/Emits.hs create mode 100644 src/Codegen/LlvmIr.hs create mode 100644 src/Desugar/Desugar.hs delete mode 100644 src/Interpreter.hs delete mode 100644 src/LlvmIr.hs create mode 100644 src/Monomorphizer/DataTypeRemover.hs create mode 100644 src/Monomorphizer/Monomorphizer.hs create mode 100644 src/Monomorphizer/MonomorphizerIr.hs create mode 100644 src/Monomorphizer/MorbIr.hs create mode 100644 src/OrderDefs.hs delete mode 100644 src/Renamer.hs create mode 100644 src/Renamer/Renamer.hs create mode 100644 src/ReportForall.hs create mode 100644 src/TreeConverter.hs delete mode 100644 src/TypeChecker.hs create mode 100644 src/TypeChecker/Bugs.md create mode 100644 src/TypeChecker/RemoveForall.hs create mode 100644 src/TypeChecker/ReportTEVar.hs create mode 100644 src/TypeChecker/TypeChecker.hs create mode 100644 src/TypeChecker/TypeCheckerBidir.hs create mode 100644 src/TypeChecker/TypeCheckerHm.hs create mode 100644 src/TypeChecker/TypeCheckerIr.hs delete mode 100644 src/TypeCheckerIr.hs create mode 100644 test_program.crf create mode 100644 tests/DoStrings.hs create mode 100644 tests/Main.hs create mode 100644 tests/TestAnnForall.hs create mode 100644 tests/TestLambdaLifter.hs create mode 100644 tests/TestRenamer.hs create mode 100644 tests/TestReportForall.hs create mode 100644 tests/TestTypeCheckerBidir.hs create mode 100644 tests/TestTypeCheckerHm.hs diff --git a/.gitignore b/.gitignore index 0b0f588..897dce2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ dist-newstyle *.y *.x *.bak +Grammar.tex src/Grammar language @@ -13,4 +14,10 @@ src/GC/lib/*.o src/GC/lib/*.so src/GC/lib/*.a src/GC/tests/*.out -src/GC/tests/logs \ No newline at end of file +src/GC/tests/logs +test_program_result +output/ +*.o +*.out +*.aux +*.log diff --git a/Grammar.cf b/Grammar.cf index 0b4785f..2db8b14 100644 --- a/Grammar.cf +++ b/Grammar.cf @@ -1,25 +1,103 @@ -Program. Program ::= [Bind]; +------------------------------------------------------------------------------- +-- * TOP-LEVEL +------------------------------------------------------------------------------- -EId. Exp3 ::= Ident; -EInt. Exp3 ::= Integer; -EAnn. Exp3 ::= "(" Exp ":" Type ")"; -ELet. Exp3 ::= "let" Bind "in" Exp; -EApp. Exp2 ::= Exp2 Exp3; -EAdd. Exp1 ::= Exp1 "+" Exp2; -EAbs. Exp ::= "\\" Ident ":" Type "." Exp; +DBind. Def ::= Bind; +DSig. Def ::= Sig; +DData. Def ::= Data; -Bind. Bind ::= Ident ":" Type ";" - Ident [Ident] "=" Exp; +internal Sig. Sig ::= LIdent ":" Type; + SigS. Sig ::= VarName ":" Type; +internal Bind. Bind ::= LIdent [LIdent] "=" Exp; + BindS. Bind ::= VarName [LIdent] "=" Exp; -separator Bind ";"; -separator Ident ""; +------------------------------------------------------------------------------- +-- * Types +------------------------------------------------------------------------------- -coercions Exp 3; +internal TLit. Type3 ::= UIdent; -- Ο„ + TIdent. Type3 ::= UIdent; + TVar. Type3 ::= TVar; -- Ξ± + TApp. Type2 ::= Type2 Type3 ; + TFun. Type1 ::= Type1 "->" Type; -- A β†’ A + TAll. Type ::= "forall" TVar "." Type; -- βˆ€Ξ±. A +internal TEVar. Type1 ::= TEVar; -- Ξ¬ +internal TData. Type1 ::= UIdent "(" [Type] ")"; -- D () -TInt. Type1 ::= "Int" ; -TPol. Type1 ::= Ident ; -TFun. Type ::= Type1 "->" Type ; -coercions Type 1 ; + MkTVar. TVar ::= LIdent; +internal MkTEVar. TEVar ::= LIdent; + +------------------------------------------------------------------------------- +-- * DATA TYPES +------------------------------------------------------------------------------- + +Data. Data ::= "data" Type "where" "{" [Inj] "}" ; + +Inj. Inj ::= UIdent ":" Type ; + +------------------------------------------------------------------------------- +-- * PATTERN MATCHING +------------------------------------------------------------------------------- + +Branch. Branch ::= Pattern "=>" Exp ; + +PVar. Pattern1 ::= LIdent; +PLit. Pattern1 ::= Lit; +PCatch. Pattern1 ::= "_"; +PEnum. Pattern1 ::= UIdent; +PInj. Pattern ::= UIdent [Pattern1]; + +------------------------------------------------------------------------------- +-- * Expressions +------------------------------------------------------------------------------- + +internal EVar. Exp4 ::= LIdent; + EVarS. Exp4 ::= VarName ; + EInj. Exp4 ::= UIdent; + ELit. Exp4 ::= Lit; + EApp. Exp3 ::= Exp3 Exp4; + EAdd. Exp2 ::= Exp2 "+" Exp3; + ELet. Exp1 ::= "let" Bind "in" Exp1; + EAbs. Exp1 ::= "\\" LIdent "." Exp1; + ECase. Exp1 ::= "case" Exp "of" "{" [Branch] "}"; + EAnn. Exp ::= Exp1 ":" Type; + +VSymbol. VarName ::= "." Symbol; +VIdent. VarName ::= LIdent; + +infixSymbol. Exp2 ::= Exp2 Symbol Exp3 ; +define infixSymbol e1 vn e3 = EApp (EApp (EVarS (VSymbol vn)) e1) e3; + +------------------------------------------------------------------------------- +-- * LITERALS +------------------------------------------------------------------------------- + +LInt. Lit ::= Integer; +LChar. Lit ::= Char; + +------------------------------------------------------------------------------- +-- * AUX +------------------------------------------------------------------------------- + +layout "of", "where"; +layout toplevel; + +separator Def ";"; +separator Branch ";" ; +separator Inj ";"; + +separator LIdent ""; +separator Type " "; +separator TVar " "; +separator nonempty Pattern1 " "; + +coercions Pattern 1; +coercions Exp 4; +coercions Type 3 ; + +token UIdent (upper (letter | digit | '_')*) ; +token LIdent (lower (letter | digit | '_')*) ; +token Symbol (["@#%^&*_-+=|?/<>,β€’:[]"]+) ; comment "--"; comment "{-" "-}"; diff --git a/Grammar.pdf b/Grammar.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f7f7a701e9a4afa734d48301a1595340199e55eb GIT binary patch literal 179560 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

;{8nLcfop0eXQ~5Wm_bf7B8GrE9;xDUu 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

doDnGja0S=jzf)CM_?&_!_npCERVcam^P~>AWaC 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

X&ijybXJ0`q%R% zP2mgEzPfAg`q#BTH(Fbm{!e;U{_OJYiz_EwYcn--e(iTW_VKaU|BsrMUen&X=5^?U zU*GoIDr=tq-MRZ4G>d9QNRgaHH$k$fDeu7^Q&<+gEb=pH)~cU-rH?|hs2EZfjT4|^ z7X79F?+7f53KGnsVm;S!Wl^RPmPKX$!m{Y@dwb(uk3a0t`E^m&EOv3k-RlSCqe36( zV9BCp!zPP5txZ3hShh>%u7&mNnQo_o%Ta34m&bz5zm%W4leM-s;qLaQ1qTwAC+I!8 zQZs4y`(I@ut*<1jn1xqu%RaYh(f?-;WSu^Jds|Z0?z>;U>1ohe`M=Lz+U%QnZ+1eR z{kFU}zaTB$8*$KDbN2NiLG9@?r;2x#WkWjypw!A7=x7rlqVD@d}_SFpuAw~ zak~kXGS_8J)F?12FFj?&sLZZ>UeG{OLUmV2%;Cogk&S_cUaZGvwIv*r>XGW1B`KG@ zBeSc<(D&+}d%Z~w`MoB&9OB#wJxdQ8G4^qUO9bk7Bwq|aF0;Nt_?Vc*(>o#-k1akH zpIh6gd;H;Iy&d|6UVY*RM6Ek#sXdB0!kewZvHZxz6#Ly`2i*>TRn9PovG@FNc-NnZ z%f)N#u7#xk6|aAE<^Qn*+z(@SaJ=-~%*UL!NHTd|$UIYq zIt*W>b05o2_;hQ6c;q38ubZbB78=cymooa;^lOrM8e{yXCPR~S)#QpPp*<_@&gLiW z5so}7VO4xhesTV}U&$Yeulc_ZIQJ|0#mUHer=4r;55BQ{?caI+m++&_=R{@|Uz_-ac$tE_xQ`v6ubkX@Adg-DH zDb1n>^A;Nj?ENfy&w1&$3CG$PmUSsfas=`1UOOvm>vfSic}v)oCdvHz{@UC)vphVM zzjNO4{Iq*E2loB?wqf3myozs=pM@}+;D)ce+0zw?#5?YVot z%z1WuKfkm^6F+US-plq%Tt{@bHdH?s~e6d9M8~tbmfau`R>=d z14UM)zv%T@vn#fGlIY*k8Vzy?ZtW~{DPLzG# zFLC*^TjN$#Ue-~%U;h8Cq-W*5xE-etT=fNQy3$#+({WR$W`Y(=5Q`C?ilTsY0?QUY z3znP%nTHvrnIt7FL$66nuu8Z#Hk>@T;=@tnC=__yDpB>18-7x!&2(HmSf*#`oLiY|b2$82d)H!(TV^*sodL zZ)$t|SF&&EwEBhg`#nGU-Doo` z5nE&LdcW!G@(1FehHlf>Ge_meWE5fi^_nq z=n_yCHT~}O(E02~lY`JKx@#g*7X4<^_Yjsvci-C|@7n&b0aS~Y?R49?D}Ryw{(TRu zv1CyTO0y`=hVBFwa6^|Z=j4PpSR1+(vu-eX6o7R7s{kXCM z($LMgyWxG@)vxJHwhvzxS;@*A(U4sewyM-R{`&7v$<-xU{~&$Q$*{g?@ABNoZMolH zHNhIXyTA=y{oS-{=*q(SqN5F6_nJZ77xnwg3GR#Ta@)9TeY1U36xN2WCC#!ZQeX5b zIE$9z>x(`|?u**(sQdLW=Jl=9u)gTzU3%tMm%U#m?SJpf+1EQu#jibIa%gYKUv}2o zD_FYe328`|o0>zq|Bvo3cvYYLp!I`ZOv{%gk?oA;7kdo-wa!b)r9RpE z@mf`m#NpREDLlE6Mw8TPLySSLCS~7Lw=rd1qEQ)}G|v+@K$MP-52R zNrpD3w2p<$e`aoYuX9Zr&s@vb{TI#C{~G?Ve7(F}BmJ-8mnUoN7sgzhpYUzY*X2jj z|8jneOy@dl`P%1WPw_QSBNsHREA=bqMtXPTnjbxqYk$Zvcb`8ZIRE15uJaZ8Yk&0Y z3#)0HA6BE*2N@y)jowtZWF^z4HS6*b3qoWBs; z9G~MtPjkAe3-KkzD85&(EtYey=e%I+yxi*C=XK@p!!H(EfQNKrp$%QJ%@33?Yf*D7 zt8gq#sX1K4mUMCgB#UAhF1l^M8!}w<9a4+FgVmyWe?VC@^Lq`b7QMMEFn0Rvtjn^; zr2X%eoPE8tRQPpq(8D;syNE1mAqC2!7S{28c{6%JS+qnV-u5f^v`^8mHtV{w*6n&& z^J2GkYTnjsb{pQ^+GL-!q1ZsYFw5@bUHM&Q0?@wbw+lU>zUT{ZU({yT<7KzMA1qq= ztiSHF4PX9}?`kvd^RJcWyW73%pU(pI9R1~&S2s&6ZNBQYHShiFs`$D$eST;6gJxa6 zloi2dT|Q@C-;sEI?~a6(U%hl+SBXMrT|U=6T4x)6{h$7oz$r4w@^LK{h({Ei?48@-lH~Ck(S^`8Jp(Eb|)-;_)E}4 zV%>a|ABnMbYhGH0$!D+H{IA=-a5Rhl=qELcO0vPTsPprC>lX#rJ0bT)yS_Y##F9mk zS33k0<)@S;rxqz_6r`kuq(X{hm8JTEu={pytCYIzEDQJYGM!>k4`FSphC8-J; zE>?z?76t}}28IS;5T(hb@0*{3TQa05v7jI|MM2*!F{e0{OFtmQHA2s=G$$u1F)t5f ze@I4Vu|j6C0>m9U3Sp^5#hLke3dVYdCWfY#MrNkQx<-0tFb9I2rQnlUma1T6U}U79 zmsyctte0PuuBnh+kXVvYoSLXm1~tM=&sfhy6SUe7x<<+nc~Co~vLIDK-#;lUxFnZL z-%r8B1hiPNsJKMI*w_?4cWh)~ZVDOn2Fc=IO87P^I$wIbP~G?S4<1`;DCxad5fJH^ ze5+81ecj_-I~Dl5_HHZ9ie9H;o?BnLe`ciTl$4`^m!3Tp@i-P!WMTceFmFmq=;9tN z&zWm-cuuK2T@-#zBfe`>FBdC!oNDrvQmxr+Ia-&czM1&m+~g`bzo|$d#Nhpb7i&ZL z{!8UgDgH72!*%DPh93*|WPXsD+P^VSZ{>mWuB_sh#kRFf*!;<_HK*&7<59Kb;Gm0+ z!to(Ig57RMg>1}Lrtr>d_PUqa8onfjStNXA%Z}8|r_3r@r^y)otC}jD)1Yd3d`Xv< zfpcmo&z7E578x=jA6egrw1%|3WnGoiC|N&st*;B?p5<>WIXf{lZ4GNO+kxq~M8a~4?w?wA{>tCE zr+2oS95FHB-Q@U6vE9%$=X;F#vaRR;=4(qjMZWsIwtOFFMSuCq_6VJc89KI4c0G9U zSM!_BCyBkLX45Kbj>`(A9RBHSWIL02dHw;<7pbDTFBG4%M)gkne(c0*lgYX7B=5an zr26hb^_1xg-UzMSdhf`y)ZLeT4%LXnFl!5+Q)|7m*yY7S<4?M0ck%QtD!*WydPvcl z`R`tBTNUjW(huZYC!FL>^U69fQ`)`gh+6){!K*3wB_jaW!kL~H(Tkm(xy1kgZHj0o78fzKIFgoV3nWRM(!~CyP<{L{m#1>bf@t= zFWl?ZcA`VGPxJ2NWkFj%WuDrZIP0%n{q1y))S~ZizSMemR?pOxYG%>=;uqF!7Gt4o zx$(l8PJfN*&jfC$c5t!J?qW(_z9lH=-ZZYIVO#F@Sc>jE;;MZ^<+)=}*YfWbUauQ7 zMJxsNW^!Bf<>bx}lu^EqL0Qa}$_kTYEMqwqDR#c0%IOsu>q21pI%&)O@Sp`o)5< zCBlbOd+$yTn6U9odP{SBgz84SbWX;P{JWCQUTc~Dyx`R3y+;dnEs-_$i~Md^^#1XQ zs21N<*MbyPQqG9H*x?YK_3`|Xd*7diJmK)|$@XnsKD)4U@uaHLR|MX4z7|;M@;4%h zlVx|oE}hJsiRH`WrdowQn8_VJe`m_X3ww_S^@}sPZ`tE&F>{*H^(B{=pEUlP-JKGb za&5I;L1$9bc@BTucxC0!W)tqGC+|@46q})Z)6?ur+^atqYoon#58hnK@=C$D{G&$X z%Egi~%NCa=PTeSSxGHA)t#uMcqVrlq*L~Q!W&OhcWqS8F6))U=C{`y+^U}oL8q=j4 z-G8*KU!>%o(baZ1#jjT7?=DF{&y73QO;Me{#5myMM@Kh5wll8Nqi)=en0TsH@LX)r zc0HlYeD&K!UZ3||JF{cPqCn2g>7`eVHp+6>H?AW$~IiWVPGB*0M z`_7~|Ta|#~sc>hal;!1%JEE3uo2;EQN#;;O<-T&Y;@)^5pjwm(m&^?A64{toyCz4f!(|NHo5H2#VgL_ zd0)=Xc-y$}=w8qNMFpQ;{Q9%$D34m4@2%Cz6%VG>-F^G%oWlv%dKY<_zwYy2d`q+0 zArmKEYnSzVa@m*oi)rZ$l6u$YhulrS^X}febGPLa?mV=*U1Pj;t!8|3wDDG*X~~&}-(axsO@F4zrSRt0 zsw!{PJY;Nsf4uqeVEOv8ZSj}4rtykhTgl$HPxXN0>Llmd7u^XL9;eGxtyuVBU)!UN zbqo1R^K<0wY}QVoBNnsX}dzM5_NlIfwb&DH&{;`7@lPYbV9S>5#Y zNz#>VRi6quuH>)xzkTsXibdAV#|0d}&bKDt&{!>(zyId{k2_@!-%>EP^yz1OA}w>6 zufhIhL*Da>IHPIi3`^UdnEy?;mbxa;(rfhY_Vadk|9CEzlg~^ARQwy;=bifLazEzZ zWPvw_zH5AmDpUWoVB)@5gM!5_zg|3lyf|GXYkgde(iMiN@?!>Hwa@)<{K>AY zd4Y8OFOK5L$LHkuS>8R9l)2#lb`h7=f*%VlgK``q51(Z;>{^+V0NF2Cd# z$+Ps`(&LKXH?}7wJo`PVEHGK@%pHw~dHXGI)Nb-llUr+k*(^nUo$N7IXZhD5Wm20H z)NRkb*>WxK-7}9>FH}^Xe)I^sXL5dCSZn*^f5A744U_wBuWsa+dFAJ)$4ph_Pfp6O z^KV<;{JJ>8%)&bRqu8&1qTAg)Kkg{GmcPqe@yZ3g{8DvwE+y^aX-V>G>qY;onzt*> zJ!rg^aorU$QRnb!8WCwrIlr5%^wTo`#c(~fL^YOYrBGJ)b5mEX83|UrYbtAZIsTnF z?Q3M{O!<$byuGk+}SR#_QzxLhu*jUc0A3WAHGhNThGhh>tX)(a<;`ETjn@R zT0HNr`yL?RXV34aE}s0$lBZaXw|*B}!1A?S*+PGpZ;9OHuA}w%>?WftooAKiW;Y~}vY z)s|Px8$SDqD(~e@Z70`UzHoQ_!uv6YukI`JJS+^UA$)6KvO`Y!<*_N>Ko$b5D4<+a2cg}g$9$wEFpry71OJ@an87HKr9ubt9 z#-;C>my%kc5N)7fZW7C-ADmg0s$g!yr5~;kZKzM7#AC#Y8qF@f%4G{!Vo|dm* z4(j=UI4%m&Hm>HTmQE%{E@o!tCI(K1hK|l|E>4avW{xhd#;zt7#&!yXmBb>t2gU}F z-hl$)?t$!Cd+$SuB1bv%?HPF{gQ4ZAMy+0yf|b~W!?f7>v85O2_7)d(rwsQ=9+_)XWW6n|em5u$Jg3JFtP7c!P$la(Bq@+8|#Vy6vPp8{v;_DyG+D8&^Wly#E z`9Vt{TzI|dqmS2Dd(`mlxpuPbdUo?3jmoJfUfju^{70%P*D%C5F10O#r|ot4<7c;b z)S6dKKURCGLPGMdaq@>`o4b;WmG|cw+xX|!bbsL2Xjfi_8I#2&iA5z9MX70AhUS(A N=9XNls;>TSTmbwXtM32+ literal 0 HcmV?d00001 diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..a7acacd --- /dev/null +++ b/Justfile @@ -0,0 +1,35 @@ +# build from scratch +build: + bnfc -o src -d Grammar.cf + cabal install --installdir=. --overwrite-policy=always + +# clean the generated directories +clean: + rm -r src/Grammar + rm language + rm -r dist-newstyle/ + +# run all tests +test: + cabal test + +debug FILE: + cabal run language -- -d {{FILE}} + +hm FILE: + cabal run language -- -t hm {{FILE}} + +bi FILE: + cabal run language -- -t bi {{FILE}} + +hmd FILE: + cabal run language -- -d -t hm {{FILE}} + +bid FILE: + cabal run language -- -d -t bi {{FILE}} + +hmdm FILE: + cabal run language -- -d -t hm -m {{FILE}} + +bidm FILE: + cabal run language -- -d -t bi -m {{FILE}} \ No newline at end of file diff --git a/Makefile b/Makefile index e63a1e6..6c1ebde 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ language : src/Grammar/Test cabal install --installdir=. --overwrite-policy=always -src/Grammar/Test.hs src/Grammar/Lex.x src/Grammar/Par.y : Grammar.cf +src/Grammar/Test.hs src/Grammar/Lex.x src/Grammar/Par.y src/Grammar/Layout : Grammar.cf bnfc -o src -d $< src/Grammar/Par.hs : src/Grammar/Par.y @@ -15,23 +15,25 @@ src/Grammar/Lex.hs : src/Grammar/Lex.x src/Grammar/%.y : Grammar.cf bnfc -o src -d $< -src/Grammar/Test : src/Grammar/Test.hs src/Grammar/Par.hs src/Grammar/Lex.hs - ghc src/Grammar/Test.hs src/Grammar/Par.hs src/Grammar/Lex.hs src/Grammar/Abs.hs src/Grammar/Skel.hs src/Grammar/Print.hs -o src/Grammar/test +src/Grammar/Test : src/Grammar/Test.hs src/Grammar/Par.hs src/Grammar/Lex.hs src/Grammar/Layout + ghc src/Grammar/Test.hs src/Grammar/Par.hs src/Grammar/Lex.hs src/Grammar/Abs.hs src/Grammar/Skel.hs src/Grammar/Print.hs src/Grammar/Layout -o src/Grammar/test + +Grammar.tex : + bnfc --latex Grammar.cf + +Grammar.pdf : Grammar.tex + pdflatex Grammar.tex + rm Grammar.aux Grammar.log + +pdf : Grammar.pdf clean : rm -r src/Grammar rm language + rm -rf dist-newstyles + rm Grammar.aux Grammar.fdb_latexmk Grammar.fls Grammar.log Grammar.synctex.gz Grammar.tex test : - ./language ./sample-programs/basic-1 - ./language ./sample-programs/basic-2 - ./language ./sample-programs/basic-3 - ./language ./sample-programs/basic-4 - ./language ./sample-programs/basic-5 - ./language ./sample-programs/basic-5 - ./language ./sample-programs/basic-6 - ./language ./sample-programs/basic-7 - ./language ./sample-programs/basic-8 - ./language ./sample-programs/basic-9 + cabal v2-test # EOF diff --git a/README.md b/README.md index 1cfb72a..7cb234e 100644 --- a/README.md +++ b/README.md @@ -1 +1,244 @@ -# language \ No newline at end of file +# Build +First generate the parser using [BNFC](https://bnfc.digitalgrammars.com/), +this is done using the command `bnfc -o src -d Grammar.cf` + +Churf can then be built using `cabal install` + +Using the tool [make](https://www.gnu.org/software/make/) the entire thing can be built by running `make` +or using [just](https://github.com/casey/just), `just build` + +# Dependencies +If you have Nix installed, simply run `nix-shell --pure shell.nix` to get into an environment +with the right versions of packages. Then run `make` and the compiler should build. + +# Compiling a program + +Using the Hindley-Milner type checker: `./language -t hm example.crf` + +Using the bidirectional type checker: `./language -t bi example.crf` + +The program to compile has to have the file extension `.crf` +# Syntax and quirks + +See Grammar.pdf for the full syntax. + +The syntactic requirements differ a bit using the different type checkers. +The bidirectional type checker require explicit `forall` everywhere a type +forall quantified type variable is declared. In the Hindley-Milner type checker +all type variables are assumed to be forall quantified. + +Currently for the code generator and monomorphizer to work correctly it is +expected that the function `main` exist with either explicitly given type `Int` +or inferrable. + +Single line comments are written using `--` +Multi line comments are written using `{-` and `-}` + +Braches and semicolons are optional. + +## Program + +A program is a list of defs separated by semicolons, which in turn is either a bind, a signature, or a data types +`Program ::= [Def]` + +```hs +data Test () where + Test : Test () +test : Int +test = 0 +``` + +## Bind + +A bind is a name followed by a white space separated list of arguments, then an equal sign followed by an expression. +Both name and arguments have to start with lower case letters + +`Bind ::= LIdent [LIdent] "=" Exp` + +```hs +example x y = x + y +``` + +## Signature +A signature is a name followed by a colon and then the type +The name has to start with a lowe case letter + +`Sig ::= LIdent ":" Type` + +```hs +const : a -> b -> a +``` + +## Data type +A data type is declared as follows + +`Data ::= "data" Type "where" "{" [Inj] "}"` + +The words in quotes are necessary keywords +The type can be any type for parsing, but only `TData` will type check. + +The list of Inj is separated by white space. Using new lines is recommended for ones own sanity. + +```hs +data Maybe (a) where + Nothing : Maybe (a) + Just : a -> Maybe (a) +``` +The parens are necessary for every data type to make the grammar unambiguous. +Thus in `data Bool () where ...` the parens *do* *not* represent Unit + +### Inj +An inj is a constructor for the data type + +It is declared like a signature, except the name has to start with a lower case letter. +The return type of the constructor also has match the type of the data type to type check. + +`Inj ::= UIdent ":" Type` + +## Type + +A type can be either a type literal, type variable, function type, explicit forall quantified type or a type representing a data type +A type literal have to start with an upper case letter, type variables have to start with a lower case letter, +data types have to start with an upper case letter, a function type is two types separated by an arrow (arrows right associative), +and foralls take one type variable followed by a type. + +`TLit ::= UIdent` + +`TVar ::= LIdent` + +`TData ::= UIdent "(" [Type] ")"` + +`TFun ::= Type "->" Type` + +`TAll ::= "forall" LIdent "." Type` + +```hs +exampleLit : Int +exampleVar : a +exampleData : Maybe (a) +exampleFun : Int -> a +exampleAll : forall a. forall b. a -> b +``` + +## Expressions + +There are a couple different expressions, probably best explained by their rules + +Type annotated expression + +`EAnn ::= "(" Exp ":" Type ")"` + +Variable + +`EVar ::= LIdent` +```hs +x +``` + +Constructor + +`EInj ::= UIdent` +```hs +Just +``` + +Literal + +`ELit ::= Lit` +```hs +0 +``` + +Function application + +`EApp ::= Exp2 Exp3` +```hs +f 0 +``` + +Addition + +`EAdd ::= Exp1 "+" Exp2` +```hs +3 + 5 +``` + +Let expression + +`ELet ::= "let" Bind "in" Exp ` +```hs +let f x = x in f 0 +``` + +Abstraction, known as lambda or closure + +`EAbs ::= "\\" LIdent "." Exp` +```hs +\x. x +``` + +Case expression consist of a list semicolon separated list of Branches + +`ECase ::= "case" Exp "of" "{" [Branch] "}"` + +```hs +case xs of + Cons x xs => 1 + Nil => 0 +``` + +### Branch +A branch is a pattern followed by the fat arrow and then an expression + +`Branch ::= Pattern "=>" Exp` + +### Pattern +A pattern can be either a variable, literal, a wildcard represented by `_`, an enum constructor (constructor with zero arguments) +, or a constructor followed by a recursive list of patterns. + +Variable match + +`PVar ::= LIdent` + +The x in the following example +```hs +x => 0 +``` +Literal match + +`PLit ::= Lit` + +The 1 in the following example +```hs +1 => 0 +``` +A wildcard match + +`PCatch ::= "_"` + +The underscore in the following example +```hs +_ => 0 +``` +A constructor without arguments + +`PEnum ::= UIdent` + +The Nothing in the following example +```hs +Nothing => 0 +``` +The recursive match on a constructor + +`PInj ::= UIdent [Pattern1]` + +The outer Just represents the UIdent and the rest is the recursive match +```hs +Just (Just 0) => 1 +``` + +For simplicity sake a user does not need to consider these last two cases as different in parsing. +We allow arbitrarily deep pattern matching. + +## Literal +We currently allow two different literals: Integer and Char diff --git a/benchmark.py b/benchmark.py new file mode 100755 index 0000000..40f0a15 --- /dev/null +++ b/benchmark.py @@ -0,0 +1,21 @@ +#!/bin/env/python3 + +import sys +import os +import time + +if __name__ == "__main__": + args = sys.argv + if len(args) == 1: + print ("first arg is number of loops second is exe") + else: + total = 0 + iter = int(args[1]) + for i in range(iter): + time_pre = time.time() + os.system("./" + args[2] + "> /dev/null") + time_post = time.time() + calc = time_post - time_pre + total += calc + + print ("File: " + args[2] + ", " + str(iter) + " runs gave average: " + str(total / iter) + "s") diff --git a/benchmark.txt b/benchmark.txt new file mode 100644 index 0000000..c12461e --- /dev/null +++ b/benchmark.txt @@ -0,0 +1,9 @@ +# Full optimization Churf +File: output/hello_world, 100 runs gave average: 0.025261127948760988s + +# O2 Haskell +File: ./Bench, 100 runs gave average: 0.05629507303237915s + +# 03 Haskell +File: ./Bench, 100 runs gave average: 0.05490849256515503s +File: ./Bench, 100 runs gave average: 0.05323728561401367s diff --git a/cabal.project.local b/cabal.project.local deleted file mode 100644 index 0432756..0000000 --- a/cabal.project.local +++ /dev/null @@ -1,2 +0,0 @@ -ignore-project: False -tests: True diff --git a/fourmolu.yaml b/fourmolu.yaml index f15300e..8b96b58 100644 --- a/fourmolu.yaml +++ b/fourmolu.yaml @@ -1,14 +1 @@ -indentation: 4 -function-arrows: trailing -comma-style: leading -import-export-style: diff-friendly indent-wheres: false -record-brace-space: false -newlines-between-decls: 1 -haddock-style: multi-line -haddock-style-module: -let-style: auto -in-style: right-align -respectful: true -fixities: [] -unicode: never diff --git a/language.cabal b/language.cabal index 8b958a5..af7178c 100644 --- a/language.cabal +++ b/language.cabal @@ -12,11 +12,9 @@ build-type: Simple extra-doc-files: CHANGELOG.md - extra-source-files: Grammar.cf - common warnings ghc-options: -W @@ -32,14 +30,33 @@ executable language Grammar.Print Grammar.Skel Grammar.ErrM - LambdaLifter + Grammar.ErrM + Grammar.Layout Auxiliary - Renamer - TypeChecker - TypeCheckerIr --- Interpreter + Renamer.Renamer + TypeChecker.TypeChecker + AnnForall + OrderDefs + TypeChecker.TypeCheckerHm + TypeChecker.TypeCheckerBidir + TypeChecker.TypeCheckerIr + TypeChecker.ReportTEVar + TypeChecker.RemoveForall + LambdaLifter + Monomorphizer.Monomorphizer + Monomorphizer.MonomorphizerIr + Monomorphizer.MorbIr + Monomorphizer.DataTypeRemover + Codegen.Codegen + Codegen.LlvmIr + Codegen.Auxillary + Codegen.CompilerState + Codegen.Emits Compiler - LlvmIr + Renamer.Renamer + TreeConverter + Desugar.Desugar + hs-source-dirs: src build-depends: @@ -47,6 +64,65 @@ executable language , mtl , containers , either - , array , extra + , array + , hspec + , QuickCheck + , directory + , process + default-language: GHC2021 + +Test-suite language-testsuite + type: exitcode-stdio-1.0 + main-is: Main.hs + + other-modules: + TestTypeCheckerBidir + TestTypeCheckerHm + TestAnnForall + TestReportForall + TestRenamer + TestLambdaLifter + DoStrings + + Grammar.Abs + Grammar.Lex + Grammar.Par + Grammar.Print + Grammar.Skel + Grammar.ErrM + Grammar.Layout + OrderDefs + Auxiliary + Monomorphizer.Monomorphizer + Monomorphizer.MonomorphizerIr + Renamer.Renamer + TypeChecker.TypeChecker + AnnForall + ReportForall + TypeChecker.TypeCheckerHm + TypeChecker.TypeCheckerBidir + TypeChecker.ReportTEVar + TypeChecker.RemoveForall + TypeChecker.TypeCheckerIr + Compiler + + hs-source-dirs: src, tests + + build-depends: + base >=4.16 + , mtl + , containers + , either + , extra + , array + , hspec + , QuickCheck + , process + , bytestring + , hspec + , directory + + default-language: GHC2021 + diff --git a/pipeline.txt b/pipeline.txt new file mode 100644 index 0000000..1872562 --- /dev/null +++ b/pipeline.txt @@ -0,0 +1,27 @@ + + Parser + | + ReportForall Report unnecessary foralls. Hm: report rank>2 foralls + | + AnnotateForall Annotate all unbound type variables with foralls + | + Renamer Rename type variables and term variables + | + / \ + / \ + TypeCheckHm TypeCheckBi + \ / + \ / + | + ReportTEVar Report type existential variables and change type AST + | + RemoveForall RemoveForall and change type AST + | + Monomorpher + | + Desugar + | + CodeGen + + + diff --git a/sample-programs/basic-1 b/sample-programs/basic-1 deleted file mode 100644 index f0cdcc4..0000000 --- a/sample-programs/basic-1 +++ /dev/null @@ -1,21 +0,0 @@ - --- tripplemagic : Int -> Int -> Int -> Int; --- tripplemagic x y z = ((\x:Int. x+x) x) + y + z; --- main : Int; --- main = tripplemagic ((\x:Int. x+x+3) ((\x:Int. x) 2)) 5 3 --- answer: 22 - --- apply : (Int -> Int) -> Int -> Int; --- apply f x = f x; --- main : Int; --- main = apply (\x : Int . x + 5) 5 --- answer: 10 - -apply : (Int -> Int -> Int) -> Int -> Int -> Int; -apply f x y = f x y; -krimp: Int -> Int -> Int; -krimp x y = x + y; -main : Int; -main = apply (krimp) 2 3; --- answer: 5 - diff --git a/sample-programs/bubble-sort.chrf b/sample-programs/bubble-sort.chrf new file mode 100644 index 0000000..59e6598 --- /dev/null +++ b/sample-programs/bubble-sort.chrf @@ -0,0 +1,11 @@ +data List (a) where + Cons : a -> List (a) -> List (a) + Nil : List (a) + +bubblesort : List (a) -> List (a) +bubblesort xs = case xs of + Nil => Nil + Cons x => case x of + Nil => Cons x Nil + Cons y => + diff --git a/sample-programs/insertion-sort.chrf b/sample-programs/insertion-sort.chrf new file mode 100644 index 0000000..fc61691 --- /dev/null +++ b/sample-programs/insertion-sort.chrf @@ -0,0 +1,30 @@ +data List (a) where + Nil : List (a) + Cons : a -> List (a) -> List (a) + +insert : Int -> List (Int) -> List (Int) +insert x xs = case xs of + Cons z zs => case (lt x z) of + True => Cons x (Cons z zs) + False => Cons z (insert x zs) + Nil => Cons x Nil + +insertionSort : List (Int) -> List (Int) +insertionSort xs = case xs of + Cons y ys => case ys of + _ => insert y (insertionSort ys) + Nil => xs + Nil => Nil + +main = head (insertionSort (revRange 1250)) + +head xs = case xs of + Cons x _ => x + +revRange x = case x of + 0 => Cons x Nil + x => Cons x (revRange (x + minusOne)) + +-- represents minus one :) +minusOne : Int ; +minusOne = 9223372036854775807 + 9223372036854775807 + 1; \ No newline at end of file diff --git a/sample-programs/loop.crf b/sample-programs/loop.crf new file mode 100644 index 0000000..e3c3c38 --- /dev/null +++ b/sample-programs/loop.crf @@ -0,0 +1,18 @@ +main = for 0 1000 + +for x n = case n of + 0 => 0 + n => for (revRange 1000) (n + minusOne) + +data List (a) where + Nil : List (a) + Cons : a -> List (a) -> List (a) + +-- create a list of x to 0 +revRange x = case x of + 0 => Cons x Nil + x => Cons x (revRange (x + minusOne)) + +-- represents minus one :) +minusOne : Int ; +minusOne = 9223372036854775807 + 9223372036854775807 + 1; \ No newline at end of file diff --git a/sample-programs/lt_testing.crf b/sample-programs/lt_testing.crf new file mode 100644 index 0000000..5edc1c9 --- /dev/null +++ b/sample-programs/lt_testing.crf @@ -0,0 +1,3 @@ +main = case (lt 3 5) of + True => 1 + False => 0 diff --git a/sample-programs/mono-1.crf b/sample-programs/mono-1.crf new file mode 100644 index 0000000..c41e9b6 --- /dev/null +++ b/sample-programs/mono-1.crf @@ -0,0 +1,8 @@ +const2 : a -> b -> a +const2 x y = x + +f : a -> a +f x = (const2 x 'c') + +main = f 5 + diff --git a/sample-programs/mono-2.crf b/sample-programs/mono-2.crf new file mode 100644 index 0000000..76a92c2 --- /dev/null +++ b/sample-programs/mono-2.crf @@ -0,0 +1,17 @@ +data Either (a b) where + Left : a -> Either (a b) + Right : b -> Either (a b) + +unwrapLeft : Either (a b) -> a +unwrapLeft x = case x of + Left y => y + +unwrapRight : Either (a b) -> b +unwrapRight x = case x of + Right y => y + +wow : Either (Int Char) +wow = Left 5 + +main = unwrapLeft wow + diff --git a/sample-programs/mono-3.crf b/sample-programs/mono-3.crf new file mode 100644 index 0000000..a51df2c --- /dev/null +++ b/sample-programs/mono-3.crf @@ -0,0 +1,11 @@ +data Number() where + One: Number () + Two: Number () + +numberToInt : Number () -> Int +numberToInt n = case n of + One => 1 + Two => 2 + +main = numberToInt One + diff --git a/sample-programs/mono-4.chrf b/sample-programs/mono-4.chrf new file mode 100644 index 0000000..79d1495 --- /dev/null +++ b/sample-programs/mono-4.chrf @@ -0,0 +1,12 @@ +data Either (a b) where + Left : a -> Either (a b) + Right : b -> Either (a b) + +unwrap : Either (a a) -> a +unwrap x = case x of + Left y => y + Right y => y + +main : Int +main = unwrap (Left 3) + diff --git a/shell.nix b/shell.nix index 0af8c7b..c8cc7a8 100644 --- a/shell.nix +++ b/shell.nix @@ -6,15 +6,20 @@ pkgs.haskellPackages.developPackage { withHoogle = true; modifier = drv: pkgs.haskell.lib.addBuildTools drv ( - (with pkgs; [ hlint haskell-language-server ghc jasmin llvmPackages_15.libllvm]) + (with pkgs; [ hlint + haskell-language-server + ghc + jasmin + llvmPackages_15.libllvm +# texlive.combined.scheme-full + graphviz + ]) ++ - (with pkgs.haskellPackages; [ - cabal-install - stylish-haskell - BNFC - alex - happy - ]) - ); + (with pkgs.haskellPackages; [ cabal-install + stylish-haskell + BNFC + alex + happy + ])); } diff --git a/spec.txt b/spec.txt new file mode 100644 index 0000000..2273846 --- /dev/null +++ b/spec.txt @@ -0,0 +1,121 @@ +--------------------------------------------------------------------------- +-- * Parser +--------------------------------------------------------------------------- + +data Program = Program [Def] + +data Def = DSig Ident Type | DBind Bind + +data Bind = Bind Ident [Ident] Exp + +data Exp + = EId Ident + | ELit Lit + | EAnn Exp Type + | ELet Ident Exp Exp + | EApp Exp Exp + | EAdd Exp Exp + | EAbs Ident Exp + +data Lit = LInt Integer + | LChar Character + +data Type + = TLit Ident -- Ο„ + | TVar TVar -- Ξ± + | TFun Type Type -- A β†’ A + | TAll TVar Type -- βˆ€Ξ±. A + | TEVar TEVar -- Ξ¬ (internal) + +data TVar = MkTVar Ident +data TEVar = MkTEVar Ident + +--------------------------------------------------------------------------- +-- * Type checker +--------------------------------------------------------------------------- + +-- β€’ Def and DSig are removed in favor on just Bind +-- β€’ Typed expressions +-- β€’ TEVar is removed (NOT IMPLEMENTED) + +newtype Program = Program [Bind] + +data Bind = Bind Id [Id] ExpT + +data Exp + = EId Ident + | ELit Lit + | ELet Bind ExpT + | EApp ExpT ExpT + | EAdd ExpT ExpT + | EAbs Ident ExpT + +type Id = (Ident, Type) +type ExpT = (Exp, Type) + + +data Lit = LInt Integer + | LChar Character + +data Type + = TLit Ident -- Ο„ + | TVar TVar -- Ξ± + | TFun Type Type -- A β†’ A + | TAll TVar Type -- βˆ€Ξ±. A + +data TVar = MkTVar Ident + +--------------------------------------------------------------------------- +-- * Lambda lifter +--------------------------------------------------------------------------- +-- β€’ EAbs are removed (NOT IMPLEMENTED) +-- β€’ ELet only allow constant expressions (NOT IMPLEMENTED) + +newtype Program = Program [Bind] + +data Bind = Bind Id [Id] ExpT + +data Exp + = EId Ident + | ELit Lit + | ELet Ident ExpT ExpT + | EApp ExpT ExpT + | EAdd ExpT ExpT + +type Id = (Ident, Type) +type ExpT = (Exp, Type) + +data Lit = LInt Integer + | LChar Character + +data Type + = TLit Ident -- Ο„ + | TVar TVar -- Ξ± + | TFun Type Type -- A β†’ A + | TAll TVar Type -- βˆ€Ξ±. A + +data TVar = MkTVar Ident + +--------------------------------------------------------------------------- +-- * Monomorpher +--------------------------------------------------------------------------- +-- β€’ Polymorphic types are removed (NOT IMPLEMENTED) + +newtype Program = Program [Bind] + +data Bind = Bind Id [Id] ExpT + +data Exp + = EId Ident + | ELit Lit + | ELet Ident ExpT ExpT + | EApp ExpT ExpT + | EAdd ExpT ExpT + +type Id = (Ident, Type) +type ExpT = (Exp, Type) + +data Lit = LInt Integer + | LChar Character + +data Type = Type Ident diff --git a/src/AnnForall.hs b/src/AnnForall.hs new file mode 100644 index 0000000..16222bd --- /dev/null +++ b/src/AnnForall.hs @@ -0,0 +1,100 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} + +module AnnForall (annotateForall) where + +import Auxiliary (partitionDefs) +import Control.Applicative (Applicative (liftA2)) +import Control.Monad.Except (throwError) +import Data.Function (on) +import Data.Set (Set) +import qualified Data.Set as Set +import Grammar.Abs +import Grammar.ErrM (Err) + +annotateForall :: Program -> Err Program +annotateForall (Program defs) = do + ds' <- mapM (fmap DData . annData) ds + bs' <- mapM (fmap DBind . annBind) bs + pure $ Program (ds' ++ ss' ++ bs') + where + ss' = map (DSig . annSig) ss + (ds, ss, bs) = partitionDefs defs + + +annData :: Data -> Err Data +annData (Data typ injs) = do + (typ', tvars) <- annTyp typ + pure (Data typ' $ map (annInj tvars) injs) + + where + annTyp typ = do + (bounded, ts) <- boundedTVars mempty typ + unbounded <- Set.fromList <$> mapM assertTVar ts + let diff = unbounded Set.\\ bounded + typ' = foldr TAll typ diff + (typ', ) . fst <$> boundedTVars mempty typ' + where + boundedTVars tvars typ = case typ of + TAll tvar t -> boundedTVars (Set.insert tvar tvars) t + TData _ ts -> pure (tvars, ts) + _ -> throwError "Misformed data declaration" + + assertTVar typ = case typ of + TVar tvar -> pure tvar + _ -> throwError $ unwords [ "Misformed data declaration:" + , "Non type variable argument" + ] + annInj tvars (Inj n t) = + Inj n $ foldr TAll t (unboundedTVars t Set.\\ tvars) + +annSig :: Sig -> Sig +annSig (Sig name typ) = Sig name $ annType typ + +annBind :: Bind -> Err Bind +annBind (Bind name vars exp) = Bind name vars <$> annExp exp + where + annExp = \case + EAnn e t -> flip EAnn (annType t) <$> annExp e + EApp e1 e2 -> liftA2 EApp (annExp e1) (annExp e2) + EAdd e1 e2 -> liftA2 EAdd (annExp e1) (annExp e2) + ELet bind e -> liftA2 ELet (annBind bind) (annExp e) + EAbs x e -> EAbs x <$> annExp e + ECase e bs -> liftA2 ECase (annExp e) (mapM annBranch bs) + e -> pure e + annBranch (Branch p e) = Branch p <$> annExp e + +annType :: Type -> Type +annType typ = go $ unboundedTVars typ + where + go us + | null us = typ + | otherwise = foldr TAll typ us + +unboundedTVars :: Type -> Set TVar +unboundedTVars = unboundedTVars' mempty + +unboundedTVars' :: Set TVar -> Type -> Set TVar +unboundedTVars' bs typ = tvars.unbounded Set.\\ tvars.bounded + where + tvars = gatherTVars typ + gatherTVars = \case + TAll tvar t -> TVars { bounded = Set.singleton tvar + , unbounded = unboundedTVars' (Set.insert tvar bs) t + } + TVar tvar -> uTVars $ Set.singleton tvar + TFun t1 t2 -> uTVars $ on Set.union (unboundedTVars' bs) t1 t2 + TData _ typs -> uTVars $ foldr (Set.union . unboundedTVars' bs) mempty typs + _ -> TVars { bounded = mempty, unbounded = mempty } + +data TVars = TVars + { bounded :: Set TVar + , unbounded :: Set TVar + } deriving (Eq, Show, Ord) + +uTVars :: Set TVar -> TVars +uTVars us = TVars + { bounded = mempty + , unbounded = us + } + diff --git a/src/Auxiliary.hs b/src/Auxiliary.hs index 735d804..22095aa 100644 --- a/src/Auxiliary.hs +++ b/src/Auxiliary.hs @@ -1,8 +1,18 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE Rank2Types #-} + module Auxiliary (module Auxiliary) where + import Control.Monad.Error.Class (liftEither) -import Control.Monad.Except (MonadError) +import Control.Monad.Except (MonadError, liftM2) import Data.Either.Combinators (maybeToRight) +import Data.List (foldl') +import Grammar.Abs +import Prelude hiding ((>>), (>>=)) + +(>>) a b = a ++ " " ++ b +(>>=) a f = f a snoc :: a -> [a] -> [a] snoc x xs = xs ++ [x] @@ -14,8 +24,52 @@ mapAccumM :: Monad m => (s -> a -> m (s, b)) -> s -> [a] -> m (s, [b]) mapAccumM f = go where go acc = \case - [] -> pure (acc, []) - x:xs -> do - (acc', x') <- f acc x - (acc'', xs') <- go acc' xs - pure (acc'', x':xs') + [] -> pure (acc, []) + x : xs -> do + (acc', x') <- f acc x + (acc'', xs') <- go acc' xs + pure (acc'', x' : xs') + +onMM :: Monad m => (b -> b -> m c) -> (a -> m b) -> a -> a -> m c +onMM f g x y = liftMM2 f (g x) (g y) + +onM :: Monad m => (b -> b -> c) -> (a -> m b) -> a -> a -> m c +onM f g x y = liftM2 f (g x) (g y) + +unzip4 :: [(a, b, c, d)] -> ([a], [b], [c], [d]) +unzip4 = + foldl' + ( \(as, bs, cs, ds) (a, b, c, d) -> + (as ++ [a], bs ++ [b], cs ++ [c], ds ++ [d]) + ) + ([], [], [], []) + +liftMM2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m c +liftMM2 f m1 m2 = do + x1 <- m1 + x2 <- m2 + f x1 x2 + +litType :: Lit -> Type +litType (LInt _) = int +litType (LChar _) = char + +int = TLit "Int" +char = TLit "Char" + +tupSequence :: Monad m => (m a, b) -> m (a, b) +tupSequence (ma, b) = (,b) <$> ma + +fst_ :: (a, b, c) -> a +snd_ :: (a, b, c) -> b +trd_ :: (a, b, c) -> c +snd_ (_, a, _) = a +fst_ (a, _, _) = a +trd_ (_, _, a) = a + +partitionDefs :: [Def] -> ([Data], [Sig], [Bind]) +partitionDefs defs = (datas, sigs, binds) + where + datas = [ d | DData d <- defs ] + sigs = [ s | DSig s <- defs ] + binds = [ b | DBind b <- defs ] diff --git a/src/CaseDesugar/CaseDesugar.hs b/src/CaseDesugar/CaseDesugar.hs new file mode 100644 index 0000000..e1db55e --- /dev/null +++ b/src/CaseDesugar/CaseDesugar.hs @@ -0,0 +1,83 @@ +{-# LANGUAGE LambdaCase #-} + +module CaseDesugar.CaseDesugar (desuga) where + +import CaseDesugar.CaseDesugarIr qualified as CIR +import TypeChecker.TypeCheckerIr qualified as TIR + +desuga :: TIR.Program -> CIR.Program +desuga (TIR.Program x) = CIR.Program $ desugaDef <$> x + +desugaDef :: TIR.Def -> CIR.Def +desugaDef (TIR.DBind bin@TIR.Bind{}) = CIR.DBind $ desugaBind bin +desugaDef (TIR.DData dat@TIR.Data{}) = CIR.DData $ desugaData dat + +desugaData :: TIR.Data -> CIR.Data +desugaData (TIR.Data t injs) = CIR.Data (desugaType t) (desugaInj <$> injs) + +desugaType :: TIR.Type -> CIR.Type +desugaType (TIR.TLit (TIR.Ident s)) = CIR.TLit (CIR.Ident s) +desugaType (TIR.TVar tv) = CIR.TVar (desugaTVar tv) +desugaType (TIR.TData (TIR.Ident s) ts) = CIR.TData (CIR.Ident s) (desugaType <$> ts) +desugaType (TIR.TFun t1 t2) = CIR.TFun (desugaType t1) (desugaType t2) +desugaType (TIR.TAll _ t1) = desugaType t1 + +desugaTVar :: TIR.TVar -> CIR.TVar +desugaTVar (TIR.MkTVar (TIR.Ident s)) = CIR.MkTVar (CIR.Ident s) + +desugaInj :: TIR.Inj -> CIR.Inj +desugaInj (TIR.Inj (TIR.Ident s) t) = CIR.Inj (CIR.Ident s) (desugaType t) + +desugaId :: TIR.Id -> CIR.Id +desugaId (TIR.Ident s, t) = (CIR.Ident s, desugaType t) + +desugaBind :: TIR.Bind -> CIR.Bind +desugaBind (TIR.Bind id args exp) = + CIR.Bind (desugaId id) (desugaId <$> args) (desugaExpT exp) + +desugaExpT :: TIR.ExpT -> CIR.ExpT +desugaExpT (exp, t) = (desugaExp exp, desugaType t) + +desugaExp :: TIR.Exp -> CIR.Exp +desugaExp (TIR.EVar (TIR.Ident s)) = CIR.EVar (CIR.Ident s) +desugaExp (TIR.EInj (TIR.Ident s)) = CIR.EInj (CIR.Ident s) +desugaExp (TIR.ELit lit) = CIR.ELit lit +desugaExp (TIR.ELet b e) = CIR.ELet (desugaBind b) (desugaExpT e) +desugaExp (TIR.EApp e1 e2) = CIR.EApp (desugaExpT e1) (desugaExpT e2) +desugaExp (TIR.EAdd e1 e2) = CIR.EAdd (desugaExpT e1) (desugaExpT e2) +desugaExp (TIR.EAbs (TIR.Ident s) e) = CIR.EAbs (CIR.Ident s) (desugaExpT e) +desugaExp (TIR.ECase e branches) = CIR.ECase (desugaExpT e) (desugaBranches branches) + +desugaBranches :: [TIR.Branch] -> [CIR.Branch] +desugaBranches bs = do + let injections = filter (\case (TIR.Branch (TIR.PInj{}, _) _) -> True; _ -> False) bs + let patterns = filter (\case (TIR.Branch (TIR.PInj{}, _) _) -> True; _ -> False) bs + undefined + +desugaBranch :: TIR.Branch -> CIR.Branch +desugaBranch (TIR.Branch (TIR.PInj (TIR.Ident s) ps, pt) e) = do + undefined +desugaBranch (TIR.Branch (p, pt) e) = do + CIR.Branch + ( case p of + TIR.PVar id -> (CIR.PVar (desugaId id), desugaType pt) + TIR.PLit (lit, t) -> (CIR.PLit (lit, desugaType t), desugaType pt) + TIR.PCatch -> (CIR.PCatch, desugaType pt) + TIR.PEnum (TIR.Ident s) -> (CIR.PEnum (CIR.Ident s), desugaType pt) + ) + (desugaExpT e) + +{- +case (Tupli 5 5) of + Tupli 6 5 => 1 + Tupli _ x => 3 + x => 1 +=== +case (Tupli 5 5) of + Tupli x y => case x of + 6 => case y of + 5 => 1 + x => 3 + _ => case y of + x => 3 +-} \ No newline at end of file diff --git a/src/CaseDesugar/CaseDesugarIr.hs b/src/CaseDesugar/CaseDesugarIr.hs new file mode 100644 index 0000000..dd9864f --- /dev/null +++ b/src/CaseDesugar/CaseDesugarIr.hs @@ -0,0 +1,226 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE PatternSynonyms #-} + +module CaseDesugar.CaseDesugarIr ( + module Grammar.Abs, + module CaseDesugar.CaseDesugarIr, +) where + +import Data.String (IsString) +import Grammar.Abs (Lit (..)) +import Grammar.Print +import Prelude +import Prelude qualified as C (Eq, Ord, Read, Show) + +newtype Program' t = Program [Def' t] + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Def' t + = DBind (Bind' t) + | DData (Data' t) + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Type + = TLit Ident + | TVar TVar + | TData Ident [Type] + | TFun Type Type + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Data' t = Data t [Inj' t] + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Inj' t = Inj Ident t + deriving (C.Eq, C.Ord, C.Show, C.Read) + +newtype Ident = Ident String + deriving (C.Eq, C.Ord, C.Show, C.Read, IsString) + +data Pattern' t + = PVar (Id' t) -- TODO should be Ident + | PLit (Lit, t) -- TODO should be Lit + | PCatch + | PEnum Ident + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Exp' t + = EVar Ident + | EInj Ident + | ELit Lit + | ELet (Bind' t) (ExpT' t) + | EApp (ExpT' t) (ExpT' t) + | EAdd (ExpT' t) (ExpT' t) + | EAbs Ident (ExpT' t) + | ECase (ExpT' t) [Branch' t] + deriving (C.Eq, C.Ord, C.Show, C.Read) + +newtype TVar = MkTVar Ident + deriving (C.Eq, C.Ord, C.Show, C.Read) + +type Id' t = (Ident, t) +type ExpT' t = (Exp' t, t) + +data Bind' t = Bind (Id' t) [Id' t] (ExpT' t) + deriving (C.Eq, C.Ord, C.Show, C.Read) + +data Branch' t = Branch (Pattern' t, t) (ExpT' t) + deriving (C.Eq, C.Ord, C.Show, C.Read) + +instance Print Ident where + prt _ (Ident s) = doc $ showString s + +instance Print t => Print (Program' t) where + prt i (Program sc) = prPrec i 0 $ prt 0 sc + +instance Print t => Print (Bind' t) where + prt i (Bind sig@(name, _) parms rhs) = + prPrec i 0 $ + concatD + [ prtSig sig + , prt 0 name + , prtIdPs 0 parms + , doc $ showString "=" + , prt 0 rhs + ] + +prtSig :: Print t => Id' t -> Doc +prtSig (name, t) = + concatD + [ prt 0 name + , doc $ showString ":" + , prt 0 t + , doc $ showString ";" + ] + +instance Print t => Print (ExpT' t) where + prt i (e, t) = + concatD + [ doc $ showString "(" + , prt i e + , doc $ showString "," + , prt i t + , doc $ showString ")" + ] + +instance Print t => Print [Bind' t] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +prtIdPs :: Print t => Int -> [Id' t] -> Doc +prtIdPs i = prPrec i 0 . concatD . map (prt i) + +instance Print t => Print (Id' t) where + prt i (name, t) = + concatD + [ doc $ showString "(" + , prt i name + , doc $ showString "," + , prt i t + , doc $ showString ")" + ] + +instance Print t => Print (Exp' t) where + prt i = \case + EVar name -> prPrec i 3 $ prt 0 name + EInj name -> prPrec i 3 $ prt 0 name + ELit lit -> prPrec i 3 $ prt 0 lit + ELet b e -> + prPrec i 3 $ + concatD + [ doc $ showString "let" + , prt 0 b + , doc $ showString "in" + , prt 0 e + ] + EApp e1 e2 -> + prPrec i 2 $ + concatD + [ prt 2 e1 + , prt 3 e2 + ] + EAdd e1 e2 -> + prPrec i 1 $ + concatD + [ prt 1 e1 + , doc $ showString "+" + , prt 2 e2 + ] + EAbs v e -> + prPrec i 0 $ + concatD + [ doc $ showString "\\" + , prt 0 v + , doc $ showString "." + , prt 0 e + ] + ECase e branches -> + prPrec i 0 $ + concatD + [ doc $ showString "case" + , prt 0 e + , doc $ showString "of" + , doc $ showString "{" + , prt 0 branches + , doc $ showString "}" + ] + +instance Print t => Print (Branch' t) where + prt i (Branch (pattern_, t) exp) = prPrec i 0 (concatD [doc (showString "("), prt 0 pattern_, doc (showString " : "), prt 0 t, doc (showString ")"), doc (showString "=>"), prt 0 exp]) + +instance Print t => Print [Branch' t] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print t => Print (Def' t) where + prt i = \case + DBind bind -> prPrec i 0 (concatD [prt 0 bind]) + DData data_ -> prPrec i 0 (concatD [prt 0 data_]) + +instance Print t => Print (Data' t) where + prt i = \case + Data type_ injs -> prPrec i 0 (concatD [doc (showString "data"), prt 0 type_, doc (showString "where"), doc (showString "{"), prt 0 injs, doc (showString "}")]) + +instance Print t => Print (Inj' t) where + prt i = \case + Inj uident type_ -> prPrec i 0 (concatD [prt 0 uident, doc (showString ":"), prt 0 type_]) + +instance Print t => Print (Pattern' t) where + prt i = \case + PVar name -> prPrec i 1 (concatD [prt 0 name]) + PLit (lit, _) -> prPrec i 1 (concatD [prt 0 lit]) + PCatch -> prPrec i 1 (concatD [doc (showString "_")]) + PEnum name -> prPrec i 1 (concatD [prt 0 name]) + +instance Print t => Print [Def' t] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print [Type] where + prt _ [] = concatD [] + prt _ (x : xs) = concatD [prt 0 x, doc (showString " "), prt 0 xs] + +instance Print Type where + prt i = \case + TLit uident -> prPrec i 1 (concatD [prt 0 uident]) + TVar tvar -> prPrec i 1 (concatD [prt 0 tvar]) + TData uident types -> prPrec i 1 (concatD [prt 0 uident, doc (showString "("), prt 0 types, doc (showString ")")]) + TFun type_1 type_2 -> prPrec i 0 (concatD [prt 1 type_1, doc (showString "->"), prt 0 type_2]) + +instance Print TVar where + prt i (MkTVar ident) = prt i ident + +type Program = Program' Type +type Def = Def' Type +type Data = Data' Type +type Bind = Bind' Type +type Branch = Branch' Type +type Pattern = Pattern' Type +type Inj = Inj' Type +type Exp = Exp' Type +type ExpT = ExpT' Type +type Id = Id' Type +pattern DBind' id vars expt = DBind (Bind id vars expt) +pattern DData' typ injs = DData (Data typ injs) diff --git a/src/Codegen/Auxillary.hs b/src/Codegen/Auxillary.hs new file mode 100644 index 0000000..c95be39 --- /dev/null +++ b/src/Codegen/Auxillary.hs @@ -0,0 +1,51 @@ +module Codegen.Auxillary where + +import Codegen.LlvmIr (LLVMType (..), LLVMValue (..)) +import Control.Monad (foldM_) +import Monomorphizer.MonomorphizerIr as MIR (ExpT, Type (..)) +import TypeChecker.TypeCheckerIr qualified as TIR + +type2LlvmType :: MIR.Type -> LLVMType +type2LlvmType (MIR.TLit id@(TIR.Ident name)) = case name of + "Int" -> I64 + "Char" -> I8 + "Bool" -> I1 + _ -> CustomType id +type2LlvmType (MIR.TFun t xs) = do + let (t', xs') = function2LLVMType xs [type2LlvmType t] + Function t' xs' + where + function2LLVMType :: Type -> [LLVMType] -> (LLVMType, [LLVMType]) + function2LLVMType (TFun t xs) s = function2LLVMType xs (type2LlvmType t : s) + function2LLVMType x s = (type2LlvmType x, s) + +getType :: ExpT -> LLVMType +getType (_, t) = type2LlvmType t + +extractTypeName :: MIR.Type -> TIR.Ident +extractTypeName (MIR.TLit id) = id +extractTypeName (MIR.TFun t xs) = + let (TIR.Ident i) = extractTypeName t + (TIR.Ident is) = extractTypeName xs + in TIR.Ident $ i <> "_$_" <> is + +valueGetType :: LLVMValue -> LLVMType +valueGetType (VInteger _) = I64 +valueGetType (VChar _) = I8 +valueGetType (VIdent _ t) = t +valueGetType (VConstant s) = Array (fromIntegral $ length s) I8 +valueGetType (VFunction _ _ t) = t + +typeByteSize :: LLVMType -> Integer +typeByteSize I1 = 1 +typeByteSize I8 = 1 +typeByteSize I32 = 4 +typeByteSize I64 = 8 +typeByteSize Ptr = 8 +typeByteSize (Ref _) = 8 +typeByteSize (Function _ _) = 8 +typeByteSize (Array n t) = n * typeByteSize t +typeByteSize (CustomType _) = 8 + +enumerateOneM_ :: Monad m => (Integer -> a -> m b) -> [a] -> m () +enumerateOneM_ f = foldM_ (\i a -> f i a >> pure (i + 1)) 1 diff --git a/src/Codegen/Codegen.hs b/src/Codegen/Codegen.hs new file mode 100644 index 0000000..be92a35 --- /dev/null +++ b/src/Codegen/Codegen.hs @@ -0,0 +1,35 @@ +module Codegen.Codegen (generateCode) where + +import Codegen.CompilerState ( + CodeGenerator (instructions), + initCodeGenerator, + ) +import Codegen.Emits (compileScs) +import Codegen.LlvmIr as LIR (llvmIrToString) +import Control.Monad.State ( + execStateT, + ) +import Data.List (sortBy) +import Grammar.ErrM (Err) +import Monomorphizer.MonomorphizerIr as MIR (Bind (..), Data (..), Def (DBind, DData), Program (..), Type (TLit)) +import TypeChecker.TypeCheckerIr (Ident (..)) + +{- | Compiles an AST and produces a LLVM Ir string. + An easy way to actually "compile" this output is to + Simply pipe it to LLI +-} +generateCode :: MIR.Program -> Bool -> Err String +generateCode (MIR.Program scs) addGc = do + let tree = filter (not . detectPrelude) (sortBy lowData scs) + let codegen = initCodeGenerator addGc tree + llvmIrToString . instructions <$> execStateT (compileScs tree) codegen + +detectPrelude :: Def -> Bool +detectPrelude (DData (Data (TLit (Ident "Bool")) _)) = True +detectPrelude (DBind (Bind (Ident ('l' : 't' : '$' : _), _) _ _)) = True +detectPrelude _ = False + +lowData :: Def -> Def -> Ordering +lowData (DData _) (DBind _) = LT +lowData (DBind _) (DData _) = GT +lowData _ _ = EQ \ No newline at end of file diff --git a/src/Codegen/CompilerState.hs b/src/Codegen/CompilerState.hs new file mode 100644 index 0000000..523cc54 --- /dev/null +++ b/src/Codegen/CompilerState.hs @@ -0,0 +1,147 @@ +module Codegen.CompilerState where + +import Auxiliary (snoc) +import Codegen.Auxillary (type2LlvmType, typeByteSize) +import Codegen.LlvmIr as LIR (LLVMIr (UnsafeRaw), + LLVMType) +import Control.Monad.State (StateT, gets, modify) +import Data.Map (Map) +import qualified Data.Map as Map +import Grammar.ErrM (Err) +import Monomorphizer.MonomorphizerIr as MIR +import qualified TypeChecker.TypeCheckerIr as TIR + +-- | The record used as the code generator state +data CodeGenerator = CodeGenerator + { instructions :: [LLVMIr] + , functions :: Map MIR.Id FunctionInfo + , customTypes :: Map LLVMType Integer + , constructors :: Map TIR.Ident ConstructorInfo + , variableCount :: Integer + , labelCount :: Integer + , gcEnabled :: Bool + } + +-- | A state type synonym +type CompilerState a = StateT CodeGenerator Err a + +data FunctionInfo = FunctionInfo + { numArgs :: Int + , arguments :: [Id] + } + deriving (Show) +data ConstructorInfo = ConstructorInfo + { numArgsCI :: Int + , argumentsCI :: [Id] + , numCI :: Integer + , returnTypeCI :: MIR.Type + } + deriving (Show) + +-- | Adds a instruction to the CodeGenerator state +emit :: LLVMIr -> CompilerState () +emit l = modify $ \t -> t{instructions = Auxiliary.snoc l $ instructions t} + +-- | Increases the variable counter in the CodeGenerator state +increaseVarCount :: CompilerState () +increaseVarCount = modify $ \t -> t{variableCount = variableCount t + 1} + +-- | Returns the variable count from the CodeGenerator state +getVarCount :: CompilerState Integer +getVarCount = gets variableCount + +-- | Increases the variable count and returns it from the CodeGenerator state +getNewVar :: CompilerState TIR.Ident +getNewVar = TIR.Ident . show <$> (increaseVarCount >> getVarCount) + +-- | Increses the label count and returns a label from the CodeGenerator state +getNewLabel :: CompilerState Integer +getNewLabel = do + modify (\t -> t{labelCount = labelCount t + 1}) + gets labelCount + +{- | Produces a map of functions infos from a list of binds, + which contains useful data for code generation. +-} +getFunctions :: [MIR.Def] -> Map Id FunctionInfo +getFunctions bs = Map.fromList $ go bs + where + go [] = [] + go (MIR.DBind (MIR.Bind id args _) : xs) = + (id, FunctionInfo{numArgs = length args, arguments = args}) + : go xs + go (_ : xs) = go xs + +createArgs :: [MIR.Type] -> [Id] +createArgs xs = fst $ foldl (\(acc, l) t -> (acc ++ [(TIR.Ident ("arg_" <> show l), t)], l + 1)) ([], 0) xs + +{- | Produces a map of functions infos from a list of binds, + which contains useful data for code generation. +-} +getConstructors :: [MIR.Def] -> Map TIR.Ident ConstructorInfo +getConstructors bs = Map.fromList $ go bs + where + go [] = [] + go (MIR.DData (MIR.Data t cons) : xs) = + fst + ( foldl + ( \(acc, i) (Inj id xs) -> + ( ( id + , ConstructorInfo + { numArgsCI = length (init . flattenType $ xs) + , argumentsCI = createArgs (init . flattenType $ xs) + , numCI = i + , returnTypeCI = t -- last . flattenType $ xs + } + ) + : acc + , i + 1 + ) + ) + ([], 0) + cons + ) + <> go xs + go (_ : xs) = go xs + +getTypes :: [MIR.Def] -> Map LLVMType Integer +getTypes bs = Map.fromList $ go bs + where + go [] = [] + go (MIR.DData (MIR.Data t ts) : xs) = (type2LlvmType t, biggestVariant ts) : go xs + go (_ : xs) = go xs + variantTypes fi = init $ map type2LlvmType (flattenType fi) + biggestVariant ts = 8 + maximum (sum . (\(Inj _ fi) -> typeByteSize <$> variantTypes fi) <$> ts) + +initCodeGenerator :: Bool -> [MIR.Def] -> CodeGenerator +initCodeGenerator addGc scs = + CodeGenerator + { instructions = defaultStart <> if addGc then gcStart else [] + , functions = getFunctions scs + , constructors = getConstructors scs + , customTypes = getTypes scs + , variableCount = 0 + , labelCount = 0 + , gcEnabled = addGc + } + +defaultStart :: [LLVMIr] +defaultStart = + [ UnsafeRaw "target triple = \"x86_64-pc-linux-gnu\"\n" + , UnsafeRaw "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n" + , UnsafeRaw "@.str = private unnamed_addr constant [3 x i8] c\"%i\n\", align 1\n" + , UnsafeRaw "@.non_exhaustive_patterns = private unnamed_addr constant [41 x i8] c\"Non-exhaustive patterns in case at %i:%i\n\"\n" + , UnsafeRaw "declare i32 @printf(ptr noalias nocapture, ...)\n" + , UnsafeRaw "declare i32 @exit(i32 noundef)\n" + , UnsafeRaw "declare ptr @malloc(i32 noundef)\n" + ] + +gcStart :: [LLVMIr] +gcStart = + [ UnsafeRaw "declare external void @cheap_init()\n" + , UnsafeRaw "declare external ptr @cheap_alloc(i64)\n" + , UnsafeRaw "declare external void @cheap_dispose()\n" + , UnsafeRaw "declare external ptr @cheap_the()\n" + , UnsafeRaw "declare external void @cheap_set_profiler(ptr, i1)\n" + , UnsafeRaw "declare external void @cheap_profiler_log_options(ptr, i64)\n" + ] diff --git a/src/Codegen/Emits.hs b/src/Codegen/Emits.hs new file mode 100644 index 0000000..bc19f87 --- /dev/null +++ b/src/Codegen/Emits.hs @@ -0,0 +1,392 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} + +module Codegen.Emits where + +import Codegen.Auxillary +import Codegen.CompilerState +import Codegen.LlvmIr as LIR +import Control.Applicative ((<|>)) +import Control.Monad (when) +import Control.Monad.State (gets, modify) +import Data.Bifunctor qualified as BI +import Data.Char (ord) +import Data.Coerce (coerce) +import Data.Map qualified as Map +import Data.Maybe (fromJust, fromMaybe, isNothing) +import Data.Tuple.Extra (dupe, first, second) +import Debug.Trace (trace, traceShow) +import Grammar.Print +import Monomorphizer.MonomorphizerIr as MIR +import TypeChecker.TypeCheckerIr qualified as TIR + +compileScs :: [MIR.Def] -> CompilerState () +compileScs [] = do + emit $ UnsafeRaw "\n" + -- as a last step create all the constructors + -- //TODO maybe merge this with the data type match? + c <- gets (Map.toList . constructors) + mapM_ + ( \(id, ci) -> do + let t = returnTypeCI ci + let t' = type2LlvmType t + let x = BI.second type2LlvmType <$> argumentsCI ci + emit $ Define FastCC t' id x + top <- getNewVar + ptr <- getNewVar + -- allocated the primary type + emit $ SetVariable top (Alloca t') + + -- set the first byte to the index of the constructor + emit $ + SetVariable ptr $ + GetElementPtr + t' + (Ref t') + (VIdent top I8) + I64 + (VInteger 0) + I32 + (VInteger 0) + emit $ Store I8 (VInteger $ numCI ci) (Ref I8) ptr + + -- get a pointer of the correct type + ptr' <- getNewVar + emit $ SetVariable ptr' (Bitcast (Ref t') (VIdent top Ptr) (Ref $ CustomType id)) + cTypes <- gets customTypes + + enumerateOneM_ + ( \i (TIR.Ident arg_n, arg_t) -> do + let arg_t' = type2LlvmType arg_t + emit $ Comment (toIr arg_t' <> " " <> arg_n <> " " <> show i) + elemPtr <- getNewVar + emit $ + SetVariable + elemPtr + ( GetElementPtr + (CustomType id) + (Ref (CustomType id)) + (VIdent ptr' Ptr) + I64 + (VInteger 0) + I32 + (VInteger i) + ) + case Map.lookup arg_t' cTypes of + Just s -> do + emit $ Comment "Malloc and store" + heapPtr <- getNewVar + useGc <- gets gcEnabled + emit $ SetVariable heapPtr (if useGc then GcMalloc s else Malloc s) + emit $ Store arg_t' (VIdent (TIR.Ident arg_n) arg_t') Ptr heapPtr + emit $ Store (Ref arg_t') (VIdent heapPtr arg_t') Ptr elemPtr + Nothing -> do + emit $ Comment "Just store" + emit $ Store arg_t' (VIdent (TIR.Ident arg_n) arg_t') Ptr elemPtr + ) + (argumentsCI ci) + + -- load and return the constructed value + emit $ Comment "Return the newly constructed value" + load <- getNewVar + emit $ SetVariable load (Load t' Ptr top) + emit $ Ret t' (VIdent load t') + emit DefineEnd + emit $ UnsafeRaw "\n" + + modify $ \s -> s{variableCount = 0} + ) + c +compileScs (MIR.DBind (MIR.Bind (name, t) args exp) : xs) = do + let t_return = type2LlvmType . last . flattenType $ t + emit $ UnsafeRaw "\n" + emit . Comment $ show name <> ": " <> show exp + let args' = map (second type2LlvmType) args + emit $ Define FastCC t_return name args' + useGc <- gets gcEnabled + when (name == "main") (mapM_ emit (firstMainContent useGc)) + functionBody <- exprToValue exp + if name == "main" + then mapM_ emit $ lastMainContent useGc functionBody + else emit $ Ret t_return functionBody + emit DefineEnd + modify $ \s -> s{variableCount = 0} + compileScs xs +compileScs (MIR.DData (MIR.Data typ ts) : xs) = do + let (TIR.Ident outer_id) = extractTypeName typ + -- //TODO this could be extracted from the customTypes map + let variantTypes fi = init $ map type2LlvmType (flattenType fi) + let biggestVariant = 7 + maximum (sum . (\(Inj _ fi) -> typeByteSize <$> variantTypes fi) <$> ts) + emit $ LIR.Type (TIR.Ident outer_id) [I8, Array biggestVariant I8] + typeSets <- gets customTypes + mapM_ + ( \(Inj inner_id fi) -> do + let types = (\s -> if Map.member s typeSets then Ref s else s) <$> variantTypes fi + emit $ LIR.Type inner_id (I8 : types) + ) + ts + compileScs xs + +firstMainContent :: Bool -> [LLVMIr] +firstMainContent True = + [ UnsafeRaw "%prof = call ptr @cheap_the()\n" + , UnsafeRaw "call void @cheap_set_profiler(ptr %prof, i1 true)\n" + , UnsafeRaw "call void @cheap_profiler_log_options(ptr %prof, i64 30)\n" + , UnsafeRaw "call void @cheap_init()\n" + ] +firstMainContent False = [] + +lastMainContent :: Bool -> LLVMValue -> [LLVMIr] +lastMainContent True var = + [ UnsafeRaw $ + "call i32 (ptr, ...) @printf(ptr noundef @.str, i64 noundef " <> toIr var <> ")\n" + , UnsafeRaw "call void @cheap_dispose()\n" + , Ret I64 (VInteger 0) + ] +lastMainContent False var = + [ UnsafeRaw $ + "call i32 (ptr, ...) @printf(ptr noundef @.str, i64 noundef " <> toIr var <> ")\n" + , Ret I64 (VInteger 0) + ] + +compileExp :: ExpT -> CompilerState () +compileExp (MIR.ELit lit, _t) = emitLit lit +compileExp (MIR.EAdd e1 e2, t) = emitAdd t e1 e2 +compileExp (MIR.EVar name, _t) = emitIdent name +compileExp (MIR.EApp e1 e2, t) = emitApp t e1 e2 +compileExp (MIR.ELet bind e, _) = emitLet bind e +compileExp (MIR.ECase e cs, t) = emitECased t e (map (t,) cs) + +emitLet :: MIR.Bind -> ExpT -> CompilerState () +emitLet (MIR.Bind id [] innerExp) e = do + evaled <- exprToValue innerExp + tempVar <- getNewVar + let t = type2LlvmType . snd $ innerExp + emit $ SetVariable tempVar (Alloca t) + emit $ Store (type2LlvmType . snd $ innerExp) evaled Ptr tempVar + emit $ SetVariable (fst id) (Load t Ptr tempVar) + compileExp e +emitLet b _ = error $ "Non empty argument list in let-bind " <> show b + +emitECased :: MIR.Type -> ExpT -> [(MIR.Type, Branch)] -> CompilerState () +emitECased t e cases = do + let cs = snd <$> cases + let ty = type2LlvmType t + let rt = type2LlvmType (snd e) + vs <- exprToValue e + lbl <- getNewLabel + let label = TIR.Ident $ "escape_" <> show lbl + stackPtr <- getNewVar + emit $ SetVariable stackPtr (Alloca ty) + mapM_ (emitCases rt ty label stackPtr vs) cs + -- crashLbl <- TIR.Ident . ("crash_" <>) . show <$> getNewLabel + -- emit $ Label crashLbl + var_num <- getVarCount + emit . UnsafeRaw $ "call i32 (ptr, ...) @printf(ptr noundef @.non_exhaustive_patterns, i64 noundef " <> show var_num <> ", i64 noundef 6)\n" + useGc <- gets gcEnabled + when useGc (emit . UnsafeRaw $ "call void @cheap_dispose()\n") + emit . UnsafeRaw $ "call i32 @exit(i32 noundef 1)\n" + mapM_ (const increaseVarCount) [0 .. 1] + emit $ Br label + emit $ Label label + res <- getNewVar + emit $ SetVariable res (Load ty Ptr stackPtr) + where + emitCases :: LLVMType -> LLVMType -> TIR.Ident -> TIR.Ident -> LLVMValue -> Branch -> CompilerState () + emitCases rt ty label stackPtr vs (Branch (MIR.PInj consId cs, _t) exp) = do + emit $ Comment "Inj" + cons <- gets constructors + let r = fromJust $ Map.lookup consId cons + + lbl_failPos <- (\x -> TIR.Ident $ "failed_" <> show x) <$> getNewLabel + lbl_succPos <- (\x -> TIR.Ident $ "success_" <> show x) <$> getNewLabel + + consVal <- getNewVar + emit $ SetVariable consVal (ExtractValue rt vs 0) + + consCheck <- getNewVar + emit $ SetVariable consCheck (Icmp LLEq I8 (VIdent consVal I8) (VInteger $ numCI r)) + emit $ BrCond (VIdent consCheck ty) lbl_succPos lbl_failPos + emit $ Label lbl_succPos + + castPtr <- getNewVar + casted <- getNewVar + emit $ SetVariable castPtr (Alloca rt) + emit $ Store rt vs Ptr castPtr + emit $ SetVariable casted (Load (CustomType (coerce consId)) Ptr castPtr) + enumerateOneM_ + ( \i c -> do + case c of + PVar (x, topT) -> do + let topT' = type2LlvmType topT + let botT' = CustomType (coerce consId) + emit . Comment $ "ident " <> toIr topT' + cTypes <- gets customTypes + if Map.member topT' cTypes + then do + deref <- getNewVar + emit $ SetVariable deref (ExtractValue botT' (VIdent casted Ptr) i) + emit $ SetVariable x (Load topT' Ptr deref) + else emit $ SetVariable x (ExtractValue botT' (VIdent casted Ptr) i) + PLit (_l, _t) -> error "Nested pattern matching to be implemented" + PInj _id _ps -> error "Nested pattern matching to be implemented" + PCatch -> pure () + PEnum _id -> error "Nested pattern matching to be implemented" + ) + cs + val <- exprToValue exp + emit $ Store ty val Ptr stackPtr + emit $ Br label + emit $ Label lbl_failPos + emitCases _rt ty label stackPtr vs (Branch (MIR.PLit (i, ct), t) exp) = do + emit $ Comment "Plit" + let i' = case i of + MIR.LInt i -> VInteger i + MIR.LChar i -> VChar (ord i) + ns <- getNewVar + lbl_failPos <- (\x -> TIR.Ident $ "failed_" <> show x) <$> getNewLabel + lbl_succPos <- (\x -> TIR.Ident $ "success_" <> show x) <$> getNewLabel + emit $ SetVariable ns (Icmp LLEq (type2LlvmType ct) vs i') + emit $ BrCond (VIdent ns ty) lbl_succPos lbl_failPos + emit $ Label lbl_succPos + val <- exprToValue exp + emit $ Store ty val Ptr stackPtr + emit $ Br label + emit $ Label lbl_failPos + emitCases rt ty label stackPtr vs (Branch (MIR.PVar (id, _), _) exp) = do + emit $ Comment "Pvar" + -- //TODO this is pretty disgusting and would heavily benefit from a rewrite + valPtr <- getNewVar + emit $ SetVariable valPtr (Alloca rt) + emit $ Store rt vs Ptr valPtr + emit $ SetVariable id (Load rt Ptr valPtr) + val <- exprToValue exp + emit $ Store ty val Ptr stackPtr + emit $ Br label + lbl_failPos <- (\x -> TIR.Ident $ "failed_" <> show x) <$> getNewLabel + emit $ Label lbl_failPos + emitCases rt ty label stackPtr vs (Branch (MIR.PEnum (TIR.Ident "True$Bool"), t) exp) = do + emitCases rt ty label stackPtr vs (Branch (MIR.PLit (MIR.LInt 1, TLit "Bool"), t) exp) + emitCases rt ty label stackPtr vs (Branch (MIR.PEnum (TIR.Ident "False$Bool"), _) exp) = do + emitCases rt ty label stackPtr vs (Branch (MIR.PLit (MIR.LInt 0, TLit "Bool"), t) exp) + emitCases rt ty label stackPtr vs br@(Branch (MIR.PEnum consId, _) exp) = do + emit $ Comment "Penum" + cons <- gets constructors + let r = Map.lookup consId cons + when (isNothing r) (error $ "Constructor: '" ++ printTree consId ++ "' does not exist in cons state:\n" ++ show cons ++ "\nin pattern\n'" ++ printTree br ++ "'\n") + + lbl_failPos <- (\x -> TIR.Ident $ "failed_" <> show x) <$> getNewLabel + lbl_succPos <- (\x -> TIR.Ident $ "success_" <> show x) <$> getNewLabel + + consVal <- getNewVar + emit $ SetVariable consVal (ExtractValue rt vs 0) + + consCheck <- getNewVar + emit $ SetVariable consCheck (Icmp LLEq I8 (VIdent consVal I8) (VInteger $ numCI (fromJust r))) + emit $ BrCond (VIdent consCheck ty) lbl_succPos lbl_failPos + emit $ Label lbl_succPos + + castPtr <- getNewVar + casted <- getNewVar + emit $ SetVariable castPtr (Alloca rt) + emit $ Store rt vs Ptr castPtr + emit $ SetVariable casted (Load (CustomType (coerce consId)) Ptr castPtr) + val <- exprToValue exp + emit $ Store ty val Ptr stackPtr + emit $ Br label + emit $ Label lbl_failPos + emitCases _ ty label stackPtr _ (Branch (MIR.PCatch, _) exp) = do + emit $ Comment "Pcatch" + val <- exprToValue exp + emit $ Store ty val Ptr stackPtr + emit $ Br label + lbl_failPos <- (\x -> TIR.Ident $ "failed_" <> show x) <$> getNewLabel + emit $ Label lbl_failPos + +emitApp :: MIR.Type -> ExpT -> ExpT -> CompilerState () +emitApp rt e1 e2 = appEmitter e1 e2 [] + where + appEmitter :: ExpT -> ExpT -> [ExpT] -> CompilerState () + appEmitter e1 e2 stack = do + let newStack = e2 : stack + case e1 of + (MIR.EApp e1' e2', _) -> appEmitter e1' e2' newStack + (MIR.EVar name, t) -> do + args <- traverse exprToValue newStack + vs <- getNewVar + funcs <- gets functions + consts <- gets constructors + let visibility = + fromMaybe Local $ + Global <$ Map.lookup name consts + <|> Global <$ Map.lookup (name, t) funcs + -- this piece of code could probably be improved, i.e remove the double `const Global` + args' = map (first valueGetType . dupe) args + let call = + case name of + TIR.Ident ('l' : 't' : '$' : _) -> Icmp LLSlt I64 (snd (head args')) (snd (args' !! 1)) + TIR.Ident ('$' : 'm' : 'i' : 'n' : 'u' : 's' : '$' : '$' : _) -> Sub I64 (snd (head args')) (snd (args' !! 1)) + _ -> Call FastCC (type2LlvmType rt) visibility name args' + emit $ Comment $ show rt + emit $ SetVariable vs call + x -> error $ "The unspeakable happened: " <> show x + +emitIdent :: TIR.Ident -> CompilerState () +emitIdent id = do + -- !!this should never happen!! + emit $ Comment "This should not have happened!" + emit $ Variable id + emit $ UnsafeRaw "\n" + +emitLit :: MIR.Lit -> CompilerState () +emitLit i = do + -- !!this should never happen!! + let (i', t) = case i of + (MIR.LInt i'') -> (VInteger i'', I64) + (MIR.LChar i'') -> (VChar $ ord i'', I8) + varCount <- getNewVar + emit $ Comment "This should not have happened!" + emit $ SetVariable varCount (Add t i' (VInteger 0)) + +emitAdd :: MIR.Type -> ExpT -> ExpT -> CompilerState () +emitAdd t e1 e2 = do + v1 <- exprToValue e1 + v2 <- exprToValue e2 + v <- getNewVar + emit $ SetVariable v (Add (type2LlvmType t) v1 v2) + +exprToValue :: ExpT -> CompilerState LLVMValue +exprToValue = \case + (MIR.ELit i, _t) -> pure $ case i of + (MIR.LInt i) -> VInteger i + (MIR.LChar i) -> VChar $ ord i + (MIR.EVar (TIR.Ident "True$Bool"), _t) -> pure $ VInteger 1 + (MIR.EVar (TIR.Ident "False$Bool"), _t) -> pure $ VInteger 0 + (MIR.EVar name, t) -> do + funcs <- gets functions + cons <- gets constructors + let res = + Map.lookup (name, t) funcs + <|> ( \c -> + FunctionInfo + { numArgs = numArgsCI c + , arguments = argumentsCI c + } + ) + <$> Map.lookup name cons + case res of + Just fi -> do + if numArgs fi == 0 + then do + vc <- getNewVar + emit $ + SetVariable + vc + (Call FastCC (type2LlvmType t) Global name []) + pure $ VIdent vc (type2LlvmType t) + else pure $ VFunction name Global (type2LlvmType t) + Nothing -> pure $ VIdent name (type2LlvmType t) + e -> do + compileExp e + v <- getVarCount + pure $ VIdent (TIR.Ident $ show v) (getType e) diff --git a/src/Codegen/LlvmIr.hs b/src/Codegen/LlvmIr.hs new file mode 100644 index 0000000..cc77cf9 --- /dev/null +++ b/src/Codegen/LlvmIr.hs @@ -0,0 +1,271 @@ +{-# LANGUAGE LambdaCase #-} + +module Codegen.LlvmIr ( + LLVMType (..), + LLVMIr (..), + llvmIrToString, + LLVMValue (..), + LLVMComp (..), + Visibility (..), + CallingConvention (..), + ToIr (..), +) where + +import Data.List (intercalate) +import TypeChecker.TypeCheckerIr (Ident (..)) + +data CallingConvention = TailCC | FastCC | CCC | ColdCC deriving (Show, Eq, Ord) +instance ToIr CallingConvention where + toIr :: CallingConvention -> String + toIr TailCC = "tailcc" + toIr FastCC = "fastcc" + toIr CCC = "ccc" + toIr ColdCC = "coldcc" + +-- | A datatype which represents some basic LLVM types +data LLVMType + = I1 + | I8 + | I32 + | I64 + | Ptr + | Ref LLVMType + | Function LLVMType [LLVMType] + | Array Integer LLVMType + | CustomType Ident + deriving (Show, Eq, Ord) + +class ToIr a where + toIr :: a -> String + +instance ToIr LLVMType where + toIr :: LLVMType -> String + toIr = \case + I1 -> "i1" + I8 -> "i8" + I32 -> "i32" + I64 -> "i64" + Ptr -> "ptr" + Ref ty -> toIr ty <> "*" + Function t xs -> toIr t <> " (" <> intercalate ", " (map toIr xs) <> ")*" + Array n ty -> concat ["[", show n, " x ", toIr ty, "]"] + CustomType (Ident ty) -> "%" <> ty + +data LLVMComp + = LLEq + | LLNe + | LLUgt + | LLUge + | LLUlt + | LLUle + | LLSgt + | LLSge + | LLSlt + | LLSle + deriving (Show, Eq, Ord) +instance ToIr LLVMComp where + toIr :: LLVMComp -> String + toIr = \case + LLEq -> "eq" + LLNe -> "ne" + LLUgt -> "ugt" + LLUge -> "uge" + LLUlt -> "ult" + LLUle -> "ule" + LLSgt -> "sgt" + LLSge -> "sge" + LLSlt -> "slt" + LLSle -> "sle" + +data Visibility = Local | Global deriving (Show, Eq, Ord) +instance ToIr Visibility where + toIr :: Visibility -> String + toIr Local = "%" + toIr Global = "@" + +{- | Represents a LLVM "value", as in an integer, a register variable, +or a string contstant +-} +data LLVMValue + = VInteger Integer + | VChar Int + | VIdent Ident LLVMType + | VConstant String + | VFunction Ident Visibility LLVMType + deriving (Show, Eq, Ord) + +instance ToIr LLVMValue where + toIr :: LLVMValue -> String + toIr v = case v of + VInteger i -> show i + VChar i -> show i + VIdent (Ident n) _ -> "%" <> n + VFunction (Ident n) vis _ -> toIr vis <> n + VConstant s -> "c" <> show s + +type Params = [(Ident, LLVMType)] +type Args = [(LLVMType, LLVMValue)] + +-- | A datatype which represents different instructions in LLVM +data LLVMIr + = Type Ident [LLVMType] + | Define CallingConvention LLVMType Ident Params + | DefineEnd + | Declare LLVMType Ident Params + | SetVariable Ident LLVMIr + | Variable Ident + | ExtractValue LLVMType LLVMValue Integer + | GetElementPtr LLVMType LLVMType LLVMValue LLVMType LLVMValue LLVMType LLVMValue + | GetElementPtrInbounds LLVMType LLVMType LLVMValue LLVMType LLVMValue LLVMType LLVMValue + | Add LLVMType LLVMValue LLVMValue + | Sub LLVMType LLVMValue LLVMValue + | Div LLVMType LLVMValue LLVMValue + | Mul LLVMType LLVMValue LLVMValue + | Srem LLVMType LLVMValue LLVMValue + | Icmp LLVMComp LLVMType LLVMValue LLVMValue + | Br Ident + | BrCond LLVMValue Ident Ident + | Label Ident + | Call CallingConvention LLVMType Visibility Ident Args + | Alloca LLVMType + | Store LLVMType LLVMValue LLVMType Ident + | Load LLVMType LLVMType Ident + | Bitcast LLVMType LLVMValue LLVMType + | Ret LLVMType LLVMValue + | Comment String + | Malloc Integer + | GcMalloc Integer + | UnsafeRaw String -- This should generally be avoided, and proper + -- instructions should be used in its place + deriving (Show, Eq, Ord) + +-- | Converts a list of LLVMIr instructions to a string +llvmIrToString :: [LLVMIr] -> String +llvmIrToString = go 0 + where + go :: Int -> [LLVMIr] -> String + go _ [] = mempty + go i (x : xs) = do + let (i', n) = case x of + Define{} -> (i + 1, 0) + DefineEnd -> (i - 1, 0) + _ -> (i, i) + insToString n x <> go i' xs + +-- \| Converts a LLVM inststruction to a String, allowing for printing etc. +-- The integer represents the indentation +-- +{- FOURMOLU_DISABLE -} + insToString :: Int -> LLVMIr -> String + insToString i l = + replicate i '\t' <> case l of + (GetElementPtr t1 t2 p t3 v1 t4 v2) -> do + -- getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + concat + [ "getelementptr ", toIr t1, ", " , toIr t2 + , " ", toIr p, ", ", toIr t3, " ", toIr v1 + , ", ", toIr t4, " ", toIr v2, "\n" + ] + (ExtractValue t1 v i) -> do + concat + [ "extractvalue ", toIr t1, " " + , toIr v, ", ", show i, "\n" + ] + (GetElementPtrInbounds t1 t2 p t3 v1 t4 v2) -> do + -- getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + concat + [ "getelementptr inbounds ", toIr t1, ", " , toIr t2 + , " ", toIr p, ", ", toIr t3, " ", toIr v1, + ", ", toIr t4, " ", toIr v2, "\n" ] + (Type (Ident n) types) -> + concat + [ "%", n, " = type { " + , intercalate ", " (map toIr types) + , " }\n" + ] + (Define c t (Ident i) params) -> + concat + [ "define ", toIr c, " ", toIr t, " @", i + , "(", intercalate ", " (map (\(Ident y, x) -> unwords [toIr x, "%" <> y]) params) + , ") {\n" + ] + DefineEnd -> "}\n" + (Declare _t (Ident _i) _params) -> undefined + (SetVariable (Ident i) ir) -> concat ["%", i, " = ", insToString 0 ir] + (Add t v1 v2) -> + concat + [ "add ", toIr t, " ", toIr v1 + , ", ", toIr v2, "\n" + ] + (Sub t v1 v2) -> + concat + [ "sub ", toIr t, " ", toIr v1, ", " + , toIr v2, "\n" + ] + (Div t v1 v2) -> + concat + [ "sdiv ", toIr t, " ", toIr v1, ", " + , toIr v2, "\n" + ] + (Mul t v1 v2) -> + concat + [ "mul ", toIr t, " ", toIr v1 + , ", ", toIr v2, "\n" + ] + (Srem t v1 v2) -> + concat + [ "srem ", toIr t, " ", toIr v1, ", " + , toIr v2, "\n" + ] + (Call c t vis (Ident i) arg) -> + concat + [ "call ", toIr c, " ", toIr t, " ", toIr vis, i, "(" + , intercalate ", " $ Prelude.map (\(x, y) -> toIr x <> " " <> toIr y) arg + , ")\n" + ] + (Alloca t) -> unwords ["alloca", toIr t, "\n"] + (Malloc t) -> + concat + [ "call ptr @malloc(i64 ", show t, ")\n"] + (GcMalloc t) -> + concat + [ "call ptr @cheap_alloc(i64 ", show t, ")\n"] + (Store t1 val t2 (Ident id2)) -> + concat + [ "store ", toIr t1, " ", toIr val + , ", ", toIr t2 , " %", id2, "\n" + ] + (Load t1 t2 (Ident addr)) -> + concat + [ "load ", toIr t1, ", " + , toIr t2, " %", addr, "\n" + ] + (Bitcast t1 v t2) -> + concat + [ "bitcast ", toIr t1, " " + , toIr v, " to ", toIr t2, "\n" + ] + (Icmp comp t v1 v2) -> + concat + [ "icmp ", toIr comp, " ", toIr t + , " ", toIr v1, ", ", toIr v2, "\n" + ] + (Ret t v) -> + concat + [ "ret ", toIr t, " " + , toIr v, "\n" + ] + (UnsafeRaw s) -> s + (Label (Ident s)) -> "\n" <> lblPfx <> s <> ":\n" + (Br (Ident s)) -> "br label %" <> lblPfx <> s <> "\n" + (BrCond val (Ident s1) (Ident s2)) -> + concat + [ "br i1 ", toIr val, ", ", "label %" + , lblPfx, s1, ", ", "label %", lblPfx, s2, "\n" + ] + (Comment s) -> "; " <> s <> "\n" + (Variable (Ident id)) -> "%" <> id +{- FOURMOLU_ENABLE -} + +lblPfx :: String +lblPfx = "lbl_" diff --git a/src/Compiler.hs b/src/Compiler.hs index fd6b6bc..3fb1fe1 100644 --- a/src/Compiler.hs +++ b/src/Compiler.hs @@ -1,266 +1,43 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} - module Compiler (compile) where -import Auxiliary (snoc) -import Control.Monad.State (StateT, execStateT, gets, modify) -import Data.Map (Map) -import qualified Data.Map as Map -import Data.Tuple.Extra (dupe, first, second) -import Grammar.ErrM (Err) -import LlvmIr (LLVMIr (..), LLVMType (..), - LLVMValue (..), Visibility (..), - llvmIrToString) -import TypeChecker (partitionType) -import TypeCheckerIr +import System.Process.Extra (readCreateProcess, shell) --- | The record used as the code generator state -data CodeGenerator = CodeGenerator - { instructions :: [LLVMIr] - , functions :: Map Id FunctionInfo - , variableCount :: Integer - } +-- spawnWait s = spawnCommand s >>= \s >>= waitForProcess --- | A state type synonym -type CompilerState a = StateT CodeGenerator Err a +optimize :: String -> IO String +optimize = readCreateProcess (shell "opt --O3 --tailcallopt -S") -data FunctionInfo = FunctionInfo - { numArgs :: Int - , arguments :: [Id] - } +compileClang :: Bool -> String -> IO String +compileClang False = + readCreateProcess . shell $ + unwords + [ "clang++" -- , "-Lsrc/GC/lib/", "-l:libgcoll.a" + , "-fno-rtti" + , "-x" + , "ir" -- , "-Lsrc/GC/lib -l:gcoll.a" + , "-o" + , "output/hello_world" + , "-" + ] +compileClang True = + readCreateProcess . shell $ + unwords + [ "clang++" -- , "-Lsrc/GC/lib/", "-l:libgcoll.a" + , "-fno-rtti" + , "src/GC/lib/cheap.cpp" + , "src/GC/lib/event.cpp" + , "src/GC/lib/heap.cpp" + , "src/GC/lib/profiler.cpp" + , "-Wall -Wextra -g -std=gnu++20 -stdlib=libstdc++" + , "-O3" + --, "-tailcallopt" + , "-Isrc/GC/include" + , "-x" + , "ir" -- , "-Lsrc/GC/lib -l:gcoll.a" + , "-o" + , "output/hello_world" + , "-" + ] --- | Adds a instruction to the CodeGenerator state -emit :: LLVMIr -> CompilerState () -emit l = modify $ \t -> t { instructions = snoc l $ instructions t } - --- | Increases the variable counter in the CodeGenerator state -increaseVarCount :: CompilerState () -increaseVarCount = modify $ \t -> t { variableCount = variableCount t + 1 } - --- | Returns the variable count from the CodeGenerator state -getVarCount :: CompilerState Integer -getVarCount = gets variableCount - --- | Increases the variable count and returns it from the CodeGenerator state -getNewVar :: CompilerState Integer -getNewVar = increaseVarCount >> getVarCount - --- | Produces a map of functions infos from a list of binds, --- which contains useful data for code generation. -getFunctions :: [Bind] -> Map Id FunctionInfo -getFunctions bs = Map.fromList $ map go bs - where - go (Bind id args _) = - (id, FunctionInfo { numArgs=length args, arguments=args }) - - - -initCodeGenerator :: [Bind] -> CodeGenerator -initCodeGenerator scs = CodeGenerator { instructions = defaultStart - , functions = getFunctions scs - , variableCount = 0 - } - --- | Compiles an AST and produces a LLVM Ir string. --- An easy way to actually "compile" this output is to --- Simply pipe it to lli -compile :: Program -> Err String -compile (Program scs) = do - let codegen = initCodeGenerator scs - llvmIrToString . instructions <$> execStateT (compileScs scs) codegen - -compileScs :: [Bind] -> CompilerState () -compileScs [] = pure () -compileScs (Bind (name, t) args exp : xs) = do - emit $ UnsafeRaw "\n" - emit . Comment $ show name <> ": " <> show exp - let args' = map (second type2LlvmType) args - emit $ Define (type2LlvmType t_return) name args' - functionBody <- exprToValue exp - if name == "main" - then mapM_ emit $ mainContent functionBody - else emit $ Ret I64 functionBody - emit DefineEnd - modify $ \s -> s { variableCount = 0 } - compileScs xs - where - t_return = snd $ partitionType (length args) t - -mainContent :: LLVMValue -> [LLVMIr] -mainContent var = - [ UnsafeRaw $ - "call i32 (ptr, ...) @printf(ptr noundef @.str, i64 noundef " <> show var <> ")\n" - , -- , SetVariable (Ident "p") (Icmp LLEq I64 (VInteger 2) (VInteger 2)) - -- , BrCond (VIdent (Ident "p")) (Ident "b_1") (Ident "b_2") - -- , Label (Ident "b_1") - -- , UnsafeRaw - -- "call i32 (ptr, ...) @printf(ptr noundef @.str, i64 noundef 1)\n" - -- , Br (Ident "end") - -- , Label (Ident "b_2") - -- , UnsafeRaw - -- "call i32 (ptr, ...) @printf(ptr noundef @.str, i64 noundef 2)\n" - -- , Br (Ident "end") - -- , Label (Ident "end") - Ret I64 (VInteger 0) - ] - -defaultStart :: [LLVMIr] -defaultStart = [ UnsafeRaw "@.str = private unnamed_addr constant [3 x i8] c\"%i\n\", align 1\n" - , UnsafeRaw "declare i32 @printf(ptr noalias nocapture, ...)\n" - ] - -compileExp :: Exp -> CompilerState () -compileExp = \case - EInt i -> emitInt i - EAdd t e1 e2 -> emitAdd t e1 e2 - EId (name, _) -> emitIdent name - EApp t e1 e2 -> emitApp t e1 e2 - EAbs t ti e -> emitAbs t ti e - ELet bind e -> emitLet bind e - ---- aux functions --- -emitAbs :: Type -> Id -> Exp -> CompilerState () -emitAbs _t tid e = emit . Comment $ "Lambda escaped previous stages: \\" <> show tid <> " . " <> show e - -emitLet :: Bind -> Exp -> CompilerState () -emitLet b e = emit . Comment $ concat [ "ELet (" - , show b - , " = " - , show e - , ") is not implemented!" - ] - -emitApp :: Type -> Exp -> Exp -> CompilerState () -emitApp t e1 e2 = appEmitter t e1 e2 [] - where - appEmitter :: Type -> Exp -> Exp -> [Exp] -> CompilerState () - appEmitter t e1 e2 stack = do - let newStack = e2 : stack - case e1 of - EApp _ e1' e2' -> appEmitter t e1' e2' newStack - EId id@(name, _) -> do - args <- traverse exprToValue newStack - vs <- getNewVar - funcs <- gets functions - let visibility = maybe Local (const Global) $ Map.lookup id funcs - args' = map (first valueGetType . dupe) args - call = Call (type2LlvmType t) visibility name args' - emit $ SetVariable (Ident $ show vs) call - x -> do - emit . Comment $ "The unspeakable happened: " - emit . Comment $ show x - -emitIdent :: Ident -> CompilerState () -emitIdent id = do - -- !!this should never happen!! - emit $ Comment "This should not have happened!" - emit $ Variable id - emit $ UnsafeRaw "\n" - -emitInt :: Integer -> CompilerState () -emitInt i = do - -- !!this should never happen!! - varCount <- getNewVar - emit $ Comment "This should not have happened!" - emit $ SetVariable (Ident (show varCount)) (Add I64 (VInteger i) (VInteger 0)) - -emitAdd :: Type -> Exp -> Exp -> CompilerState () -emitAdd t e1 e2 = do - v1 <- exprToValue e1 - v2 <- exprToValue e2 - v <- getNewVar - emit $ SetVariable (Ident $ show v) (Add (type2LlvmType t) v1 v2) - --- emitMul :: Exp -> Exp -> CompilerState () --- emitMul e1 e2 = do --- (v1,v2) <- binExprToValues e1 e2 --- increaseVarCount --- v <- gets variableCount --- emit $ SetVariable $ Ident $ show v --- emit $ Mul I64 v1 v2 - --- emitMod :: Exp -> Exp -> CompilerState () --- emitMod e1 e2 = do --- -- `let m a b = rem (abs $ b + a) b` --- (v1,v2) <- binExprToValues e1 e2 --- increaseVarCount --- vadd <- gets variableCount --- emit $ SetVariable $ Ident $ show vadd --- emit $ Add I64 v1 v2 --- --- increaseVarCount --- vabs <- gets variableCount --- emit $ SetVariable $ Ident $ show vabs --- emit $ Call I64 (Ident "llvm.abs.i64") --- [ (I64, VIdent (Ident $ show vadd)) --- , (I1, VInteger 1) --- ] --- increaseVarCount --- v <- gets variableCount --- emit $ SetVariable $ Ident $ show v --- emit $ Srem I64 (VIdent (Ident $ show vabs)) v2 - --- emitDiv :: Exp -> Exp -> CompilerState () --- emitDiv e1 e2 = do --- (v1,v2) <- binExprToValues e1 e2 --- increaseVarCount --- v <- gets variableCount --- emit $ SetVariable $ Ident $ show v --- emit $ Div I64 v1 v2 - --- emitSub :: Exp -> Exp -> CompilerState () --- emitSub e1 e2 = do --- (v1,v2) <- binExprToValues e1 e2 --- increaseVarCount --- v <- gets variableCount --- emit $ SetVariable $ Ident $ show v --- emit $ Sub I64 v1 v2 - -exprToValue :: Exp -> CompilerState LLVMValue -exprToValue = \case - EInt i -> pure $ VInteger i - - EId id@(name, t) -> do - funcs <- gets functions - case Map.lookup id funcs of - Just fi -> do - if numArgs fi == 0 - then do - vc <- getNewVar - emit $ SetVariable (Ident $ show vc) - (Call (type2LlvmType t) Global name []) - pure $ VIdent (Ident $ show vc) (type2LlvmType t) - else pure $ VFunction name Global (type2LlvmType t) - Nothing -> pure $ VIdent name (type2LlvmType t) - - e -> do - compileExp e - v <- getVarCount - pure $ VIdent (Ident $ show v) (getType e) - -type2LlvmType :: Type -> LLVMType -type2LlvmType = \case - TInt -> I64 - TFun t xs -> do - let (t', xs') = function2LLVMType xs [type2LlvmType t] - Function t' xs' - t -> CustomType $ Ident ("\"" ++ show t ++ "\"") - where - function2LLVMType :: Type -> [LLVMType] -> (LLVMType, [LLVMType]) - function2LLVMType (TFun t xs) s = function2LLVMType xs (type2LlvmType t : s) - function2LLVMType x s = (type2LlvmType x, s) - -getType :: Exp -> LLVMType -getType (EInt _) = I64 -getType (EAdd t _ _) = type2LlvmType t -getType (EId (_, t)) = type2LlvmType t -getType (EApp t _ _) = type2LlvmType t -getType (EAbs t _ _) = type2LlvmType t -getType (ELet _ e) = getType e - -valueGetType :: LLVMValue -> LLVMType -valueGetType (VInteger _) = I64 -valueGetType (VIdent _ t) = t -valueGetType (VConstant s) = Array (length s) I8 -valueGetType (VFunction _ _ t) = t +compile :: String -> Bool -> IO String +compile s addGc = optimize s >>= compileClang addGc diff --git a/src/Desugar/Desugar.hs b/src/Desugar/Desugar.hs new file mode 100644 index 0000000..550d7c3 --- /dev/null +++ b/src/Desugar/Desugar.hs @@ -0,0 +1,117 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} + +module Desugar.Desugar (desugar) where + +import Grammar.Abs + +{- + +The entire module should never have any catch all pattern matches as that +will disble warnings for when the grammar is expanded. + +-} + +desugar :: Program -> Program +desugar (Program defs) = Program (map desugarDef defs) + +desugarVarName :: VarName -> LIdent +desugarVarName (VSymbol (Symbol i)) = LIdent $ fixName i +desugarVarName (VIdent i) = i + +desugarDef :: Def -> Def +desugarDef = \case + DBind b -> DBind (desugarBind b) + DSig sig -> DSig (desugarSig sig) + DData d -> DData (desugarData d) + +desugarBind :: Bind -> Bind +desugarBind (BindS name args e) = Bind (desugarVarName name) args (desugarExp e) +desugarBind (Bind name args e) = Bind name args (desugarExp e) + +desugarSig :: Sig -> Sig +desugarSig (SigS ident typ) = Sig (desugarVarName ident) (desugarType typ) +desugarSig (Sig ident typ) = Sig ident (desugarType typ) + +desugarData :: Data -> Data +desugarData (Data typ injs) = Data (desugarType typ) (map desugarInj injs) + +desugarType :: Type -> Type +desugarType = \case + TIdent (UIdent "Int") -> TLit "Int" + TIdent (UIdent "Char") -> TLit "Char" + TIdent ident -> TData ident [] + TApp t1 t2 -> + let (name : tvars) = flatten t1 ++ [t2] + in case name of + TIdent ident -> TData ident (map desugarType tvars) + _ -> error "desugarType is not implemented correctly" + TLit l -> TLit l + TVar v -> TVar v + (TAll i t) -> TAll i (desugarType t) + TFun t1 t2 -> TFun (desugarType t1) (desugarType t2) + TEVar v -> TEVar v + TData ident typ -> TData ident (map desugarType typ) + where + flatten :: Type -> [Type] + flatten (TApp a b) = flatten a <> flatten b + flatten a = [a] + +desugarInj :: Inj -> Inj +desugarInj (Inj ident typ) = Inj ident (desugarType typ) + +desugarExp :: Exp -> Exp +desugarExp = \case + EApp e1 e2 -> EApp (desugarExp e1) (desugarExp e2) + EAdd e1 e2 -> EAdd (desugarExp e1) (desugarExp e2) + EAbs i e -> EAbs i (desugarExp e) + ELet b e -> ELet (desugarBind b) (desugarExp e) + ECase e br -> ECase (desugarExp e) (map desugarBranch br) + EAnn e t -> EAnn (desugarExp e) t + EVarS (VSymbol (Symbol symb)) -> EVar (LIdent $ fixName symb) + EVarS (VIdent (LIdent ident)) -> EVar $ LIdent $ fixName ident + EVar i -> EVar i + ELit l -> ELit l + EInj i -> EInj i + +desugarBranch :: Branch -> Branch +desugarBranch (Branch p e) = Branch (desugarPattern p) (desugarExp e) + +desugarPattern :: Pattern -> Pattern +desugarPattern = \case + PVar ident -> PVar ident + PLit lit -> PLit (desugarLit lit) + PCatch -> PCatch + PEnum ident -> PEnum ident + PInj ident patterns -> PInj ident (map desugarPattern patterns) + +desugarLit :: Lit -> Lit +desugarLit (LInt i) = LInt i +desugarLit (LChar c) = LChar c + +fixName :: String -> String +fixName = concatMap mapSymbols + where + mapSymbols :: Char -> String + mapSymbols c = case c of + '@' -> "$at$" + '#' -> "$octothorpe$" + '%' -> "$percent$" + '^' -> "$hat$" + '&' -> "$and$" + '*' -> "$star$" + '_' -> "$underscore$" + '-' -> "$minus$" + '+' -> "$plus$" + '=' -> "$equals$" + '|' -> "$pipe$" + '?' -> "$questionmark$" + '/' -> "$fslash$" + '<' -> "$langle$" + '>' -> "$rangle$" + ',' -> "$comma$" + 'β€’' -> "$bullet$" + ':' -> "$semicolon$" + '[' -> "$lbracket$" + ']' -> "$rbracket$" + c -> c : "" diff --git a/src/Interpreter.hs b/src/Interpreter.hs deleted file mode 100644 index 37d46a7..0000000 --- a/src/Interpreter.hs +++ /dev/null @@ -1,116 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedRecordDot #-} -{-# LANGUAGE OverloadedStrings #-} -module Interpreter where - -import Auxiliary (maybeToRightM) -import Control.Applicative (Applicative) -import Control.Monad.Except (Except, MonadError (throwError), - liftEither) -import Control.Monad.State (MonadState, StateT, evalStateT) -import Data.Either.Combinators (maybeToRight) -import Data.Map (Map) -import qualified Data.Map as Map -import Data.Maybe (maybe) -import Grammar.Abs -import Grammar.ErrM (Err) -import Grammar.Print (printTree) - -interpret :: Program -> Err Integer -interpret (Program scs) = do - main <- findMain scs - eval (initCxt scs) main >>= - \case - VClosure {} -> throwError "main evaluated to a function" - VInt i -> pure i - - -initCxt :: [Bind] -> Cxt -initCxt scs = - Cxt { env = mempty - , sig = foldr insert mempty $ map expandLambdas scs - } - where insert (Bind name _ rhs) = Map.insert name rhs - -expandLambdas :: Bind -> Bind -expandLambdas (Bind name parms rhs) = Bind name [] $ foldr EAbs rhs parms - -findMain :: [Bind] -> Err Exp -findMain [] = throwError "No main!" -findMain (sc:scs) = case sc of - Bind "main" _ rhs -> pure rhs - _ -> findMain scs - -data Val = VInt Integer - | VClosure Env Ident Exp - deriving (Show, Eq) - -type Env = Map Ident Val -type Sig = Map Ident Exp - -data Cxt = Cxt - { env :: Map Ident Val - , sig :: Map Ident Exp - } deriving (Show, Eq) - -eval :: Cxt -> Exp -> Err Val -eval cxt = \case - - -- ------------ x ∈ Ξ³ - -- Ξ³ ⊒ x ⇓ Ξ³(x) - - EId x -> do - case Map.lookup x cxt.env of - Just e -> pure e - Nothing -> - case Map.lookup x cxt.sig of - Just e -> eval (emptyEnv cxt) e - Nothing -> throwError ("Unbound variable: " ++ printTree x) - - -- --------- - -- Ξ³ ⊒ i ⇓ i - - EInt i -> pure $ VInt i - - -- Ξ³ ⊒ e ⇓ let Ξ΄ in Ξ»x. f - -- Ξ³ ⊒ e₁ ⇓ v - -- Ξ΄,x=v ⊒ f ⇓ v₁ - -- ------------------------------ - -- Ξ³ ⊒ e e₁ ⇓ v₁ - - EApp e e1 -> - eval cxt e >>= \case - VInt _ -> throwError "Not a function" - VClosure delta x f -> do - v <- eval cxt e1 - let cxt' = putEnv (Map.insert x v delta) cxt - eval cxt' f - - - -- - -- ----------------------------- - -- Ξ³ ⊒ Ξ»x. f ⇓ let Ξ³ in Ξ»x. f - - EAbs par e -> pure $ VClosure cxt.env par e - - - -- Ξ³ ⊒ e ⇓ v - -- Ξ³ ⊒ e₁ ⇓ v₁ - -- ------------------ - -- Ξ³ ⊒ e e₁ ⇓ v + v₁ - - EAdd e e1 -> do - v <- eval cxt e - v1 <- eval cxt e1 - case (v, v1) of - (VInt i, VInt i1) -> pure $ VInt (i + i1) - _ -> throwError "Can't add a function" - - ELet _ _ -> throwError "ELet pattern match should never occur!" - - -emptyEnv :: Cxt -> Cxt -emptyEnv cxt = cxt { env = mempty } - -putEnv :: Env -> Cxt -> Cxt -putEnv env cxt = cxt { env = env } diff --git a/src/LambdaLifter.hs b/src/LambdaLifter.hs index 015e7f3..5581814 100644 --- a/src/LambdaLifter.hs +++ b/src/LambdaLifter.hs @@ -1,138 +1,249 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE OverloadedStrings #-} -module LambdaLifter (lambdaLift, freeVars, abstract, rename, collectScs) where +module LambdaLifter where -import Auxiliary (snoc) -import Control.Applicative (Applicative (liftA2)) -import Control.Monad.State (MonadState (get, put), State, evalState) -import Data.Set (Set) -import qualified Data.Set as Set -import Prelude hiding (exp) -import Renamer -import TypeCheckerIr +import Auxiliary (onM, snoc) +import Control.Applicative (Applicative (liftA2)) +import Control.Monad.State (MonadState (get, put), State, + evalState) +import Data.Function (on) +import Data.List (delete, mapAccumL, (\\)) +import Prelude hiding (exp) +import TypeChecker.TypeCheckerIr -- | Lift lambdas and let expression into supercombinators. -- Three phases: --- @freeVars@ annotatss all the free variables. +-- @freeVars@ annotates all the free variables. -- @abstract@ converts lambdas into let expressions. -- @collectScs@ moves every non-constant let expression to a top-level function. +-- lambdaLift :: Program -> Program -lambdaLift = collectScs . abstract . freeVars - +lambdaLift (Program ds) = Program (datatypes ++ binds) + where + datatypes = flip filter ds $ \case DData _ -> True + _ -> False + binds = map DBind $ (collectScs . abstract . freeVars) [b | DBind b <- ds] -- | Annotate free variables -freeVars :: Program -> AnnProgram -freeVars (Program ds) = [ (n, xs, freeVarsExp (Set.fromList xs) e) - | Bind n xs e <- ds - ] +freeVars :: [Bind] -> [ABind] +freeVars binds = [ let ae = freeVarsExp [] e + ae' = ae { frees = ae.frees \\ xs } + in ABind n xs ae' + | Bind n xs e <- binds + ] -freeVarsExp :: Set Id -> Exp -> AnnExp -freeVarsExp localVars = \case - EId n | Set.member n localVars -> (Set.singleton n, AId n) - | otherwise -> (mempty, AId n) +freeVarsExp :: Frees -> ExpT -> Ann AExpT +freeVarsExp localVars (ae, t) = case ae of + EVar n | elem (n,t) localVars -> Ann { frees = [(n, t)] + , term = (AVar n, t) + } + | otherwise -> Ann { frees = [] + , term = (AVar n, t) + } - EInt i -> (mempty, AInt i) + EInj n -> Ann { frees = [], term = (AInj n, t) } - EApp t e1 e2 -> (Set.union (freeVarsOf e1') (freeVarsOf e2'), AApp t e1' e2') + ELit lit -> Ann { frees = [], term = (ALit lit, t) } + + EApp e1 e2 -> Ann { frees = annae1.frees <|| annae2.frees + , term = (AApp annae1 annae2, t) + } where - e1' = freeVarsExp localVars e1 - e2' = freeVarsExp localVars e2 + (annae1, annae2) = on (,) (freeVarsExp localVars) e1 e2 - EAdd t e1 e2 -> (Set.union (freeVarsOf e1') (freeVarsOf e2'), AAdd t e1' e2') + EAdd e1 e2 -> Ann { frees = annae1.frees <|| annae2.frees + , term = (AAdd annae1 annae2, t) + } where - e1' = freeVarsExp localVars e1 - e2' = freeVarsExp localVars e2 + (annae1, annae2) = on (,) (freeVarsExp localVars) e1 e2 - EAbs t par e -> (Set.delete par $ freeVarsOf e', AAbs t par e') + + EAbs x e -> Ann { frees = delete (x,t_x) $ annae.frees + , term = (AAbs x annae, t) } where - e' = freeVarsExp (Set.insert par localVars) e + annae = freeVarsExp (localVars <| (x,t_x)) e + t_x = case t of TFun t _ -> t + _ -> error "Impossible" -- Sum free variables present in bind and the expression - ELet (Bind name parms rhs) e -> (Set.union binders_frees e_free, ALet new_bind e') + -- let f x = x + y in f 5 + z β†’ frees: y, z + ELet bind@(Bind n _ _) e -> + Ann { frees = delete n annae.frees <|| annbind.frees + , term = (ALet annbind annae, t) + } where - binders_frees = Set.delete name $ freeVarsOf rhs' - e_free = Set.delete name $ freeVarsOf e' + annae = freeVarsExp (localVars <| n) e + annbind = freeVarsBind localVars bind - rhs' = freeVarsExp e_localVars rhs - new_bind = ABind name parms rhs' - - e' = freeVarsExp e_localVars e - e_localVars = Set.insert name localVars + ECase e branches -> + Ann { frees = foldl (<||) annae.frees (map frees annbranches) + , term = (ACase annae annbranches, t) + } + where + annae = freeVarsExp localVars e + annbranches = map (freeVarsBranch localVars) branches -freeVarsOf :: AnnExp -> Set Id -freeVarsOf = fst +freeVarsBind :: Frees -> Bind -> Ann ABind +freeVarsBind localVars (Bind name vars e) = + Ann { frees = annae.frees \\ vars + , term = ABind name vars annae + } + where + annae = freeVarsExp (localVars <|| vars) e + + +freeVarsBranch :: Frees -> Branch -> Ann ABranch +freeVarsBranch localVars (Branch pt e) = + Ann { frees = annae.frees \\ varsInPattern + , term = ABranch pt annae + } + where + annae = freeVarsExp localVars e + varsInPattern = go [] pt + where + go acc (p, t) = case p of + PVar n -> acc <| (n, t) + PInj _ ps -> foldl go acc ps + _ -> [] + -- AST annotated with free variables -type AnnProgram = [(Id, [Id], AnnExp)] -type AnnExp = (Set Id, AnnExp') +type Frees = [(Ident, Type)] -data ABind = ABind Id [Id] AnnExp deriving Show +data Ann a = Ann + { frees :: Frees + , term :: a + } deriving (Show, Eq) -data AnnExp' = AId Id - | AInt Integer - | ALet ABind AnnExp - | AApp Type AnnExp AnnExp - | AAdd Type AnnExp AnnExp - | AAbs Type Id AnnExp - deriving Show --- | Lift lambdas to let expression of the form @let sc = \v₁ x₁ -> e₁@. --- Free variables are @v₁ vβ‚‚ .. vβ‚™@ are bound. -abstract :: AnnProgram -> Program -abstract prog = Program $ evalState (mapM go prog) 0 +data ABind = ABind Id [Id] (Ann AExpT) deriving (Show, Eq) +data ABranch = ABranch (Pattern, Type) (Ann AExpT) deriving (Show, Eq) + +type AExpT = (AExp, Type) + +data AExp = AVar Ident + | AInj Ident + | ALit Lit + | ALet (Ann ABind) (Ann AExpT) + | AApp (Ann AExpT) (Ann AExpT) + | AAdd (Ann AExpT) (Ann AExpT) + | AAbs Ident (Ann AExpT) + | ACase (Ann AExpT) [Ann ABranch] + deriving (Show, Eq) + +abstract :: [ABind] -> [Bind] +abstract bs = evalState (mapM (abstractAnnBind . Ann []) bs) 0 + +abstractAnnBind :: Ann ABind -> State Int Bind +abstractAnnBind Ann { term = ABind name vars annae } = + Bind name (vars' <|| vars) <$> abstractAnnExp annae' where - go :: (Id, [Id], AnnExp) -> State Int Bind - go (name, parms, rhs) = Bind name (parms ++ parms1) <$> abstractExp rhs' + (annae', vars') = go [] annae where - (rhs', parms1) = flattenLambdasAnn rhs + go acc = \case + Ann { term = (AAbs x ae, TFun t _) } -> go (snoc (x, t) acc) ae + ae -> (ae, acc) +abstractAnnExp :: Ann AExpT -> State Int ExpT +abstractAnnExp Ann {frees, term = (annae, typ) } = case annae of + AVar n -> pure (EVar n, typ) + AInj n -> pure (EInj n, typ) + ALit lit -> pure (ELit lit, typ) + AApp annae1 annae2 -> (, typ) <$> onM EApp abstractAnnExp annae1 annae2 + AAdd annae1 annae2 -> (, typ) <$> onM EAdd abstractAnnExp annae1 annae2 --- | Flatten nested lambdas and collect the parameters --- @\x.\y.\z. ae β†’ (ae, [x,y,z])@ -flattenLambdasAnn :: AnnExp -> (AnnExp, [Id]) -flattenLambdasAnn ae = go (ae, []) - where - go :: (AnnExp, [Id]) -> (AnnExp, [Id]) - go ((free, e), acc) = - case e of - AAbs _ par (free1, e1) -> - go ((Set.delete par free1, e1), snoc par acc) - _ -> ((free, e), acc) - -abstractExp :: AnnExp -> State Int Exp -abstractExp (free, exp) = case exp of - AId n -> pure $ EId n - AInt i -> pure $ EInt i - AApp t e1 e2 -> liftA2 (EApp t) (abstractExp e1) (abstractExp e2) - AAdd t e1 e2 -> liftA2 (EAdd t) (abstractExp e1) (abstractExp e2) - ALet b e -> liftA2 ELet (go b) (abstractExp e) - where - go (ABind name parms rhs) = do - (rhs', parms1) <- flattenLambdas <$> skipLambdas abstractExp rhs - pure $ Bind name (parms ++ parms1) rhs' - - skipLambdas :: (AnnExp -> State Int Exp) -> AnnExp -> State Int Exp - skipLambdas f (free, ae) = case ae of - AAbs t par ae1 -> EAbs t par <$> skipLambdas f ae1 - _ -> f (free, ae) - - -- Lift lambda into let and bind free variables - AAbs t parm e -> do + -- \x. \y. x + y + z β‡’ let sc x y z = x + y + z in sc + AAbs x annae' -> do i <- nextNumber - rhs <- abstractExp e + rhs <- abstractAnnExp annae'' + let sc_name = Ident ("sc_" ++ show i) + e@(_, t) = foldl applyFree (EVar sc_name, typ) frees + pure (ELet (Bind (sc_name, typ) vars rhs) e ,t) - let sc_name = Ident ("sc_" ++ show i) - sc = ELet (Bind (sc_name, t) parms rhs) $ EId (sc_name, t) - - pure $ foldl (EApp TInt) sc $ map EId freeList where - freeList = Set.toList free - parms = snoc parm freeList + vars = frees <| (x, t_x) <|| ys + t_x = case typ of TFun t _ -> t + _ -> error "Impossible" + (annae'', ys) = go [] annae' + where + go acc = \case + Ann { term = (AAbs x ae, TFun t _) } -> go (snoc (x, t) acc) ae + ae -> (ae, acc) + + + applyFree :: (Exp' Type, Type) -> (Ident, Type) -> (Exp' Type, Type) + applyFree (e, t_e) (x, t_x) = (EApp (e, t_e) (EVar x, t_x), t_e') + where + t_e' = case t_e of TFun _ t -> t + _ -> error "Impossible" + + ACase annae' bs -> do + bs <- mapM go bs + e <- abstractAnnExp annae' + pure (ECase e bs, typ) + where + go Ann { term = ABranch p annae } = Branch p <$> abstractAnnExp annae + + ALet b annae' -> + (, typ) <$> liftA2 ELet (abstractAnnBind b) (abstractAnnExp annae') + + +-- | Collects supercombinators by lifting non-constant let expressions +collectScs :: [Bind] -> [Bind] +collectScs = concatMap collectFromRhs + where + collectFromRhs (Bind name parms rhs) = + let (rhs_scs, rhs') = collectScsExp rhs + in Bind name parms rhs' : rhs_scs + + +collectScsExp :: ExpT -> ([Bind], ExpT) +collectScsExp expT@(exp, typ) = case exp of + EVar _ -> ([], expT) + EInj _ -> ([], expT) + ELit _ -> ([], expT) + + EApp e1 e2 -> (scs1 ++ scs2, (EApp e1' e2', typ)) + where + (scs1, e1') = collectScsExp e1 + (scs2, e2') = collectScsExp e2 + + EAdd e1 e2 -> (scs1 ++ scs2, (EAdd e1' e2', typ)) + where + (scs1, e1') = collectScsExp e1 + (scs2, e2') = collectScsExp e2 + + EAbs par e -> (scs, (EAbs par e', typ)) + where + (scs, e') = collectScsExp e + + ECase e branches -> (scs ++ scs_e, (ECase e' branches', typ)) + where + (scs, branches') = mapAccumL f [] branches + (scs_e, e') = collectScsExp e + f acc b = (acc ++ acc', b') + where (acc', b') = collectScsBranch b + + -- Collect supercombinators from bind, the rhss, and the expression. + -- + -- > f = let sc x y = rhs in e + -- + ELet (Bind name parms rhs) e + | null parms -> (rhs_scs ++ et_scs, (ELet bind et', snd et')) + | otherwise -> (bind : rhs_scs ++ et_scs, et') + where + bind = Bind name parms rhs' + (rhs_scs, rhs') = collectScsExp rhs + (et_scs, et') = collectScsExp e + +collectScsBranch (Branch patt exp) = (scs, Branch patt exp') + where (scs, exp') = collectScsExp exp nextNumber :: State Int Int nextNumber = do @@ -140,51 +251,11 @@ nextNumber = do put $ succ i pure i --- | Collects supercombinators by lifting non-constant let expressions -collectScs :: Program -> Program -collectScs (Program scs) = Program $ concatMap collectFromRhs scs - where - collectFromRhs (Bind name parms rhs) = - let (rhs_scs, rhs') = collectScsExp rhs - in Bind name parms rhs' : rhs_scs +(<|) :: Eq a => [a] -> a -> [a] +xs <| x | elem x xs = xs + | otherwise = snoc x xs -collectScsExp :: Exp -> ([Bind], Exp) -collectScsExp = \case - EId n -> ([], EId n) - EInt i -> ([], EInt i) +(<||) :: Eq a => [a] -> [a] -> [a] +xs <|| ys = foldl (<|) xs ys - EApp t e1 e2 -> (scs1 ++ scs2, EApp t e1' e2') - where - (scs1, e1') = collectScsExp e1 - (scs2, e2') = collectScsExp e2 - - EAdd t e1 e2 -> (scs1 ++ scs2, EAdd t e1' e2') - where - (scs1, e1') = collectScsExp e1 - (scs2, e2') = collectScsExp e2 - - EAbs t par e -> (scs, EAbs t par e') - where - (scs, e') = collectScsExp e - - -- Collect supercombinators from bind, the rhss, and the expression. - -- - -- > f = let sc x y = rhs in e - -- - ELet (Bind name parms rhs) e -> if null parms - then ( rhs_scs ++ e_scs, ELet bind e') - else (bind : rhs_scs ++ e_scs, e') - where - bind = Bind name parms rhs' - (rhs_scs, rhs') = collectScsExp rhs - (e_scs, e') = collectScsExp e - - --- @\x.\y.\z. e β†’ (e, [x,y,z])@ -flattenLambdas :: Exp -> (Exp, [Id]) -flattenLambdas = go . (, []) - where - go (e, acc) = case e of - EAbs _ par e1 -> go (e1, snoc par acc) - _ -> (e, acc) diff --git a/src/LlvmIr.hs b/src/LlvmIr.hs deleted file mode 100644 index d340ddc..0000000 --- a/src/LlvmIr.hs +++ /dev/null @@ -1,204 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module LlvmIr ( - LLVMType (..), - LLVMIr (..), - llvmIrToString, - LLVMValue (..), - LLVMComp (..), - Visibility (..), -) where - -import Data.List (intercalate) -import TypeCheckerIr - --- | A datatype which represents some basic LLVM types -data LLVMType - = I1 - | I8 - | I32 - | I64 - | Ptr - | Ref LLVMType - | Function LLVMType [LLVMType] - | Array Int LLVMType - | CustomType Ident - -instance Show LLVMType where - show :: LLVMType -> String - show = \case - I1 -> "i1" - I8 -> "i8" - I32 -> "i32" - I64 -> "i64" - Ptr -> "ptr" - Ref ty -> show ty <> "*" - Function t xs -> show t <> " (" <> intercalate ", " (map show xs) <> ")*" - Array n ty -> concat ["[", show n, " x ", show ty, "]"] - CustomType (Ident ty) -> ty - -data LLVMComp - = LLEq - | LLNe - | LLUgt - | LLUge - | LLUlt - | LLUle - | LLSgt - | LLSge - | LLSlt - | LLSle -instance Show LLVMComp where - show :: LLVMComp -> String - show = \case - LLEq -> "eq" - LLNe -> "ne" - LLUgt -> "ugt" - LLUge -> "uge" - LLUlt -> "ult" - LLUle -> "ule" - LLSgt -> "sgt" - LLSge -> "sge" - LLSlt -> "slt" - LLSle -> "sle" - -data Visibility = Local | Global -instance Show Visibility where - show :: Visibility -> String - show Local = "%" - show Global = "@" - --- | Represents a LLVM "value", as in an integer, a register variable, --- or a string contstant -data LLVMValue - = VInteger Integer - | VIdent Ident LLVMType - | VConstant String - | VFunction Ident Visibility LLVMType - -instance Show LLVMValue where - show :: LLVMValue -> String - show v = case v of - VInteger i -> show i - VIdent (Ident n) _ -> "%" <> n - VFunction (Ident n) vis _ -> show vis <> n - VConstant s -> "c" <> show s - -type Params = [(Ident, LLVMType)] -type Args = [(LLVMType, LLVMValue)] - --- | A datatype which represents different instructions in LLVM -data LLVMIr - = Define LLVMType Ident Params - | DefineEnd - | Declare LLVMType Ident Params - | SetVariable Ident LLVMIr - | Variable Ident - | Add LLVMType LLVMValue LLVMValue - | Sub LLVMType LLVMValue LLVMValue - | Div LLVMType LLVMValue LLVMValue - | Mul LLVMType LLVMValue LLVMValue - | Srem LLVMType LLVMValue LLVMValue - | Icmp LLVMComp LLVMType LLVMValue LLVMValue - | Br Ident - | BrCond LLVMValue Ident Ident - | Label Ident - | Call LLVMType Visibility Ident Args - | Alloca LLVMType - | Store LLVMType Ident LLVMType Ident - | Bitcast LLVMType Ident LLVMType - | Ret LLVMType LLVMValue - | Comment String - | UnsafeRaw String -- This should generally be avoided, and proper - -- instructions should be used in its place - deriving (Show) - --- | Converts a list of LLVMIr instructions to a string -llvmIrToString :: [LLVMIr] -> String -llvmIrToString = go 0 - where - go :: Int -> [LLVMIr] -> String - go _ [] = mempty - go i (x : xs) = do - let (i', n) = case x of - Define{} -> (i + 1, 0) - DefineEnd -> (i - 1, 0) - _ -> (i, i) - insToString n x <> go i' xs - --- | Converts a LLVM inststruction to a String, allowing for printing etc. --- The integer represents the indentation -insToString :: Int -> LLVMIr -> String -insToString i l = - replicate i '\t' <> case l of - (Define t (Ident i) params) -> - concat - [ "define ", show t, " @", i - , "(", intercalate ", " (map (\(Ident y, x) -> unwords [show x, "%" <> y]) params) - , ") {\n" - ] - DefineEnd -> "}\n" - (Declare _t (Ident _i) _params) -> undefined - (SetVariable (Ident i) ir) -> concat ["%", i, " = ", insToString 0 ir] - (Add t v1 v2) -> - concat - [ "add ", show t, " ", show v1 - , ", ", show v2, "\n" - ] - (Sub t v1 v2) -> - concat - [ "sub ", show t, " ", show v1, ", " - , show v2, "\n" - ] - (Div t v1 v2) -> - concat - [ "sdiv ", show t, " ", show v1, ", " - , show v2, "\n" - ] - (Mul t v1 v2) -> - concat - [ "mul ", show t, " ", show v1 - , ", ", show v2, "\n" - ] - (Srem t v1 v2) -> - concat - [ "srem ", show t, " ", show v1, ", " - , show v2, "\n" - ] - (Call t vis (Ident i) arg) -> - concat - [ "call ", show t, " ", show vis, i, "(" - , intercalate ", " $ Prelude.map (\(x, y) -> show x <> " " <> show y) arg - , ")\n" - ] - (Alloca t) -> unwords ["alloca", show t, "\n"] - (Store t1 (Ident id1) t2 (Ident id2)) -> - concat - [ "store ", show t1, " %", id1 - , ", ", show t2 , " %", id2, "\n" - ] - (Bitcast t1 (Ident i) t2) -> - concat - [ "bitcast ", show t1, " %" - , i, " to ", show t2, "\n" - ] - (Icmp comp t v1 v2) -> - concat - [ "icmp ", show comp, " ", show t - , " ", show v1, ", ", show v2, "\n" - ] - (Ret t v) -> - concat - [ "ret ", show t, " " - , show v, "\n" - ] - (UnsafeRaw s) -> s - (Label (Ident s)) -> "\nlabel_" <> s <> ":\n" - (Br (Ident s)) -> "br label %label_" <> s <> "\n" - (BrCond val (Ident s1) (Ident s2)) -> - concat - [ "br i1 ", show val, ", ", "label %" - , "label_", s1, ", ", "label %", "label_", s2, "\n" - ] - (Comment s) -> "; " <> s <> "\n" - (Variable (Ident id)) -> "%" <> id diff --git a/src/Main.hs b/src/Main.hs index 1831428..b487222 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -1,97 +1,196 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} module Main where +import AnnForall (annotateForall) +import Codegen.Codegen (generateCode) import Compiler (compile) +import Control.Monad (when, (<=<)) +import Data.List.Extra (isSuffixOf) +import Data.Maybe (fromJust, isNothing) +import Desugar.Desugar (desugar) import GHC.IO.Handle.Text (hPutStrLn) import Grammar.ErrM (Err) +import Grammar.Layout (resolveLayout) import Grammar.Par (myLexer, pProgram) -import Grammar.Print (printTree) - --- import Interpreter (interpret) +import Grammar.Print (Print, printTree) import LambdaLifter (lambdaLift) -import Renamer (rename) +import Monomorphizer.Monomorphizer (monomorphize) +import OrderDefs (orderDefs) +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import System.Console.GetOpt ( + ArgDescr (NoArg, ReqArg), + ArgOrder (RequireOrder), + OptDescr (Option), + getOpt, + usageInfo, + ) +import System.Directory ( + createDirectory, + doesPathExist, + getDirectoryContents, + removeDirectoryRecursive, + setCurrentDirectory, + ) import System.Environment (getArgs) -import System.Exit (exitFailure, exitSuccess) +import System.Exit ( + ExitCode (ExitFailure), + exitFailure, + exitSuccess, + exitWith, + ) import System.IO (stderr) -import TypeChecker (typecheck) +import System.Process (spawnCommand, waitForProcess) +import TypeChecker.TypeChecker (TypeChecker (Bi, Hm), typecheck) main :: IO () -main = - getArgs >>= \case - [] -> print "Required file path missing" - (s : _) -> main' s +main = getArgs >>= parseArgs >>= uncurry main' -main' :: String -> IO () -main' s = do - file <- readFile s +parseArgs :: [String] -> IO (Options, String) +parseArgs argv = case getOpt RequireOrder flags argv of + (os, f : _, []) + | opts.help || isNothing opts.typechecker -> do + hPutStrLn stderr (usageInfo header flags) + exitSuccess + | otherwise -> pure (opts, f) + where + opts = foldr ($) initOpts os + (_, _, errs) -> do + hPutStrLn stderr (concat errs ++ usageInfo header flags) + exitWith (ExitFailure 1) + where + header = "Usage: language [--help] [-d|--debug] [-t|type-checker bi/hm] FILE \n" - printToErr "-- Parse Tree -- " - parsed <- fromSyntaxErr . pProgram $ myLexer file - printToErr $ printTree parsed +flags :: [OptDescr (Options -> Options)] +flags = + [ Option ['d'] ["debug"] (NoArg enableDebug) "Print debug messages." + , Option ['t'] ["type-checker"] (ReqArg chooseTypechecker "bi/hm") "Choose type checker. Possible options are bi and hm" + , Option ['m'] ["disable-gc"] (NoArg disableGC) "Disables the garbage collector and uses malloc instead." + , Option [] ["help"] (NoArg enableHelp) "Print this help message" + ] - printToErr "\n-- Renamer --" - let renamed = rename parsed - printToErr $ printTree renamed +initOpts :: Options +initOpts = + Options + { help = False + , debug = False + , gc = True + , typechecker = Nothing + } - printToErr "\n-- TypeChecker --" - typechecked <- fromTypeCheckerErr $ typecheck renamed - printToErr $ printTree typechecked +enableHelp :: Options -> Options +enableHelp opts = opts{help = True} - printToErr "\n-- Lambda Lifter --" - let lifted = lambdaLift typechecked - printToErr $ printTree lifted +enableDebug :: Options -> Options +enableDebug opts = opts{debug = True} - printToErr "\n -- Printing compiler output to stdout --" - compiled <- fromCompilerErr $ compile lifted - putStrLn compiled - writeFile "llvm.ll" compiled +disableGC :: Options -> Options +disableGC opts = opts{gc = False} - -- interpred <- fromInterpreterErr $ interpret lifted - -- putStrLn "\n-- interpret" - -- print interpred +chooseTypechecker :: String -> Options -> Options +chooseTypechecker s options = options{typechecker = tc} + where + tc = case s of + "hm" -> pure Hm + "bi" -> pure Bi + _ -> Nothing - exitSuccess +data Options = Options + { help :: Bool + , debug :: Bool + , gc :: Bool + , typechecker :: Maybe TypeChecker + } + +main' :: Options -> String -> IO () +main' opts s = + let + log :: (Print a, Show a) => a -> IO () + log = printToErr . if opts.debug then show else printTree + in + do + file <- readFile s + + printToErr "-- Parse Tree -- " + parsed <- fromErr . pProgram . resolveLayout True $ myLexer (file ++ prelude) + log parsed + + printToErr "-- Desugar --" + let desugared = desugar parsed + log desugared + + printToErr "\n-- Renamer --" + _ <- fromErr $ reportForall (fromJust opts.typechecker) desugared + renamed <- fromErr $ (rename <=< annotateForall) desugared + log renamed + + printToErr "\n-- TypeChecker --" + typechecked <- fromErr $ typecheck (fromJust opts.typechecker) (orderDefs renamed) + log typechecked + + printToErr "\n-- Lambda Lifter --" + let lifted = lambdaLift typechecked + log lifted + + printToErr "\n -- Monomorphizer --" + let monomorphized = monomorphize lifted + log monomorphized + + printToErr "\n -- Compiler --" + -- generatedCode <- fromErr $ generateCode monomorphized (gc opts) + generatedCode <- fromErr $ generateCode monomorphized False + + check <- doesPathExist "output" + when check (removeDirectoryRecursive "output") + createDirectory "output" + createDirectory "output/logs" + when opts.debug $ do + writeFile "output/llvm.ll" generatedCode + debugDotViz + + -- compile generatedCode (gc opts) + compile generatedCode False + printToErr "Compilation done!" + printToErr "\n-- Program output --" + print =<< spawnWait "./output/hello_world" + + exitSuccess + +debugDotViz :: IO () +debugDotViz = do + setCurrentDirectory "output" + spawnWait "opt -dot-cfg llvm.ll -disable-output" + content <- filter (isSuffixOf ".dot") <$> getDirectoryContents "." + let commands = (\p -> "dot " <> p <> " -Tpng -o" <> p <> ".png") <$> content + mapM_ spawnWait commands + setCurrentDirectory ".." + return () + +spawnWait :: String -> IO ExitCode +spawnWait s = spawnCommand s >>= waitForProcess printToErr :: String -> IO () printToErr = hPutStrLn stderr -fromCompilerErr :: Err a -> IO a -fromCompilerErr = - either - ( \err -> do - putStrLn "\nCOMPILER ERROR" - putStrLn err - exitFailure - ) - pure +fromErr :: Err a -> IO a +fromErr = either (\s -> printToErr s >> exitFailure) pure -fromSyntaxErr :: Err a -> IO a -fromSyntaxErr = - either - ( \err -> do - putStrLn "\nSYNTAX ERROR" - putStrLn err - exitFailure - ) - pure - -fromTypeCheckerErr :: Err a -> IO a -fromTypeCheckerErr = - either - ( \err -> do - putStrLn "\nTYPECHECKER ERROR" - putStrLn err - exitFailure - ) - pure - -fromInterpreterErr :: Err a -> IO a -fromInterpreterErr = - either - ( \err -> do - putStrLn "\nINTERPRETER ERROR" - putStrLn err - exitFailure - ) - pure +prelude :: String +prelude = + unlines + [ "\n" + , "data Bool where" + , " False : Bool" + , " True : Bool" + , -- The function body of lt is replaced during code gen. It exists here for type checking purposes. + "lt : Int -> Int -> Bool" + , "lt x y = case x of" + , " _ => True" + , " _ => False" + , "\n" + , -- The function body of - is replaced during code gen. It exists here for type checking purposes. + ".- : Int -> Int -> Int" + , ".- x y = 0" + , "\n" + ] diff --git a/src/Monomorphizer/DataTypeRemover.hs b/src/Monomorphizer/DataTypeRemover.hs new file mode 100644 index 0000000..e4caef0 --- /dev/null +++ b/src/Monomorphizer/DataTypeRemover.hs @@ -0,0 +1,60 @@ +module Monomorphizer.DataTypeRemover (removeDataTypes) where + +import Monomorphizer.MonomorphizerIr qualified as M2 +import Monomorphizer.MorbIr qualified as M1 +import TypeChecker.TypeCheckerIr (Ident (Ident)) + +removeDataTypes :: M1.Program -> M2.Program +removeDataTypes (M1.Program defs) = M2.Program (map pDef defs) + +pDef :: M1.Def -> M2.Def +pDef (M1.DBind b) = M2.DBind (pBind b) +pDef (M1.DData d) = M2.DData (pData d) + +pData :: M1.Data -> M2.Data +pData (M1.Data t cs) = M2.Data (pType t) (map pCons cs) + +pCons :: M1.Inj -> M2.Inj +pCons (M1.Inj ident t) = M2.Inj ident (pType t) + +pType :: M1.Type -> M2.Type +pType (M1.TLit ident) = M2.TLit ident +pType (M1.TFun t1 t2) = M2.TFun (pType t1) (pType t2) +pType (M1.TData (Ident "Bool") _) = M2.TLit (Ident "Bool") +pType d = M2.TLit (Ident (newName d)) -- This is the step + +newName :: M1.Type -> String +newName (M1.TLit (Ident str)) = str +newName (M1.TFun t1 t2) = newName t1 ++ newName t2 +newName (M1.TData (Ident str) args) = str ++ concatMap newName args + +pBind :: M1.Bind -> M2.Bind +pBind (M1.Bind id argIds expt) = M2.Bind (pId id) (map pId argIds) (pExpT expt) + +pId :: (Ident, M1.Type) -> (Ident, M2.Type) +pId (ident, t) = (ident, pType t) + +pExpT :: M1.ExpT -> M2.ExpT +pExpT (exp, t) = (pExp exp, pType t) + +pExp :: M1.Exp -> M2.Exp +pExp (M1.EVar ident) = M2.EVar ident +pExp (M1.ELit lit) = M2.ELit (pLit lit) +pExp (M1.ELet bind expt) = M2.ELet (pBind bind) (pExpT expt) +pExp (M1.EApp e1 e2) = M2.EApp (pExpT e1) (pExpT e2) +pExp (M1.EAdd e1 e2) = M2.EAdd (pExpT e1) (pExpT e2) +pExp (M1.ECase expT branches) = M2.ECase (pExpT expT) (map pBranch branches) + +pBranch :: M1.Branch -> M2.Branch +pBranch (M1.Branch (patt, t) expt) = M2.Branch (pPattern patt, pType t) (pExpT expt) + +pPattern :: M1.Pattern -> M2.Pattern +pPattern (M1.PVar id) = M2.PVar (pId id) +pPattern (M1.PLit (lit, t)) = M2.PLit (pLit lit, pType t) +pPattern (M1.PInj ident patts) = M2.PInj ident (map pPattern patts) +pPattern M1.PCatch = M2.PCatch +pPattern (M1.PEnum ident) = M2.PEnum ident + +pLit :: M1.Lit -> M2.Lit +pLit (M1.LInt v) = M2.LInt v +pLit (M1.LChar c) = M2.LChar c diff --git a/src/Monomorphizer/Monomorphizer.hs b/src/Monomorphizer/Monomorphizer.hs new file mode 100644 index 0000000..3a8bd9e --- /dev/null +++ b/src/Monomorphizer/Monomorphizer.hs @@ -0,0 +1,419 @@ +{-# LANGUAGE LambdaCase #-} + +{- | For now, converts polymorphic functions to concrete ones based on usage. +Assumes lambdas are lifted. + +This step of compilation is as follows: + +Split all function bindings into monomorphic and polymorphic binds. The +monomorphic bindings will be part of this compilation step. +Apply the following monomorphization function on all monomorphic binds, with +their type as an additional argument. + +The function that transforms Binds operates on both monomorphic and +polymorphic functions, creates a context in which all possible polymorphic types +are mapped to concrete types, created using the additional argument. +Expressions are then recursively processed. The type of these expressions +are changed to using the mapped generic types. The expected type provided +in the recursion is changed depending on the different nodes. + +When an external bind is encountered (with EId), it is checked whether it +exists in outputed binds or not. If it does, nothing further is evaluated. +If not, the bind transformer function is called on it with the +expected type in this context. The result of this computation (a monomorphic +bind) is added to the resulting set of binds. +-} +module Monomorphizer.Monomorphizer (monomorphize, morphExp, morphBind) where + +import Monomorphizer.DataTypeRemover (removeDataTypes) +import Monomorphizer.MonomorphizerIr qualified as O +import Monomorphizer.MorbIr qualified as M +import TypeChecker.TypeCheckerIr (Ident (Ident)) +import TypeChecker.TypeCheckerIr qualified as T + +import Control.Monad.Reader ( + MonadReader (ask, local), + Reader, + asks, + runReader, + ) +import Control.Monad.State ( + MonadState (get), + StateT (runStateT), + gets, + modify, + ) +import Data.Coerce (coerce) +import Data.Map qualified as Map +import Data.Maybe (catMaybes) +import Data.Set qualified as Set +import Grammar.Print (printTree) +import Debug.Trace (trace) + +{- | EnvM is the monad containing the read-only state as well as the +output state containing monomorphized functions and to-be monomorphized +data type declarations. +-} +newtype EnvM a = EnvM (StateT Output (Reader Env) a) + deriving (Functor, Applicative, Monad, MonadState Output, MonadReader Env) + +type Output = Map.Map Ident Outputted + +{- | Data structure describing outputted top-level information, that is +Binds, Polymorphic Data types (monomorphized in a later step) and +Marked bind, which means that it is in the process of monomorphization +and should not be monomorphized again. +-} +data Outputted = Marked | Complete M.Bind | Data M.Type T.Data deriving (Show) + +-- | Static environment. +data Env = Env + { input :: Map.Map Ident T.Bind + -- ^ All binds in the program. + , dataDefs :: Map.Map Ident T.Data + -- ^ All constructors mapped to their respective polymorphic data def + -- which includes all other constructors. + , polys :: Map.Map Ident M.Type + -- ^ Maps polymorphic identifiers with concrete types. + , locals :: Set.Set Ident + -- ^ Local variables. + } + +-- | Determines if the identifier describes a local variable in the given context. +localExists :: Ident -> EnvM Bool +localExists ident = asks (Set.member ident . locals) + +-- | Gets a polymorphic bind from an id. +getInputBind :: Ident -> EnvM (Maybe T.Bind) +getInputBind ident = asks (Map.lookup ident . input) + +-- | Add monomorphic function derived from a polymorphic one, to env. +addOutputBind :: M.Bind -> EnvM () +addOutputBind b@(M.Bind (ident, _) _ _) = modify (Map.insert ident (Complete b)) + +{- | Marks a global bind as being processed, meaning that when encountered again, +it should not be recursively processed. +-} +markBind :: Ident -> EnvM () +markBind ident = modify (Map.insert ident Marked) + +-- | Check if bind has been touched or not. +isBindMarked :: Ident -> EnvM Bool +isBindMarked ident = gets (Map.member ident) + +-- | Checks if constructor is outputted. +isConsMarked :: Ident -> EnvM Bool +isConsMarked ident = gets (Map.member ident) + +-- | Finds main bind. +getMain :: EnvM T.Bind +getMain = asks (\env -> case Map.lookup (T.Ident "main") (input env) of + Just mainBind -> mainBind + Nothing -> error "main not found in monomorphizer!" + ) + +{- | Makes a kv pair list of polymorphic to monomorphic mappings, throws runtime +error when encountering different structures between the two arguments. Debug: +First argument is the name of the bind. +-} +mapTypes :: Ident -> T.Type -> M.Type -> [(Ident, M.Type)] +mapTypes _ident (T.TLit _) (M.TLit _) = [] +mapTypes _ident (T.TVar (T.MkTVar i1)) tm = [(i1, tm)] +mapTypes ident (T.TFun pt1 pt2) (M.TFun mt1 mt2) = + mapTypes ident pt1 mt1 + ++ mapTypes ident pt2 mt2 +mapTypes ident (T.TData tIdent pTs) (M.TData mIdent mTs) = + if tIdent /= mIdent + then error "the data type names of monomorphic and polymorphic data types does not match" + else foldl (\xs (p, m) -> mapTypes ident p m ++ xs) [] (zip pTs mTs) +mapTypes ident t1 t2 = error $ "in bind: '" ++ printTree ident ++ "', " ++ + "structure of types not the same: '" ++ printTree t1 ++ "', '" ++ printTree t2 ++ "'" + +-- | Gets the mapped monomorphic type of a polymorphic type in the current context. +getMonoFromPoly :: T.Type -> EnvM M.Type +getMonoFromPoly t = do + env <- ask + return $ getMono (polys env) t + where + getMono :: Map.Map Ident M.Type -> T.Type -> M.Type + getMono polys t = case t of + (T.TLit ident) -> M.TLit (coerce ident) + (T.TFun t1 t2) -> M.TFun (getMono polys t1) (getMono polys t2) + (T.TVar (T.MkTVar ident)) -> case Map.lookup ident polys of + Just concrete -> concrete + Nothing -> M.TLit (Ident "void") + -- error $ "type not found! type: " ++ show ident ++ ", error in previous compilation steps" + (T.TData ident args) -> M.TData ident (map (getMono polys) args) + +{- | If ident not already in env's output, morphed bind to output +(and all referenced binds within this bind). +Returns the annotated bind name. +-} +morphBind :: M.Type -> T.Bind -> EnvM Ident +morphBind expectedType b@(T.Bind (ident, btype) args (exp, expt)) = do + -- The "new name" is used to find out if it is already marked or not. + let name' = newFuncName expectedType b + bindMarked <- isBindMarked (coerce name') + local + ( \env -> + env + { locals = Set.fromList (map fst args) + , polys = Map.fromList (mapTypes ident btype expectedType) + } + ) + $ do + -- Return with right name if already marked + if bindMarked + then return name' + else do + -- Mark so that this bind will not be processed in recursive or cyclic + -- function calls + markBind (coerce name') + expt' <- getMonoFromPoly expt + exp' <- morphExp expt' exp + -- Get monomorphic type sof args + args' <- mapM morphArg args + addOutputBind $ + M.Bind + (coerce name', expectedType) + args' + (exp', expt') + return name' + +-- | Monomorphizes arguments of a bind. +morphArg :: (Ident, T.Type) -> EnvM (Ident, M.Type) +morphArg (ident, t) = do + t' <- getMonoFromPoly t + return (ident, t') + +-- | Gets the data bind from the name of a constructor. +getInputData :: Ident -> EnvM (Maybe T.Data) +getInputData ident = do + env <- ask + return $ Map.lookup ident (dataDefs env) + +{- | Monomorphize a constructor using it's global name. Constructors may +appear as expressions in the tree, or as patterns in case-expressions. +'newIdent' has a unique name while 'ident' has a general name. +-} +morphCons :: M.Type -> Ident -> Ident -> EnvM () +morphCons expectedType ident newIdent = do + --trace ("Tjofras:" ++ show (newName expectedType ident)) $ return () + maybeD <- getInputData ident + case maybeD of + Nothing -> error $ "identifier '" ++ show ident ++ "' not found" + Just d -> do + modify (\output -> Map.insert newIdent (Data expectedType d) output) + +-- | Converts literals from input to output tree. +convertLit :: T.Lit -> M.Lit +convertLit (T.LInt v) = M.LInt v +convertLit (T.LChar v) = M.LChar v + +-- | Monomorphizes an expression, given an expected type. +morphExp :: M.Type -> T.Exp -> EnvM M.Exp +morphExp expectedType exp = case exp of + T.ELit lit -> return $ M.ELit (convertLit lit) + -- Constructor + T.EInj ident -> do + let ident' = newName (getDataType expectedType) ident + morphCons expectedType ident ident' + return $ M.EVar ident' + T.EApp (e1, _t1) (e2, t2) -> do + t2' <- getMonoFromPoly t2 + e2' <- morphExp t2' e2 + e1' <- morphExp (M.TFun t2' expectedType) e1 + return $ M.EApp (e1', M.TFun t2' expectedType) (e2', t2') + T.EAdd (e1, t1) (e2, t2) -> do + t1' <- getMonoFromPoly t1 + t2' <- getMonoFromPoly t2 + e1' <- morphExp t1' e1 + e2' <- morphExp t2' e2 + return $ M.EAdd (e1', expectedType) (e2', expectedType) + T.EAbs ident (exp, t) -> local (\env -> env{locals = Set.insert ident (locals env)}) $ do + t' <- getMonoFromPoly t + morphExp t' exp + T.ECase (exp, t) bs -> do + t' <- getMonoFromPoly t + exp' <- morphExp t' exp + bs' <- mapM morphBranch bs + return $ M.ECase (exp', t') (catMaybes bs') + -- Ideally constructors should be EInj, though this code handles them + -- as well. + T.EVar ident -> do + isLocal <- localExists ident + if isLocal + then do + return $ M.EVar (coerce ident) + else do + bind <- getInputBind ident + case bind of + Nothing -> error $ "unbound variable: '" ++ printTree ident ++ "'" + Just bind' -> do + -- New bind to process + newBindName <- morphBind expectedType bind' + return $ M.EVar (coerce newBindName) + T.ELet (T.Bind (identB, tB) args (expB, tExpB)) (exp, tExp) -> + if length args > 0 then error "only constants in lets allowed" + else do + tB' <- getMonoFromPoly tB + tExpB' <- getMonoFromPoly tExpB + tExp' <- getMonoFromPoly tExp + expB' <- morphExp tExpB' expB + exp' <- morphExp tExp' exp + return $ M.ELet (M.Bind (identB, tB') [] (expB', tExpB')) (exp', tExp') + +-- | Monomorphizes case-of branches. +morphBranch :: T.Branch -> EnvM (Maybe M.Branch) +morphBranch (T.Branch (p, pt) (e, et)) = do + pt' <- getMonoFromPoly pt + et' <- getMonoFromPoly et + env <- ask + maybeMorphedPattern <- morphPattern p pt' + case maybeMorphedPattern of + Nothing -> return Nothing + Just (p', newLocals) -> + local (const env { locals = Set.union (locals env) newLocals }) $ do + e' <- morphExp et' e + return $ Just (M.Branch (p', pt') (e', et')) + +morphPattern :: T.Pattern -> M.Type -> EnvM (Maybe (M.Pattern, Set.Set Ident)) +morphPattern p expectedType = case p of + T.PVar ident -> return $ Just (M.PVar (ident, expectedType), Set.singleton ident) + T.PLit lit -> return $ Just (M.PLit (convertLit lit, expectedType), Set.empty) + T.PCatch -> return $ Just (M.PCatch, Set.empty) + T.PEnum ident -> return $ Just (M.PEnum (newName expectedType ident), Set.empty) + T.PInj ident pts -> do let newIdent = newName expectedType ident + outEnv <- get + trace ("WOW: " ++ show (newName expectedType ident)) $ return () + trace ("WOW2: " ++ show (outEnv)) $ return () + isMarked <- isConsMarked newIdent + if isMarked + then do + trace ("WOW3") $ return () + ts' <- mapM (getMonoFromPoly . snd) pts + let pts' = zip (map fst pts) ts' + psSets <- mapM (uncurry morphPattern) pts' + let maybePsSets = sequence psSets + case maybePsSets of + Nothing -> return Nothing + Just psSets' -> return $ Just + (M.PInj newIdent (map fst psSets'), Set.unions $ map snd psSets') + else return Nothing + +-- | Creates a new identifier for a function with an assigned type. +newFuncName :: M.Type -> T.Bind -> Ident +newFuncName t (T.Bind (ident@(Ident bindName), _) _ _) = + if bindName == "main" + then Ident bindName + else newName t ident + +newName :: M.Type -> Ident -> Ident +newName t (Ident str) = Ident $ str ++ "$" ++ newName' t + where + newName' :: M.Type -> String + newName' (M.TLit (Ident str)) = str + newName' (M.TFun t1 t2) = newName' t1 ++ "_" ++ newName' t2 + newName' (M.TData (Ident str) ts) = str ++ foldl (\s t -> s ++ "." ++ newName' t) "" ts + +-- | Monomorphization step. +monomorphize :: T.Program -> O.Program +monomorphize (T.Program defs) = + removeDataTypes $ + M.Program + ( getDefsFromOutput + (runEnvM Map.empty (createEnv defs) monomorphize') + ) + where + monomorphize' :: EnvM () + monomorphize' = do + main <- getMain + morphBind (M.TLit $ Ident "Int") main + return () + +-- | Runs and gives the output binds. +runEnvM :: Output -> Env -> EnvM () -> Output +runEnvM o env (EnvM stateM) = snd $ runReader (runStateT stateM o) env + +-- | Creates the environment based on the input binds. +createEnv :: [T.Def] -> Env +createEnv defs = + Env + { input = Map.fromList bindPairs + , dataDefs = Map.fromList dataPairs + , polys = Map.empty + , locals = Set.empty + } + where + bindPairs = (map (\b -> (getBindName b, b)) . getBindsFromDefs) defs + dataPairs :: [(Ident, T.Data)] + dataPairs = (foldl (\acc d@(T.Data _ cs) -> map ((,d) . getConsName) cs ++ acc) [] . getDataFromDefs) defs + +-- | Gets a top-lefel function name. +getBindName :: T.Bind -> Ident +getBindName (T.Bind (ident, _) _ _) = ident + +-- Helper functions +-- Gets custom data declarations form defs. +getDataFromDefs :: [T.Def] -> [T.Data] +getDataFromDefs = + foldl + ( \bs -> \case + T.DBind _ -> bs + T.DData d -> d : bs + ) + [] + +getConsName :: T.Inj -> Ident +getConsName (T.Inj ident _) = ident + +getBindsFromDefs :: [T.Def] -> [T.Bind] +getBindsFromDefs = + foldl + ( \bs -> \case + T.DBind b -> b : bs + T.DData _ -> bs + ) + [] + +getDefsFromOutput :: Output -> [M.Def] +getDefsFromOutput o = + map M.DBind binds + ++ (map (M.DData . snd) . Map.toList) (createNewData dataInput Map.empty) + where + (binds, dataInput) = splitBindsAndData o + +-- | Splits the output into binds and data declaration components (used in createNewData) +splitBindsAndData :: Output -> ([M.Bind], [(Ident, M.Type, T.Data)]) +splitBindsAndData output = + foldl + ( \(oBinds, oData) (ident, o) -> case o of + Marked -> error "internal bug in monomorphizer" + Complete b -> (b : oBinds, oData) + Data t d -> (oBinds, (ident, t, d) : oData) + ) + ([], []) + (Map.toList output) + +-- | Converts all found constructors to monomorphic data declarations. +createNewData :: [(Ident, M.Type, T.Data)] -> Map.Map Ident M.Data -> Map.Map Ident M.Data +createNewData [] o = o +createNewData ((consIdent, consType, polyData) : input) o = + createNewData input $ + Map.insertWith + (\_ (M.Data _ cs) -> M.Data newDataType (newCons : cs)) + newDataName + (M.Data newDataType [newCons]) + o + where + T.Data (T.TData polyDataIdent _) _ = polyData + newDataType = getDataType consType + newDataName = newName newDataType polyDataIdent + newCons = M.Inj consIdent consType + +-- | Gets the Data Type of a constructor type (a -> Just a becomes Just a). +getDataType :: M.Type -> M.Type +getDataType (M.TFun _t1 t2) = getDataType t2 +getDataType tData@(M.TData _ _) = tData +getDataType _ = error "???" + diff --git a/src/Monomorphizer/MonomorphizerIr.hs b/src/Monomorphizer/MonomorphizerIr.hs new file mode 100644 index 0000000..052cdc1 --- /dev/null +++ b/src/Monomorphizer/MonomorphizerIr.hs @@ -0,0 +1,182 @@ +{-# LANGUAGE LambdaCase #-} + +module Monomorphizer.MonomorphizerIr (module Monomorphizer.MonomorphizerIr) where + +import Grammar.Print +import TypeChecker.TypeCheckerIr qualified as TIR (Ident (..)) + +type Id = (TIR.Ident, Type) + +newtype Program = Program [Def] + deriving (Show, Ord, Eq) + +data Def = DBind Bind | DData Data + deriving (Show, Ord, Eq) + +data Data = Data Type [Inj] + deriving (Show, Ord, Eq) + +data Bind = Bind Id [Id] ExpT + deriving (Show, Ord, Eq) + +data Exp + = EVar TIR.Ident + | ELit Lit + | ELet Bind ExpT + | EApp ExpT ExpT + | EAdd ExpT ExpT + | ECase ExpT [Branch] + deriving (Show, Ord, Eq) + +data Pattern + = PVar Id + | PLit (Lit, Type) + | PInj TIR.Ident [Pattern] + | PCatch + | PEnum TIR.Ident + deriving (Eq, Ord, Show) + +data Branch = Branch (Pattern, Type) ExpT + deriving (Eq, Ord, Show) + +type ExpT = (Exp, Type) + +data Inj = Inj TIR.Ident Type + deriving (Show, Ord, Eq) + +data Lit + = LInt Integer + | LChar Char + deriving (Show, Ord, Eq) + +data Type = TLit TIR.Ident | TFun Type Type + deriving (Show, Ord, Eq) + +flattenType :: Type -> [Type] +flattenType (TFun t1 t2) = t1 : flattenType t2 +flattenType x = [x] + +instance Print Program where + prt i (Program sc) = prPrec i 0 $ prt 0 sc + +instance Print (Bind) where + prt i (Bind sig@(name, _) parms rhs) = + prPrec i 0 $ + concatD + [ prtSig sig + , prt 0 name + , prtIdPs 0 parms + , doc $ showString "=" + , prt 0 rhs + ] + +prtSig :: Id -> Doc +prtSig (name, t) = + concatD + [ prt 0 name + , doc $ showString ":" + , prt 0 t + , doc $ showString ";" + ] + +instance Print (ExpT) where + prt i (e, t) = + concatD + [ doc $ showString "(" + , prt i e + , doc $ showString "," + , prt i t + , doc $ showString ")" + ] + +instance Print [Bind] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +prtIdPs :: Int -> [Id] -> Doc +prtIdPs i = prPrec i 0 . concatD . map (prt i) + +instance Print Exp where + prt i = \case + EVar name -> prPrec i 3 $ prt 0 name + ELit lit -> prPrec i 3 $ prt 0 lit + ELet b e -> + prPrec i 3 $ + concatD + [ doc $ showString "let" + , prt 0 b + , doc $ showString "in" + , prt 0 e + ] + EApp e1 e2 -> + prPrec i 2 $ + concatD + [ prt 2 e1 + , prt 3 e2 + ] + EAdd e1 e2 -> + prPrec i 1 $ + concatD + [ prt 1 e1 + , doc $ showString "+" + , prt 2 e2 + ] + ECase e branches -> + prPrec i 0 $ + concatD + [ doc $ showString "case" + , prt 0 e + , doc $ showString "of" + , doc $ showString "{" + , prt 0 branches + , doc $ showString "}" + ] + +instance Print Branch where + prt i (Branch (pattern_, t) exp) = prPrec i 0 (concatD [doc (showString "("), prt 0 pattern_, doc (showString " : "), prt 0 t, doc (showString ")"), doc (showString "=>"), prt 0 exp]) + +instance Print [Branch] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print Def where + prt i = \case + DBind bind -> prPrec i 0 (concatD [prt 0 bind]) + DData data_ -> prPrec i 0 (concatD [prt 0 data_]) + +instance Print Data where + prt i = \case + Data type_ injs -> prPrec i 0 (concatD [doc (showString "data"), prt 0 type_, doc (showString "where"), doc (showString "{"), prt 0 injs, doc (showString "}")]) + +instance Print Inj where + prt i = \case + Inj uident type_ -> prPrec i 0 (concatD [prt 0 uident, doc (showString ":"), prt 0 type_]) + +instance Print Pattern where + prt i = \case + PVar name -> prPrec i 1 (concatD [prt 0 name]) + PLit (lit, _) -> prPrec i 1 (concatD [prt 0 lit]) + PCatch -> prPrec i 1 (concatD [doc (showString "_")]) + PEnum name -> prPrec i 1 (concatD [prt 0 name]) + PInj uident patterns -> prPrec i 0 (concatD [prt 0 uident, prt 1 patterns]) + +instance Print [Def] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print [Type] where + prt _ [] = concatD [] + prt _ (x : xs) = concatD [prt 0 x, doc (showString " "), prt 0 xs] + +instance Print Type where + prt i = \case + TLit uident -> prPrec i 1 (concatD [prt 0 uident]) + TFun type_1 type_2 -> prPrec i 0 (concatD [prt 1 type_1, doc (showString "->"), prt 0 type_2]) + +instance Print Lit where + prt i = \case + LInt int -> prt i int + LChar char -> prt i char diff --git a/src/Monomorphizer/MorbIr.hs b/src/Monomorphizer/MorbIr.hs new file mode 100644 index 0000000..3e5db6b --- /dev/null +++ b/src/Monomorphizer/MorbIr.hs @@ -0,0 +1,184 @@ +{-# LANGUAGE LambdaCase #-} +module Monomorphizer.MorbIr where + +import Grammar.Print +import TypeChecker.TypeCheckerIr qualified as TIR (Ident (..)) + +type Id = (TIR.Ident, Type) + +newtype Program = Program [Def] + deriving (Show, Ord, Eq) + +data Def = DBind Bind | DData Data + deriving (Show, Ord, Eq) + +data Data = Data Type [Inj] + deriving (Show, Ord, Eq) + +data Bind = Bind Id [Id] ExpT + deriving (Show, Ord, Eq) + +data Exp + = EVar TIR.Ident + | ELit Lit + | ELet Bind ExpT + | EApp ExpT ExpT + | EAdd ExpT ExpT + | ECase ExpT [Branch] + deriving (Show, Ord, Eq) + +data Pattern + = PVar Id + | PLit (Lit, Type) + | PInj TIR.Ident [Pattern] + | PCatch + | PEnum TIR.Ident + deriving (Eq, Ord, Show) + +data Branch = Branch (Pattern, Type) ExpT + deriving (Eq, Ord, Show) + +type ExpT = (Exp, Type) + +data Inj = Inj TIR.Ident Type + deriving (Show, Ord, Eq) + +data Lit + = LInt Integer + | LChar Char + deriving (Show, Ord, Eq) + +data Type = TLit TIR.Ident | TFun Type Type | TData TIR.Ident [Type] + + deriving (Show, Ord, Eq) + +flattenType :: Type -> [Type] +flattenType (TFun t1 t2) = t1 : flattenType t2 +flattenType x = [x] + +instance Print Program where + prt i (Program sc) = prPrec i 0 $ prt 0 sc + +instance Print (Bind) where + prt i (Bind sig@(name, _) parms rhs) = + prPrec i 0 $ + concatD + [ prtSig sig + , prt 0 name + , prtIdPs 0 parms + , doc $ showString "=" + , prt 0 rhs + ] + +prtSig :: Id -> Doc +prtSig (name, t) = + concatD + [ prt 0 name + , doc $ showString ":" + , prt 0 t + , doc $ showString ";" + ] + +instance Print (ExpT) where + prt i (e, t) = + concatD + [ doc $ showString "(" + , prt i e + , doc $ showString "," + , prt i t + , doc $ showString ")" + ] + +instance Print [Bind] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +prtIdPs :: Int -> [Id] -> Doc +prtIdPs i = prPrec i 0 . concatD . map (prt i) + +instance Print Exp where + prt i = \case + EVar name -> prPrec i 3 $ prt 0 name + ELit lit -> prPrec i 3 $ prt 0 lit + ELet b e -> + prPrec i 3 $ + concatD + [ doc $ showString "let" + , prt 0 b + , doc $ showString "in" + , prt 0 e + ] + EApp e1 e2 -> + prPrec i 2 $ + concatD + [ prt 2 e1 + , prt 3 e2 + ] + EAdd e1 e2 -> + prPrec i 1 $ + concatD + [ prt 1 e1 + , doc $ showString "+" + , prt 2 e2 + ] + ECase e branches -> + prPrec i 0 $ + concatD + [ doc $ showString "case" + , prt 0 e + , doc $ showString "of" + , doc $ showString "{" + , prt 0 branches + , doc $ showString "}" + ] + +instance Print Branch where + prt i (Branch (pattern_, t) exp) = prPrec i 0 (concatD [doc (showString "("), prt 0 pattern_, doc (showString " : "), prt 0 t, doc (showString ")"), doc (showString "=>"), prt 0 exp]) + +instance Print [Branch] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print Def where + prt i = \case + DBind bind -> prPrec i 0 (concatD [prt 0 bind]) + DData data_ -> prPrec i 0 (concatD [prt 0 data_]) + +instance Print Data where + prt i = \case + Data type_ injs -> prPrec i 0 (concatD [doc (showString "data"), prt 0 type_, doc (showString "where"), doc (showString "{"), prt 0 injs, doc (showString "}")]) + +instance Print Inj where + prt i = \case + Inj uident type_ -> prPrec i 0 (concatD [prt 0 uident, doc (showString ":"), prt 0 type_]) + +instance Print Pattern where + prt i = \case + PVar name -> prPrec i 1 (concatD [prt 0 name]) + PLit (lit, _) -> prPrec i 1 (concatD [prt 0 lit]) + PCatch -> prPrec i 1 (concatD [doc (showString "_")]) + PEnum name -> prPrec i 1 (concatD [prt 0 name]) + PInj uident patterns -> prPrec i 0 (concatD [prt 0 uident, prt 1 patterns]) + +instance Print [Def] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print [Type] where + prt _ [] = concatD [] + prt _ (x : xs) = concatD [prt 0 x, doc (showString " "), prt 0 xs] + +instance Print Type where + prt i = \case + TLit uident -> prPrec i 1 (concatD [prt 0 uident]) + TFun type_1 type_2 -> prPrec i 0 (concatD [prt 1 type_1, doc (showString "->"), prt 0 type_2]) + TData uident types -> prPrec i 1 (concatD [prt 0 uident, doc (showString "("), prt 0 types, doc (showString ")")]) + +instance Print Lit where + prt i = \case + LInt int -> prt i int + LChar char -> prt i char + diff --git a/src/OrderDefs.hs b/src/OrderDefs.hs new file mode 100644 index 0000000..079512b --- /dev/null +++ b/src/OrderDefs.hs @@ -0,0 +1,43 @@ +{-# LANGUAGE LambdaCase #-} + +module OrderDefs where + +import Control.Monad.State (State, execState, get, modify, when) +import Data.Function (on) +import Data.List (partition, sortBy) +import Data.Set (Set) +import qualified Data.Set as Set +import Grammar.Abs + +orderDefs :: Program -> Program +orderDefs (Program defs) = + Program $ not_binds ++ map DBind (has_sig ++ orderBinds no_sig) + + where + (has_sig, no_sig) = partition (\(Bind n _ _) -> elem n sig_names) + [ b | DBind b <- defs] + sig_names = [ n | DSig (Sig n _) <- defs ] + not_binds = flip filter defs $ \case DBind _ -> False + _ -> True + +orderBinds :: [Bind] -> [Bind] +orderBinds binds = sortBy (on compare countUniqueCalls) binds + where + bind_names = [ n | Bind n _ _ <- binds] + + countUniqueCalls :: Bind -> Int + countUniqueCalls (Bind n _ e) = + Set.size $ execState (go e) (Set.singleton n) + where + go :: Exp -> State (Set LIdent) () + go exp = get >>= \called -> case exp of + EVar x -> when (Set.notMember x called && elem x bind_names) $ + modify (Set.insert x) + EApp e1 e2 -> on (>>) go e1 e2 + EAdd e1 e2 -> on (>>) go e1 e2 + ELet (Bind _ _ e) e' -> on (>>) go e e' + EAbs _ e -> go e + ECase e bs -> go e >> mapM_ (\(Branch _ e) -> go e) bs + EAnn e _ -> go e + EInj _ -> pure () + ELit _ -> pure () diff --git a/src/Renamer.hs b/src/Renamer.hs deleted file mode 100644 index b284e92..0000000 --- a/src/Renamer.hs +++ /dev/null @@ -1,84 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module Renamer (module Renamer) where - -import Auxiliary (mapAccumM) -import Control.Monad.State (MonadState, State, evalState, gets, - modify) -import Data.Map (Map) -import qualified Data.Map as Map -import Data.Maybe (fromMaybe) -import Data.Tuple.Extra (dupe) -import Grammar.Abs - - --- | Rename all variables and local binds -rename :: Program -> Program -rename (Program bs) = Program $ evalState (runRn $ mapM (renameSc initNames) bs) 0 - where - initNames = Map.fromList $ map (\(Bind name _ _ _ _) -> dupe name) bs - renameSc :: Names -> Bind -> Rn Bind - renameSc old_names (Bind name t _ parms rhs) = do - (new_names, parms') <- newNames old_names parms - rhs' <- snd <$> renameExp new_names rhs - pure $ Bind name t name parms' rhs' - - --- | Rename monad. State holds the number of renamed names. -newtype Rn a = Rn { runRn :: State Int a } - deriving (Functor, Applicative, Monad, MonadState Int) - --- | Maps old to new name -type Names = Map Ident Ident - -renameLocalBind :: Names -> Bind -> Rn (Names, Bind) -renameLocalBind old_names (Bind name t _ parms rhs) = do - (new_names, name') <- newName old_names name - (new_names', parms') <- newNames new_names parms - (new_names'', rhs') <- renameExp new_names' rhs - pure (new_names'', Bind name' t name' parms' rhs') - -renameExp :: Names -> Exp -> Rn (Names, Exp) -renameExp old_names = \case - EId n -> pure (old_names, EId . fromMaybe n $ Map.lookup n old_names) - - EInt i1 -> pure (old_names, EInt i1) - - EApp e1 e2 -> do - (env1, e1') <- renameExp old_names e1 - (env2, e2') <- renameExp old_names e2 - pure (Map.union env1 env2, EApp e1' e2') - - EAdd e1 e2 -> do - (env1, e1') <- renameExp old_names e1 - (env2, e2') <- renameExp old_names e2 - pure (Map.union env1 env2, EAdd e1' e2') - - ELet b e -> do - (new_names, b) <- renameLocalBind old_names b - (new_names', e') <- renameExp new_names e - pure (new_names', ELet b e') - - EAbs par t e -> do - (new_names, par') <- newName old_names par - (new_names', e') <- renameExp new_names e - pure (new_names', EAbs par' t e') - - EAnn e t -> do - (new_names, e') <- renameExp old_names e - pure (new_names, EAnn e' t) - --- | Create a new name and add it to name environment. -newName :: Names -> Ident -> Rn (Names, Ident) -newName env old_name = do - new_name <- makeName old_name - pure (Map.insert old_name new_name env, new_name) - --- | Create multiple names and add them to the name environment -newNames :: Names -> [Ident] -> Rn (Names, [Ident]) -newNames = mapAccumM newName - --- | Annotate name with number and increment the number @prefix β‡’ prefix_number@. -makeName :: Ident -> Rn Ident -makeName (Ident prefix) = gets (\i -> Ident $ prefix ++ "_" ++ show i) <* modify succ - diff --git a/src/Renamer/Renamer.hs b/src/Renamer/Renamer.hs new file mode 100644 index 0000000..1eee3f0 --- /dev/null +++ b/src/Renamer/Renamer.hs @@ -0,0 +1,112 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} + +module Renamer.Renamer (rename) where + +import Auxiliary (maybeToRightM, onM, partitionDefs) +import Control.Applicative (liftA2) +import Control.Monad.Except (ExceptT, MonadError, runExceptT) +import Control.Monad.State (MonadState, State, evalState, gets, + modify) +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Tuple.Extra (dupe) +import Grammar.Abs +import Grammar.ErrM (Err) +import Grammar.Print (printTree) + +-- | Rename all variables and local binds +rename :: Program -> Err Program +rename (Program defs) = rename' $ do + ds' <- mapM (fmap DData . rnData) ds + ss' <- mapM (fmap DSig . rnSig) ss + bs' <- mapM (fmap DBind . rnTopBind) bs + pure $ Program (ds' ++ ss' ++ bs') + where + (ds, ss, bs) = partitionDefs defs + rename' = flip evalState initCxt + . runExceptT + . runRn + initCxt = Cxt + { counter = 0 + , names = Map.fromList $ [ dupe n | Sig n _ <- ss ] + ++ [ dupe n | Bind n _ _ <- bs ] + } +rnData :: Data -> Rn Data +rnData (Data typ injs) = liftA2 Data (rnType typ) (mapM rnInj injs) + where + rnInj (Inj name t) = Inj name <$> rnType t + +rnSig :: Sig -> Rn Sig +rnSig (Sig name typ) = liftA2 Sig (getName name) (rnType typ) + +rnType :: Type -> Rn Type +rnType = \case + TVar (MkTVar name) -> TVar . MkTVar <$> getName name + TData name ts -> TData name <$> localNames (mapM rnType ts) + TFun t1 t2 -> onM TFun (localNames . rnType) t1 t2 + TAll (MkTVar name) t -> liftA2 (TAll . MkTVar) (newName name) (rnType t) + typ -> pure typ + +rnTopBind :: Bind -> Rn Bind +rnTopBind = rnBind' False + +rnLocalBind :: Bind -> Rn Bind +rnLocalBind = rnBind' True + +rnBind' :: Bool -> Bind -> Rn Bind +rnBind' isLocal (Bind name vars rhs) = do + name' <- if isLocal then newName name else getName name + (vars', rhs') <- localNames $ liftA2 (,) (mapM newName vars) (rnExp rhs) + pure (Bind name' vars' rhs') + +rnExp :: Exp -> Rn Exp +rnExp = \case + EVar x -> EVar <$> getName x + EInj x -> pure (EInj x) + ELit lit -> pure (ELit lit) + EApp e1 e2 -> onM EApp (localNames . rnExp) e1 e2 + EAdd e1 e2 -> onM EAdd (localNames . rnExp) e1 e2 + ELet bind e -> liftA2 ELet (rnLocalBind bind) (rnExp e) + EAbs x e -> liftA2 EAbs (newName x) (rnExp e) + EAnn e t -> liftA2 EAnn (rnExp e) (rnType t) + ECase e bs -> liftA2 ECase (rnExp e) (mapM (localNames . rnBranch) bs) + +rnBranch :: Branch -> Rn Branch +rnBranch (Branch p e) = liftA2 Branch (rnPattern p) (rnExp e) + +rnPattern :: Pattern -> Rn Pattern +rnPattern = \case + PVar x -> PVar <$> newName x + PLit lit -> pure (PLit lit) + PCatch -> pure PCatch + PEnum name -> pure (PEnum name) + PInj name ps -> PInj name <$> mapM rnPattern ps + +data Cxt = Cxt + { counter :: Int + , names :: Map LIdent LIdent + } + +-- | Rename monad. State holds the number of renamed names. +newtype Rn a = Rn {runRn :: ExceptT String (State Cxt) a} + deriving (Functor, Applicative, Monad, MonadState Cxt, MonadError String) + +getName :: LIdent -> Rn LIdent +getName name = maybeToRightM err =<< gets (Map.lookup name . names) + where err = "Can't find new name " ++ printTree name + +newName :: LIdent -> Rn LIdent +newName name = do + name' <- gets (mk name . counter) + modify $ \cxt -> cxt { counter = succ cxt.counter + , names = Map.insert name name' cxt.names + } + pure name' + where + mk (LIdent name) i = LIdent ("$" ++ show i ++ name) + +localNames :: MonadState Cxt m => m b -> m b +localNames m = do + old_names <- gets names + m <* modify ( \cxt' -> cxt' { names = old_names }) diff --git a/src/ReportForall.hs b/src/ReportForall.hs new file mode 100644 index 0000000..8b5e9db --- /dev/null +++ b/src/ReportForall.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE LambdaCase #-} + +module ReportForall (reportForall) where + +import Auxiliary (partitionDefs) +import Control.Monad (unless, void, when) +import Control.Monad.Except (MonadError (throwError)) +import Data.Either.Combinators (mapRight) +import Data.Foldable (foldlM) +import Data.Function (on) +import Data.List (delete) +import Grammar.Abs +import Grammar.ErrM (Err) +import TypeChecker.TypeChecker (TypeChecker (Bi, Hm)) + +reportForall :: TypeChecker -> Program -> Err () +reportForall tc p = do + when (tc == Hm) $ rpProgram rpaType p + rpProgram rpuType p + +rpuType :: Type -> Err () +rpuType typ = do + tvars <- go [] typ + unless (null tvars) $ throwError "Unused forall" + where + go tvars = \case + TAll tvar t + | tvar `elem` tvars -> throwError "Unused forall" + | otherwise -> go (tvar : tvars) t + TVar tvar -> pure (delete tvar tvars) + TFun t1 t2 -> go tvars t1 >>= (`go` t2) + TData _ typs -> foldlM go tvars typs + _ -> pure tvars + + +rpaType :: Type -> Err () +rpaType = rpForall . skipForall + where + skipForall = \case + TAll _ t -> skipForall t + t -> t + rpForall = \case + TAll {} -> throwError "Higher rank forall not allowed" + TFun t1 t2 -> on (>>) rpForall t1 t2 + TData _ typs -> mapM_ rpForall typs + _ -> pure () + +rpProgram :: (Type -> Err ()) -> Program -> Err () +rpProgram rf (Program defs) = do + mapM_ rpuBind bs + mapM_ rpuData ds + mapM_ rpuSig ss + where + (ds, ss, bs) = partitionDefs defs + rpuSig (Sig _ typ) = rf typ + rpuData (Data typ injs) = rf typ >> mapM rpuInj injs + rpuInj (Inj _ typ) = rf typ + rpuBind (Bind _ _ rhs) = rpuExp rhs + rpuBranch (Branch _ e) = rpuExp e + rpuExp = \case + EAnn e t -> rpuExp e >> rf t + EApp e1 e2 -> on (>>) rpuExp e1 e2 + EAdd e1 e2 -> on (>>) rpuExp e1 e2 + ELet bind e -> rpuBind bind >> rpuExp e + EAbs _ e -> rpuExp e + ECase e bs -> rpuExp e >> mapM_ rpuBranch bs + _ -> pure () + diff --git a/src/TreeConverter.hs b/src/TreeConverter.hs new file mode 100644 index 0000000..2dfa7d2 --- /dev/null +++ b/src/TreeConverter.hs @@ -0,0 +1,13 @@ +module TreeConverter where + +--import qualified Grammar.Abs as G +--import qualified TypeChecker.TypeCheckerIr as T +-- +--convertToTypecheckerIR :: G.Program -> Either String T.Program +--convertToTypecheckerIR (G.Program defs) = T.Program (map convertDef defs) +-- +--convertDef :: G.Bind -> T.Bind +--convertDef (G.Bind name t _ args exp) = T.Bind (name, t) (map (\i -> (i, T.TMono "Int"))) (convertExp exp) +-- +-- + diff --git a/src/TypeChecker.hs b/src/TypeChecker.hs deleted file mode 100644 index 1e44888..0000000 --- a/src/TypeChecker.hs +++ /dev/null @@ -1,178 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedRecordDot #-} - -module TypeChecker (typecheck, partitionType) where - -import Auxiliary (maybeToRightM, snoc) -import Control.Monad.Except (throwError, unless) -import Data.Map (Map) -import qualified Data.Map as Map -import Grammar.Abs -import Grammar.ErrM (Err) -import Grammar.Print (Print (prt), concatD, doc, printTree, - render) -import Prelude hiding (exp, id) -import qualified TypeCheckerIr as T - --- NOTE: this type checker is poorly tested - --- TODO --- Coercion --- Type inference - -data Cxt = Cxt - { env :: Map Ident Type -- ^ Local scope signature - , sig :: Map Ident Type -- ^ Top-level signatures - } - -initCxt :: [Bind] -> Cxt -initCxt sc = Cxt { env = mempty - , sig = Map.fromList $ map (\(Bind n t _ _ _) -> (n, t)) sc - } - -typecheck :: Program -> Err T.Program -typecheck (Program sc) = T.Program <$> mapM (checkBind $ initCxt sc) sc - --- | Check if infered rhs type matches type signature. -checkBind :: Cxt -> Bind -> Err T.Bind -checkBind cxt b = - case expandLambdas b of - Bind name t _ parms rhs -> do - (rhs', t_rhs) <- infer cxt rhs - unless (typeEq t_rhs t) . throwError $ typeErr name t t_rhs - pure $ T.Bind (name, t) (zip parms ts_parms) rhs' - where - ts_parms = fst $ partitionType (length parms) t - --- | @ f x y = rhs β‡’ f = \x.\y. rhs @ -expandLambdas :: Bind -> Bind -expandLambdas (Bind name t _ parms rhs) = Bind name t name [] rhs' - where - rhs' = foldr ($) rhs $ zipWith EAbs parms ts_parms - ts_parms = fst $ partitionType (length parms) t - --- | Infer type of expression. -infer :: Cxt -> Exp -> Err (T.Exp, Type) -infer cxt = \case - EId x -> - case lookupEnv x cxt of - Nothing -> - case lookupSig x cxt of - Nothing -> throwError ("Unbound variable:" ++ printTree x) - Just t -> pure (T.EId (x, t), t) - Just t -> pure (T.EId (x, t), t) - - EInt i -> pure (T.EInt i, T.TInt) - - EApp e e1 -> do - (e', t) <- infer cxt e - case t of - TFun t1 t2 -> do - e1' <- check cxt e1 t1 - pure (T.EApp t2 e' e1', t2) - _ -> do - throwError ("Not a function: " ++ show e) - - EAdd e e1 -> do - e' <- check cxt e T.TInt - e1' <- check cxt e1 T.TInt - pure (T.EAdd T.TInt e' e1', T.TInt) - - EAbs x t e -> do - (e', t1) <- infer (insertEnv x t cxt) e - let t_abs = TFun t t1 - pure (T.EAbs t_abs (x, t) e', t_abs) - - ELet b e -> do - let cxt' = insertBind b cxt - b' <- checkBind cxt' b - (e', t) <- infer cxt' e - pure (T.ELet b' e', t) - - EAnn e t -> do - (e', t1) <- infer cxt e - unless (typeEq t t1) $ - throwError "Inferred type and type annotation doesn't match" - pure (e', t1) - --- | Check infered type matches the supplied type. -check :: Cxt -> Exp -> Type -> Err T.Exp -check cxt exp typ = case exp of - - EId x -> do - t <- case lookupEnv x cxt of - Nothing -> maybeToRightM - ("Unbound variable:" ++ printTree x) - (lookupSig x cxt) - Just t -> pure t - unless (typeEq t typ) . throwError $ typeErr x typ t - pure $ T.EId (x, t) - - EInt i -> do - unless (typeEq typ TInt) $ throwError $ typeErr i TInt typ - pure $ T.EInt i - - EApp e e1 -> do - (e', t) <- infer cxt e - case t of - TFun t1 t2 -> do - e1' <- check cxt e1 t1 - pure $ T.EApp t2 e' e1' - _ -> throwError ("Not a function 2: " ++ printTree e) - - EAdd e e1 -> do - e' <- check cxt e T.TInt - e1' <- check cxt e1 T.TInt - pure $ T.EAdd T.TInt e' e1' - - EAbs x t e -> do - (e', t_e) <- infer (insertEnv x t cxt) e - let t1 = TFun t t_e - unless (typeEq t1 typ) $ throwError "Wrong lamda type!" - pure $ T.EAbs t1 (x, t) e' - - ELet b e -> do - let cxt' = insertBind b cxt - b' <- checkBind cxt' b - e' <- check cxt' e typ - pure $ T.ELet b' e' - - EAnn e t -> do - unless (typeEq t typ) $ - throwError "Inferred type and type annotation doesn't match" - check cxt e t - --- | Check if types are equivalent. Doesn't handle coercion or polymorphism. -typeEq :: Type -> Type -> Bool -typeEq (TFun t t1) (TFun q q1) = typeEq t q && typeEq t1 q1 -typeEq t t1 = t == t1 - --- | Partion type into types of parameters and return type. -partitionType :: Int -- Number of parameters to apply - -> Type - -> ([Type], Type) -partitionType = go [] - where - go acc 0 t = (acc, t) - go acc i t = case t of - TFun t1 t2 -> go (snoc t1 acc) (i - 1) t2 - _ -> error "Number of parameters and type doesn't match" - -insertBind :: Bind -> Cxt -> Cxt -insertBind (Bind n t _ _ _) = insertEnv n t - -lookupEnv :: Ident -> Cxt -> Maybe Type -lookupEnv x = Map.lookup x . env - -insertEnv :: Ident -> Type -> Cxt -> Cxt -insertEnv x t cxt = cxt { env = Map.insert x t cxt.env } - -lookupSig :: Ident -> Cxt -> Maybe Type -lookupSig x = Map.lookup x . sig - -typeErr :: Print a => a -> Type -> Type -> String -typeErr p expected actual = render $ concatD - [ doc $ showString "Wrong type:", prt 0 p , doc $ showString "\n" - , doc $ showString "Expected:" , prt 0 expected, doc $ showString "\n" - , doc $ showString "Actual: " , prt 0 actual - ] diff --git a/src/TypeChecker/Bugs.md b/src/TypeChecker/Bugs.md new file mode 100644 index 0000000..d1fd70d --- /dev/null +++ b/src/TypeChecker/Bugs.md @@ -0,0 +1,48 @@ +# Bugs + +## Using uninstantiated type variables + +Program below should not type check + +```hs +data Test (a) where { + Test : b -> Test (a) + }; +``` + +## Duplicate definitions of functions + +Program below should not type check + +```hs +id x = x ; +id x = x ; +``` + +## What? + +Program below should not type check + +```hs +main : a -> b ; +main x = x; +``` +## Pattern match on functions + +Program below should not type check + +```hs +main = case \x. x of { + _ => 0; +}; +``` + +# Inference should not depend on order + +This one is really tough, strangely +Spent many hours on this so far + +```hs +main = id 0 ; +id x = x; +``` diff --git a/src/TypeChecker/RemoveForall.hs b/src/TypeChecker/RemoveForall.hs new file mode 100644 index 0000000..886ecb0 --- /dev/null +++ b/src/TypeChecker/RemoveForall.hs @@ -0,0 +1,49 @@ +{-# LANGUAGE LambdaCase #-} + +module TypeChecker.RemoveForall (removeForall) where + +import Auxiliary (onM) +import Control.Applicative (Applicative (liftA2)) +import Data.Function (on) +import Data.List (partition) +import Data.Tuple.Extra (second) +import Grammar.ErrM (Err) +import qualified TypeChecker.ReportTEVar as R +import TypeChecker.TypeCheckerIr + +removeForall :: Program' R.Type -> Program +removeForall (Program defs) = Program $ map (DData . rfData) ds + ++ map (DBind . rfBind) bs + where + (ds, bs) = ([d | DData d <- defs ], [ b | DBind b <- defs ]) + rfData (Data typ injs) = Data (rfType typ) (map rfInj injs) + rfInj (Inj name typ) = Inj name (rfType typ) + rfBind (Bind name vars rhs) = Bind (rfId name) (map rfId vars) (rfExpT rhs) + rfId = second rfType + rfExpT (e, t) = (rfExp e, rfType t) + rfExp = \case + EApp e1 e2 -> on EApp rfExpT e1 e2 + EAdd e1 e2 -> on EAdd rfExpT e1 e2 + ELet bind e -> ELet (rfBind bind) (rfExpT e) + EAbs name e -> EAbs name (rfExpT e) + ECase e bs -> ECase (rfExpT e) (map rfBranch bs) + ELit lit -> ELit lit + EVar name -> EVar name + EInj name -> EInj name + rfBranch (Branch p e) = Branch (rfPatternT p) (rfExpT e) + rfPatternT (p, t) = (rfPattern p, rfType t) + rfPattern = \case + PVar name -> PVar name + PLit lit -> PLit lit + PCatch -> PCatch + PEnum name -> PEnum name + PInj name ps -> PInj name (map rfPatternT ps) + +rfType :: R.Type -> Type +rfType = \case + R.TAll _ t -> rfType t + R.TFun t1 t2 -> on TFun rfType t1 t2 + R.TData name ts -> TData name (map rfType ts) + R.TLit lit -> TLit lit + R.TVar tvar -> TVar tvar + diff --git a/src/TypeChecker/ReportTEVar.hs b/src/TypeChecker/ReportTEVar.hs new file mode 100644 index 0000000..62cd301 --- /dev/null +++ b/src/TypeChecker/ReportTEVar.hs @@ -0,0 +1,84 @@ +{-# LANGUAGE LambdaCase #-} + +module TypeChecker.ReportTEVar where + +import Auxiliary (onM) +import Control.Applicative (Applicative (liftA2), liftA3) +import Control.Monad.Except (MonadError (throwError)) +import Data.Coerce (coerce) +import Data.Tuple.Extra (secondM) +import Grammar.Abs qualified as G +import Grammar.ErrM (Err) +import Grammar.Print (printTree) +import TypeChecker.TypeCheckerIr hiding (Type (..)) + +data Type + = TLit Ident + | TVar TVar + | TData Ident [Type] + | TFun Type Type + | TAll TVar Type + deriving (Eq, Ord, Show, Read) + +class ReportTEVar a b where + reportTEVar :: a -> Err b + +instance ReportTEVar (Program' G.Type) (Program' Type) where + reportTEVar (Program defs) = Program <$> reportTEVar defs + +instance ReportTEVar (Def' G.Type) (Def' Type) where + reportTEVar = \case + DBind bind -> DBind <$> reportTEVar bind + DData dat -> DData <$> reportTEVar dat + +instance ReportTEVar (Bind' G.Type) (Bind' Type) where + reportTEVar (Bind id vars rhs) = liftA3 Bind (reportTEVar id) (reportTEVar vars) (reportTEVar rhs) + +instance ReportTEVar (Exp' G.Type) (Exp' Type) where + reportTEVar exp = case exp of + EVar name -> pure $ EVar name + EInj name -> pure $ EInj name + ELit lit -> pure $ ELit lit + ELet bind e -> liftA2 ELet (reportTEVar bind) (reportTEVar e) + EApp e1 e2 -> onM EApp reportTEVar e1 e2 + EAdd e1 e2 -> onM EAdd reportTEVar e1 e2 + EAbs name e -> EAbs name <$> reportTEVar e + ECase e branches -> liftA2 ECase (reportTEVar e) (reportTEVar branches) + +instance ReportTEVar (Branch' G.Type) (Branch' Type) where + reportTEVar (Branch (patt, t_patt) e) = liftA2 Branch (liftA2 (,) (reportTEVar patt) (reportTEVar t_patt)) (reportTEVar e) + +instance ReportTEVar (Pattern' G.Type, G.Type) (Pattern' Type, Type) where + reportTEVar (p, t) = liftA2 (,) (reportTEVar p) (reportTEVar t) + +instance ReportTEVar (Pattern' G.Type) (Pattern' Type) where + reportTEVar = \case + PVar name -> pure $ PVar name + PLit lit -> pure $ PLit lit + PCatch -> pure PCatch + PEnum name -> pure $ PEnum name + PInj name ps -> PInj name <$> reportTEVar ps + +instance ReportTEVar (Data' G.Type) (Data' Type) where + reportTEVar (Data typ injs) = liftA2 Data (reportTEVar typ) (reportTEVar injs) + +instance ReportTEVar (Inj' G.Type) (Inj' Type) where + reportTEVar (Inj name typ) = Inj name <$> reportTEVar typ + +instance ReportTEVar (Id' G.Type) (Id' Type) where + reportTEVar = secondM reportTEVar + +instance ReportTEVar (ExpT' G.Type) (ExpT' Type) where + reportTEVar (exp, typ) = liftA2 (,) (reportTEVar exp) (reportTEVar typ) + +instance ReportTEVar a b => ReportTEVar [a] [b] where + reportTEVar = mapM reportTEVar + +instance ReportTEVar G.Type Type where + reportTEVar = \case + G.TLit lit -> pure $ TLit (coerce lit) + G.TVar (G.MkTVar i) -> pure $ TVar (MkTVar $ coerce i) + G.TData name typs -> TData (coerce name) <$> reportTEVar typs + G.TFun t1 t2 -> liftA2 TFun (reportTEVar t1) (reportTEVar t2) + G.TAll (G.MkTVar i) t -> TAll (MkTVar $ coerce i) <$> reportTEVar t + G.TEVar tevar -> throwError ("Found TEVar: " ++ printTree tevar) diff --git a/src/TypeChecker/TypeChecker.hs b/src/TypeChecker/TypeChecker.hs new file mode 100644 index 0000000..7f3d67a --- /dev/null +++ b/src/TypeChecker/TypeChecker.hs @@ -0,0 +1,20 @@ +module TypeChecker.TypeChecker (typecheck, TypeChecker (..)) where + +import Control.Monad ((<=<)) +import qualified Grammar.Abs as G +import Grammar.ErrM (Err) +import TypeChecker.RemoveForall (removeForall) +import qualified TypeChecker.ReportTEVar as R +import TypeChecker.ReportTEVar (reportTEVar) +import qualified TypeChecker.TypeCheckerBidir as Bi +import qualified TypeChecker.TypeCheckerHm as Hm +import TypeChecker.TypeCheckerIr + +data TypeChecker = Bi | Hm deriving Eq + +typecheck :: TypeChecker -> G.Program -> Err Program +typecheck tc = fmap removeForall . (reportTEVar <=< f) + where + f = case tc of + Bi -> Bi.typecheck + Hm -> fmap fst . Hm.typecheck diff --git a/src/TypeChecker/TypeCheckerBidir.hs b/src/TypeChecker/TypeCheckerBidir.hs new file mode 100644 index 0000000..04a8d91 --- /dev/null +++ b/src/TypeChecker/TypeCheckerBidir.hs @@ -0,0 +1,858 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} + +module TypeChecker.TypeCheckerBidir (typecheck) where + +import Auxiliary (int, litType, maybeToRightM, snoc) +import Control.Applicative (Applicative (liftA2), (<|>)) +import Control.Monad.Except (ExceptT, MonadError (throwError), + forM, runExceptT, unless, zipWithM, + zipWithM_) +import Control.Monad.Extra (fromMaybeM, ifM) +import Control.Monad.State (MonadState, State, evalState, gets, + modify) +import Data.Coerce (coerce) +import Data.Foldable (foldlM) +import Data.Function (on) +import Data.List (intercalate) +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Maybe (fromMaybe, isNothing) +import Data.Sequence (Seq (..)) +import qualified Data.Sequence as S +import qualified Data.Set as Set +import Data.Tuple.Extra (second) +import Debug.Trace (trace) +import Grammar.Abs +import Grammar.ErrM +import Grammar.Print (printTree) +import Prelude hiding (exp) +import qualified TypeChecker.TypeCheckerIr as T + +-- Implementation is derived from the paper (Dunfield and Krishnaswami 2013) +-- https://doi.org/10.1145/2500365.2500582 +-- +-- TODO +-- β€’ Fix problems with types in Pattern/Branch in TypeCheckerIr +-- β€’ Remove EAdd +-- β€’ Add kinds!! + +data EnvElem = EnvVar LIdent Type -- ^ Term variable typing. x : A + | EnvTVar TVar -- ^ Universal type variable. Ξ± + | EnvTEVar TEVar -- ^ Existential unsolved type variable. Ξ¬ + | EnvTEVarSolved TEVar Type -- ^ Existential solved type variable. Ξ¬ = Ο„ + | EnvMark TEVar -- ^ Scoping Marker. β–Ά Ξ¬ + deriving (Eq, Show) + +type Env = Seq EnvElem + +-- | Ordered context +-- Ξ“ ::= ・| Ξ“, Ξ± | Ξ“, Ξ¬ | Ξ“, β–Ά Ξ¬ | Ξ“, x:A +data Cxt = Cxt + { env :: Env -- ^ Local scope context Ξ“ + , sig :: Map LIdent Type -- ^ Top-level signatures x : A + , binds :: Map LIdent Exp -- ^ Top-level binds x : e + , next_tevar :: Int -- ^ Counter to distinguish Ξ¬ + , data_injs :: Map UIdent Type -- ^ Data injections (constructors) K/inj : A + , currentBind :: LIdent -- ^ Used for recursive functions + } deriving (Show, Eq) + +newtype Tc a = Tc { runTc :: ExceptT String (State Cxt) a } + deriving (Functor, Applicative, Monad, MonadState Cxt, MonadError String) + + +initCxt :: [Def] -> Cxt +initCxt defs = Cxt + { env = mempty + , sig = Map.fromList [ (name, t) + | DSig' name t <- defs + ] + , binds = Map.fromList [ (name, foldr EAbs rhs vars) + | DBind' name vars rhs <- defs + ] + , next_tevar = 0 + , data_injs = Map.fromList [ (name, foldr TAll t $ unboundedTVars t) + | DData (Data _ injs) <- defs + , Inj name t <- injs + ] + , currentBind = "" + } + where + unboundedTVars = uncurry (Set.\\) . go (mempty, mempty) + where + go (unbounded, bounded) = \case + TAll tvar t -> go (unbounded, Set.insert tvar bounded) t + TVar tvar -> (Set.insert tvar unbounded, bounded) + TFun t1 t2 -> foldl go (unbounded, bounded) [t1, t2] + TData _ typs -> foldl go (unbounded, bounded) typs + _ -> (unbounded, bounded) + +typecheck :: Program -> Err (T.Program' Type) +typecheck (Program defs) = do + dataTypes' <- mapM typecheckDataType [ d | DData d <- defs ] + binds' <- typecheckBinds (initCxt defs) [b | DBind b <- defs] + pure . T.Program $ map T.DData dataTypes' ++ map T.DBind binds' + +typecheckBinds :: Cxt -> [Bind] -> Err [T.Bind' Type] +typecheckBinds cxt = flip evalState cxt + . runExceptT + . runTc + . mapM typecheckBind + +typecheckBind :: Bind -> Tc (T.Bind' Type) +typecheckBind (Bind name vars rhs) = do + modify $ \cxt -> cxt { currentBind = name } + bind'@(T.Bind (name, typ) _ _) <- lookupSig name >>= \case + Just t -> do + (rhs', _) <- check (foldr EAbs rhs vars) t + pure (T.Bind (coerce name, t) [] (rhs', t)) + Nothing -> do + (e, t) <- apply =<< infer (foldr EAbs rhs vars) + pure (T.Bind (coerce name, t) [] (e, t)) + env <- gets env + unless (isComplete env) err + insertSig (coerce name) typ + putEnv Empty + pure bind' + where + err = throwError $ unlines + [ "Type inference failed: " ++ printTree (Bind name vars rhs) + , "Did you forget to add type annotation to a polymorphic function?" + ] + +-- TODO remove some checks +typecheckDataType :: Data -> Err (T.Data' Type) +typecheckDataType (Data typ injs) = do + (name, tvars) <- go [] typ + injs' <- mapM (\i -> typecheckInj i name tvars) injs + pure (T.Data typ injs') + where + go tvars = \case + TAll tvar t -> go (tvar:tvars) t + TData name typs + | Right tvars' <- mapM toTVar typs + , all (`elem` tvars) tvars' + -> pure (name, tvars') + _ -> throwError $ unwords ["Bad data type definition: ", ppT typ] + +-- TODO remove some checks +typecheckInj :: Inj -> UIdent -> [TVar] -> Err (T.Inj' Type) +typecheckInj (Inj inj_name inj_typ) name tvars + | not $ boundTVars tvars inj_typ + = throwError "Unbound type variables" + | TData name' typs <- getDataId inj_typ + , name' == name + , Right tvars' <- mapM toTVar typs + , all (`elem` tvars) tvars' + = pure $ T.Inj (coerce inj_name) (foldr TAll inj_typ tvars') + | otherwise + = throwError $ unwords + ["Bad type constructor: ", show name + , "\nExpected: ", ppT . TData name $ map TVar tvars + , "\nActual: ", ppT $ getDataId inj_typ + ] + where + boundTVars :: [TVar] -> Type -> Bool + boundTVars tvars' = \case + TAll tvar t -> boundTVars (tvar:tvars') t + TFun t1 t2 -> on (&&) (boundTVars tvars') t1 t2 + TVar tvar -> elem tvar tvars' + TData _ typs -> all (boundTVars tvars) typs + TLit _ -> True + TEVar _ -> error "TEVar in data type declaration" + + + +--------------------------------------------------------------------------- +-- * Typing rules +--------------------------------------------------------------------------- + +-- | Ξ“ ⊒ e ↑ A ⊣ Ξ” +-- Under input context Ξ“, e checks against input type A, with output context βˆ† +check :: Exp -> Type -> Tc (T.ExpT' Type) + +-- Ξ“,Ξ± ⊒ e ↑ A ⊣ Ξ”,Ξ±,Θ +-- ------------------- βˆ€I +-- Ξ“ ⊒ e ↑ βˆ€Ξ±.A ⊣ Ξ” +check e (TAll alpha a) = do + let env_tvar = EnvTVar alpha + insertEnv env_tvar + e' <- check e a + (env_l, _) <- gets (splitOn env_tvar . env) + putEnv env_l + apply e' + +-- Ξ“,(x:A) ⊒ e ↑ B ⊒ Ξ”,(x:A),Θ +-- --------------------------- β†’I +-- Ξ“ ⊒ Ξ»x.e ↑ A β†’ B ⊣ Ξ” +check (EAbs x e) (TFun a b) = do + let env_var = EnvVar x a + insertEnv env_var + e' <- check e b + (env_l, _) <- gets (splitOn env_var . env) + putEnv env_l + apply (T.EAbs (coerce x) e', TFun a b) + + --FIXME +-- Ξ“ ⊒ e ↑ A ⊣ Θ Θ ⊒ Ξ  ∷ [Θ]A ↓ C ⊣ Ξ” +-- ------------------------------------ Case +-- Ξ“ ⊒ case e of Ξ  ↓ C ⊣ Ξ” +check (ECase scrut pi) c = do + (scrut', a) <- infer scrut + case pi of + [] -> do + subtype a c + apply (T.ECase (scrut', a) [], a) + _ -> do + pi' <- forM pi $ \(Branch p e) -> do + p' <- checkPattern p =<< apply a + e' <- check e c + pure (T.Branch p' e') + apply (T.ECase (scrut', a) pi', c) + where + go (pi, b) (Branch p e) = do + p' <- checkPattern p =<< apply a + e'@(_, b') <- infer e + subtype b' b + apply (T.Branch p' e' : pi, b') + + +-- Ξ“,Ξ± ⊒ e ↓ A ⊣ Θ Θ ⊒ [Θ]A <: [Θ]B ⊣ Ξ” +-- -------------------------------------- Sub +-- Ξ“ ⊒ e ↑ B ⊣ Ξ” +check e b = do + (e', a) <- infer e + b' <- apply b + subtype a b' + apply (e', b) + + + + +checkPattern :: Pattern -> Type -> Tc (T.Pattern' Type, Type) +checkPattern patt t_patt = case patt of + + -- ------------------- + -- Ξ“ ⊒ x ↑ A ⊣ Ξ“,(x:A) + PVar x -> do + insertEnv $ EnvVar x t_patt + apply (T.PVar (coerce x), t_patt) + + -- ------------- + -- Ξ“ ⊒ _ ↑ A ⊣ Ξ“ + PCatch -> apply (T.PCatch, t_patt) + + -- Ξ“ ⊒ Ο„ ↓ A ⊣ Ξ“ Ξ“ ⊒ A <: B ⊣ Ξ” + -- ------------------------------ + -- Ξ“ ⊒ Ο„ ↑ B ⊣ Ξ” + PLit lit -> do + subtype (litType lit) t_patt + apply (T.PLit lit, t_patt) + + -- Ξ“ βˆ‹ (K : A) Ξ“ ⊒ A <: B ⊣ Ξ” + -- --------------------------- + -- Ξ“ ⊒ K ↑ B ⊣ Ξ” + PEnum name -> do + t <- maybeToRightM ("Unknown constructor " ++ show name) + =<< lookupInj name + subtype t t_patt + apply (T.PEnum (coerce name), t_patt) + + -- Example + -- Ξ“ βˆ‹ (K : A) let A = βˆ€Ξ±. A₁ -> Aβ‚‚ -> TΟ„s + -- Ξ“ ⊒ [Ξ¬/Ξ±]TΟ„s <: B ⊣ Ξ˜β‚ + -- Θ ⊒ p₁ ↑ [Θ][Ξ¬/Ξ±]A₁ ⊣ Ξ˜β‚‚ + -- Ξ˜β‚‚ ⊒ pβ‚‚ ↑ [Ξ˜β‚‚][Ξ¬/Ξ±]Aβ‚‚ ⊣ Ξ” + -- --------------------------- + -- Ξ“ ⊒ K p₁ pβ‚‚ ↑ B ⊣ Ξ” + PInj name ps -> do + t_inj <- maybeToRightM "unknown constructor" =<< lookupInj name + let ts = getArgs t_inj + unless (length ts == length ps) + $ throwError "Wrong number of arguments!" + + -- [Ξ¬/Ξ±] + sub <- substituteTVarsOf t_inj + subtype (sub $ getDataId t_inj) t_patt + let check p t = checkPattern p =<< apply (sub t) + ps' <- zipWithM check ps ts + apply (T.PInj (coerce name) ps', t_patt) + where + substituteTVarsOf = \case + TAll tvar t -> do + tevar <- fresh + (substitute tvar tevar .) <$> substituteTVarsOf t + _ -> pure id + + getArgs = \case + TAll _ t -> getArgs t + t -> go [] t + where + go acc = \case + TFun t1 t2 -> go (snoc t1 acc) t2 + _ -> acc + +-- | Ξ“ ⊒ e ↓ A ⊣ Ξ” +-- Under input context Ξ“, e infers output type A, with output context βˆ† +infer :: Exp -> Tc (T.ExpT' Type) +infer (ELit lit) = apply (T.ELit lit, litType lit) + +-- Ξ“ βˆ‹ (x : A) Ξ“ ⊒ rec(x) +-- ------------- Var --------------------- VarRec +-- Ξ“ ⊒ x ↓ A ⊣ Ξ“ Ξ“ ⊒ x ↓ Ξ¬ ⊣ Ξ“,(x : Ξ¬) +infer (EVar x) = do + a <- ifM (gets $ (x==) . currentBind) varRec var + apply (T.EVar (coerce x), a) + where + var = maybeToRightM "Can't infer" =<< + liftA2 (<|>) (lookupEnv x) (lookupSig x) + varRec = do + alpha <- TEVar <$> fresh + insertEnv (EnvVar x alpha) + pure alpha + +infer (EInj kappa) = do + t <- maybeToRightM ("Unknown constructor: " ++ show kappa) + =<< lookupInj kappa + apply (T.EInj $ coerce kappa, t) + +-- Ξ“ ⊒ A Ξ“ ⊒ e ↑ A ⊣ Ξ” +-- --------------------- Anno +-- Ξ“ ⊒ (e : A) ↓ A ⊣ Ξ” +infer (EAnn e a) = do + _ <- gets $ (`wellFormed` a) . env + (e', _) <- check e a + apply (e', a) + +-- Ξ“ ⊒ e₁ ↓ A ⊣ Θ Ξ“ ⊒ [Θ]A β€’ ⇓ C ⊣ Ξ” +-- ----------------------------------- β†’E +-- Ξ“ ⊒ e₁ eβ‚‚ ↓ C ⊣ Ξ” +infer (EApp e1 e2) = do + e1'@(_, a) <- infer e1 + (e2', c) <- applyInfer a e2 + apply (T.EApp e1' e2', c) + +-- Ξ“,Ξ¬,Ξ­,(x:Ξ¬) ⊒ e ↑ Ξ­ ⊣ Ξ”,(x:Ξ¬),Θ +-- ------------------------------- β†’I +-- Ξ“ ⊒ Ξ»x.e ↓ Ξ¬ β†’ Ξ­ ⊣ Ξ” +infer (EAbs name e) = do + alpha <- fresh + epsilon <- fresh + insertEnv $ EnvTEVar alpha + insertEnv $ EnvTEVar epsilon + let env_var = EnvVar name (TEVar alpha) + insertEnv env_var + e' <- check e $ TEVar epsilon + dropTrailing env_var + apply (T.EAbs (coerce name) e', on TFun TEVar alpha epsilon) + +-- Ξ“ ⊒ rhs ↓ A ⊣ Θ Θ,(x:A) ⊒ e ↑ C ⊣ Ξ”,(x:A),Θ +-- -------------------------------------------- LetI +-- Ξ“ ⊒ let x = rhs in e ↑ C ⊣ Ξ” +infer (ELet (Bind x vars rhs) e) = do + (rhs', a) <- infer $ foldr EAbs rhs vars + let env_var = EnvVar x a + insertEnv env_var + e'@(_, c) <- infer e + (env_l, _) <- gets (splitOn env_var . env) + putEnv env_l + apply (T.ELet (T.Bind (coerce x, a) [] (rhs', a)) e', c) + +-- Ξ“ ⊒ e₁ ↑ Int ⊣ Θ Θ ⊒ eβ‚‚ ↑ Int +-- --------------------------- +I +-- Ξ“ ⊒ e₁ + eβ‚‚ ↓ Int ⊣ Ξ” +infer (EAdd e1 e2) = do + e1' <- check e1 int + e2' <- check e2 int + apply (T.EAdd e1' e2', int) + + --FIXME +-- Ξ“ ⊒ e ↑ A ⊣ Θ Θ ⊒ Ξ  ∷ [Θ]A ↑ C ⊣ Ξ” +-- ------------------------------------ Case +-- Ξ“ ⊒ case e of Ξ  ↓ C ⊣ Ξ” +infer (ECase scrut pi) = do + (scrut', a) <- infer scrut + case pi of + [] -> apply (T.ECase (scrut', a) [], a) + (Branch _ e):_ -> do + (_, b)<- infer e + (pi', b') <- foldlM go ([], b) pi + apply (T.ECase (scrut', a) pi', b') + where + go (pi, b) (Branch p e) = do + p' <- checkPattern p =<< apply a + e'@(_, b') <- infer e + subtype b' b + apply (T.Branch p' e' : pi, b') + +-- | Ξ“ ⊒ A β€’ e ⇓ C ⊣ Ξ” +-- Under input context Ξ“ , applying a function of type A to e infers type C, with output context βˆ† +-- Instantiate existential type variables until there is an arrow type. +applyInfer :: Type -> Exp -> Tc (T.ExpT' Type, Type) + +-- Ξ“,Ξ¬ ⊒ [Ξ¬/Ξ±]A β€’ e ⇓ C ⊣ Ξ” +-- ------------------------ βˆ€App +-- Ξ“ ⊒ βˆ€Ξ±.A β€’ e ⇓ C ⊣ Ξ” +applyInfer (TAll alpha a) e = do + alpha' <- fresh + insertEnv $ EnvTEVar alpha' + applyInfer (substitute alpha alpha' a) e + +-- Ξ“[Ξ¬β‚‚,ά₁,(Ξ¬=ά₁→ά₂)] ⊒ e ↑ ά₁ ⊣ Ξ” +-- ------------------------------- Ξ¬App +-- Ξ“[Ξ¬] ⊒ Ξ¬ β€’ e ⇓ Ξ¬β‚‚ ⊣ Ξ” +applyInfer (TEVar alpha) e = do + alpha1 <- fresh + alpha2 <- fresh + (env_l, env_r) <- gets (splitOn (EnvTEVar alpha) . env) + putEnv $ (env_l + :|> EnvTEVar alpha2 + :|> EnvTEVar alpha1 + :|> EnvTEVarSolved alpha (on TFun TEVar alpha1 alpha2) + ) <> env_r + e' <- check e $ TEVar alpha1 + apply (e', TEVar alpha2) + +-- Ξ“ ⊒ e ↑ A ⊣ Ξ” +-- --------------------- β†’App +-- Ξ“ ⊒ A β†’ C β€’ e ⇓ C ⊣ Ξ” +applyInfer (TFun a c) e = do + exp' <- check e a + apply (exp', c) + +applyInfer a e = throwError ("Cannot apply type " ++ show a ++ " with expression " ++ show e) + +--------------------------------------------------------------------------- +-- * Subtyping rules +--------------------------------------------------------------------------- + +-- | Ξ“ ⊒ A <: B ⊣ Ξ” +-- Under input context Ξ“, type A is a subtype of B, with output context βˆ† +subtype :: Type -> Type -> Tc () +subtype (TLit lit1) (TLit lit2) | lit1 == lit2 = pure () + +-- -------------------- <:Var +-- Ξ“[Ξ±] ⊒ Ξ± <: Ξ± ⊣ Ξ“[Ξ±] +subtype (TVar alpha) (TVar alpha') | alpha == alpha' = pure () + +-- -------------------- <:Exvar +-- Ξ“[Ξ¬] ⊒ Ξ¬ <: Ξ¬ ⊣ Ξ“[Ξ¬] +subtype (TEVar alpha) (TEVar alpha') | alpha == alpha' = pure () + +-- Ξ“ ⊒ B₁ <: A₁ ⊣ Θ Θ ⊒ [Θ]Aβ‚‚ <: [Θ]Bβ‚‚ ⊣ Ξ” +-- ----------------------------------------- <:β†’ +-- Ξ“ ⊒ A₁ β†’ Aβ‚‚ <: B₁ β†’ Bβ‚‚ ⊣ Ξ” +subtype (TFun a1 a2) (TFun b1 b2) = do + subtype b1 a1 + a2' <- apply a2 + b2' <- apply b2 + subtype a2' b2' + +-- Ξ“, Ξ± ⊒ A <: B ⊣ Ξ”,Ξ±,Θ +-- --------------------- <:βˆ€R +-- Ξ“ ⊒ A <: βˆ€Ξ±. B ⊣ Ξ” +subtype a (TAll alpha b) = do + let env_tvar = EnvTVar alpha + insertEnv env_tvar + subtype a b + dropTrailing env_tvar + +-- Ξ“,β–Ά Ξ¬,Ξ¬ ⊒ [Ξ¬/Ξ±]A <: B ⊣ Ξ”,β–Ά Ξ¬,Θ +-- ------------------------------- <:βˆ€L +-- Ξ“ ⊒ βˆ€Ξ±.A <: B ⊣ Ξ” +subtype (TAll alpha a) b = do + alpha' <- fresh + let env_marker = EnvMark alpha' + insertEnv env_marker + insertEnv $ EnvTEVar alpha' + let a' = substitute alpha alpha' a + subtype a' b + dropTrailing env_marker + +-- Ξ¬ βˆ‰ FV(A) Ξ“[Ξ¬] ⊒ Ξ¬ :=< A ⊣ Ξ” +-- ------------------------------ <:instantiateL +-- Ξ“[Ξ¬] ⊒ Ξ¬ <: A ⊣ Ξ” +subtype (TEVar alpha) a | notElem alpha $ frees a = instantiateL alpha a + +-- Ξ¬ βˆ‰ FV(A) Ξ“[Ξ¬] ⊒ A =:< Ξ¬ ⊣ Ξ” +-- ------------------------------ <:instantiateR +-- Ξ“[Ξ¬] ⊒ A <: Ξ¬ ⊣ Ξ” +subtype a (TEVar alpha) | notElem alpha $ frees a = instantiateR a alpha + + +subtype (TData name1 typs1) (TData name2 typs2) + + -- D₁ = Dβ‚‚ + -- ---------------- + -- Ξ“ ⊒ D₁ () <: Dβ‚‚ () + | name1 == name2 + , [] <- typs1 + , [] <- typs2 + = pure () + + -- Ξ“ ⊒ ά₁ <: έ₁ ⊣ Ξ˜β‚ + -- ... + -- D₁ = Dβ‚‚ Ξ˜β‚™β‚‹β‚ ⊒ [Ξ˜β‚™β‚‹β‚]Ξ¬β‚™ <: [Ξ˜β‚™β‚‹β‚]Ξ­β‚™ ⊣ Ξ” + -- ------------------------------------------- + -- Ξ“ ⊒ D (ά₁ β€₯ Ξ¬β‚™) <: D (έ₁ β€₯ Ξ­β‚™) ⊣ Ξ” + | name1 == name2 + , t1:t1s <- typs1 + , t2:t2s <- typs2 + = do + subtype t1 t2 + zipWithM_ go t1s t2s + where + go t1' t2' = do + t1'' <- apply t1' + t2'' <- apply t2' + subtype t1'' t2'' + +subtype (TIdent t1) (TIdent t2) | t1 == t2 = pure () + +subtype t1 t2 = throwError $ unwords ["Types", show t1, "and", show t2, "doesn't match!"] + +--------------------------------------------------------------------------- +-- * Instantiation rules +--------------------------------------------------------------------------- + +-- | Ξ“ ⊒ Ξ¬ :=< A ⊣ Ξ” +-- Under input context Ξ“, instantiate Ξ¬ such that Ξ¬ <: A, with output context βˆ† +instantiateL :: TEVar -> Type -> Tc () +instantiateL alpha a = gets env >>= \env -> go env alpha a + where + go env alpha tau + | isMono tau + , (env_l, env_r) <- splitOn (EnvTEVar alpha) env + , Right _ <- wellFormed env_l tau + = putEnv $ (env_l :|> EnvTEVarSolved alpha tau) <> env_r + + -- Ξ“ ⊒ Ο„ + -- ----------------------------- InstLSolve + -- Ξ“,Ξ¬,Ξ“' ⊒ Ξ¬ :=< Ο„ ⊣ Ξ“,(Ξ¬=Ο„),Ξ“' + go env alpha tau + | isMono tau + , (env_l, env_r) <- splitOn (EnvTEVar alpha) env + , Right _ <- wellFormed env_l tau + = putEnv $ (env_l :|> EnvTEVarSolved alpha tau) <> env_r + + -- ----------------------------- InstLReach + -- Ξ“[Ξ¬][Ξ­] ⊒ Ξ¬ :=< Ξ­ ⊣ Ξ“[Ξ¬][Ξ­=Ξ¬] + go env alpha (TEVar epsilon) = do + let (env_l, env_r) = splitOn (EnvTEVar epsilon) env + putEnv $ (env_l :|> EnvTEVarSolved epsilon (TEVar alpha)) <> env_r + + -- Ξ“[ά₂ά₁,(Ξ¬=ά₁→ά₂)] ⊒ A₁ =:< ά₁ ⊣ Θ Θ ⊒ Ξ¬β‚‚ :=< [Θ]Aβ‚‚ ⊣ Ξ” + -- ------------------------------------------------------- InstLArr + -- Ξ“[Ξ¬] ⊒ Ξ¬ :=< A₁ β†’ Aβ‚‚ ⊣ Ξ” + go _ alpha (TFun a1 a2) = do + alpha1 <- fresh + alpha2 <- fresh + insertEnv $ EnvTEVar alpha2 + insertEnv $ EnvTEVar alpha1 + insertEnv $ EnvTEVarSolved alpha (on TFun TEVar alpha1 alpha2) + instantiateR a1 alpha1 + instantiateL alpha2 =<< apply a2 + + -- Ξ“[Ξ¬],Ξ΅ ⊒ Ξ¬ :=< E ⊣ Ξ”,Ξ΅,Ξ”' + -- ------------------------- InstLAIIR + -- Ξ“[Ξ¬] ⊒ Ξ¬ :=< βˆ€Ξ΅.Ξ• ⊣ Ξ” + go env tevar (TAll tvar t) = do + instantiateL tevar t + let (env_l, _) = splitOn (EnvTVar tvar) env + putEnv env_l + + go _ alpha a = error $ "Trying to instantiateL: " ++ ppT (TEVar alpha) + ++ " <: " ++ ppT a + +-- | Ξ“ ⊒ A =:< Ξ¬ ⊣ Ξ” +-- Under input context Ξ“, instantiate Ξ¬ such that A <: Ξ¬, with output context βˆ† +instantiateR :: Type -> TEVar -> Tc () +instantiateR a alpha = gets env >>= \env -> go env a alpha + where + -- Ξ“ ⊒ Ο„ + -- ----------------------------- InstRSolve + -- Ξ“,Ξ¬,Ξ“' ⊒ Ο„ =:< Ξ¬ ⊣ Ξ“,(Ξ¬=Ο„),Ξ“' + go env tau alpha + | isMono tau + , (env_l, env_r) <- splitOn (EnvTEVar alpha) env + , Right _ <- wellFormed env_l tau + = putEnv $ (env_l :|> EnvTEVarSolved alpha tau) <> env_r + + -- + -- ----------------------------- InstRReach + -- Ξ“[Ξ¬][Ξ­] ⊒ Ξ­ =:< Ξ¬ ⊣ Ξ“[Ξ¬][Ξ­=Ξ¬] + go env (TEVar epsilon) alpha = do + let (env_l, env_r) = splitOn (EnvTEVar epsilon) env + putEnv $ (env_l :|> EnvTEVarSolved epsilon (TEVar alpha)) <> env_r + + -- Ξ“[ά₂ά₁,(Ξ¬=ά₁→ά₂)] ⊒ A₁ :=< ά₁ ⊣ Θ Θ ⊒ Ξ¬β‚‚ =:< [Θ]Aβ‚‚ ⊣ Ξ” + -- ------------------------------------------------------- InstRArr + -- Ξ“[Ξ¬] ⊒ A₁ β†’ Aβ‚‚ =:< Ξ¬ ⊣ Ξ” + go _ (TFun a1 a2) alpha = do + alpha1 <- fresh + alpha2 <- fresh + insertEnv $ EnvTEVar alpha2 + insertEnv $ EnvTEVar alpha1 + insertEnv $ EnvTEVarSolved alpha (on TFun TEVar alpha1 alpha2) + instantiateL alpha1 a1 + a2' <- apply a2 + instantiateR a2' alpha2 + + -- Ξ“[Ξ¬],β–ΆΞ­,Ξ΅ ⊒ [Ξ­/Ξ΅]E =:< Ξ¬ ⊣ Ξ”,β–ΆΞ­,Ξ”' + -- ---------------------------------- InstRAIIL + -- Ξ“[Ξ¬] ⊒ βˆ€Ξ΅.Ξ• =:< Ξ¬ ⊣ Ξ” + go env (TAll epsilon e) alpha = do + epsilon' <- fresh + insertEnv $ EnvMark epsilon' + insertEnv $ EnvTVar epsilon + instantiateR (substitute epsilon epsilon' e) alpha + let (env_l, _) = splitOn (EnvMark epsilon') env + putEnv env_l + + go _ a alpha = throwError $ "Trying to instantiateR: " ++ ppT a ++ " <: " + ++ ppT (TEVar alpha) + +--------------------------------------------------------------------------- +-- * Auxiliary +--------------------------------------------------------------------------- + +frees :: Type -> [TEVar] +frees = \case + TLit _ -> [] + TVar _ -> [] + TEVar tevar -> [tevar] + TFun t1 t2 -> on (++) frees t1 t2 + TAll _ t -> frees t + TData _ typs -> concatMap frees typs + +-- | [Ξ¬/Ξ±]A +substitute :: TVar -- Ξ± + -> TEVar -- Ξ¬ + -> Type -- A + -> Type -- [Ξ¬/Ξ±]A +substitute tvar tevar typ = case typ of + TLit _ -> typ + TVar tvar' | tvar' == tvar -> TEVar tevar + | otherwise -> typ + TEVar _ -> typ + TFun t1 t2 -> on TFun substitute' t1 t2 + TAll tvar' t -> TAll tvar' (substitute' t) + TData name typs -> TData name $ map substitute' typs + where + substitute' = substitute tvar tevar + +-- | Ξ“,x,Ξ“' β†’ (Ξ“, Ξ“') +splitOn :: EnvElem -> Env -> (Env, Env) +splitOn x env = second (S.drop 1) $ S.breakl (==x) env + +-- | Drop frontmost elements until and including element @x@. +dropTrailing :: EnvElem -> Tc () +dropTrailing x = modifyEnv $ S.takeWhileL (/= x) + + +findSolved :: TEVar -> Env -> Maybe Type +findSolved _ Empty = Nothing +findSolved tevar (xs :|> x) = case x of + EnvTEVarSolved tevar' t | tevar == tevar' -> Just t + _ -> findSolved tevar xs + +-- | Ξ“ ⊒ A +-- Under context Ξ“, type A is well-formed +wellFormed :: Env -> Type -> Err () +wellFormed env = \case + TLit _ -> pure () + + -- -------- UvarWF + -- Ξ“[Ξ±] ⊒ Ξ± + TVar tvar -> unless (EnvTVar tvar `elem` env) $ + throwError ("Unbound type variable: " ++ show tvar) + -- Ξ“ ⊒ A Ξ“ ⊒ B + -- ------------- ArrowWF + -- Ξ“ ⊒ A β†’ B + TFun t1 t2 -> do { wellFormed env t1; wellFormed env t2 } + + -- Ξ“,Ξ± ⊒ A + -- -------- ForallWF + -- Ξ“ ⊒ βˆ€Ξ±.A + TAll tvar t -> wellFormed (env :|> EnvTVar tvar) t + + TEVar tevar + -- ---------- EvarWF + -- Ξ“[Ξ¬] ⊒ Ξ¬ + | EnvTEVar tevar `elem` env -> pure () + + -- ---------- SolvedEvarWF + -- Ξ“[Ξ¬=Ο„] ⊒ Ξ¬ + | Just _ <- findSolved tevar env -> pure () + | otherwise -> throwError ("Can't find type: " ++ show tevar) + + TData _ typs -> mapM_ (wellFormed env) typs + +isMono :: Type -> Bool +isMono = \case + TAll{} -> False + TFun t1 t2 -> on (&&) isMono t1 t2 + TData _ typs -> all isMono typs + TVar _ -> True + TEVar _ -> True + TLit _ -> True + +fresh :: Tc TEVar +fresh = do + tevar <- gets (MkTEVar . LIdent . show . next_tevar) + modify $ \cxt -> cxt { next_tevar = succ cxt.next_tevar } + pure tevar + + +isComplete :: Env -> Bool +isComplete = isNothing . S.findIndexL unSolvedTEVar + where + unSolvedTEVar = \case + EnvTEVar _ -> True + _ -> False + +getDataId :: Type -> Type +getDataId typ = case typ of + TAll _ t -> getDataId t + TFun _ t -> getDataId t + TData {} -> typ + +toTVar :: Type -> Err TVar +toTVar = \case + TVar tvar -> pure tvar + _ -> throwError "Not a type variable" + +insertEnv :: EnvElem -> Tc () +insertEnv x = modifyEnv (:|> x) + +lookupSig :: LIdent -> Tc (Maybe Type) +lookupSig x = gets (Map.lookup x . sig) + +insertSig :: LIdent -> Type -> Tc () +insertSig name t = modify $ \cxt -> cxt { sig = Map.insert name t cxt.sig } + +lookupEnv :: LIdent -> Tc (Maybe Type) +lookupEnv x = gets (findId . env) + where + findId Empty = Nothing + findId (ys :|> y) = case y of + EnvVar x' t | x==x' -> Just t + _ -> findId ys + +lookupInj :: UIdent -> Tc (Maybe Type) +lookupInj x = gets (Map.lookup x . data_injs) + +putEnv :: Env -> Tc () +putEnv = modifyEnv . const + +modifyEnv :: (Env -> Env) -> Tc () +modifyEnv f = + modify $ \cxt -> {- trace (ppEnv (f cxt.env)) -} cxt { env = f cxt.env } + +pattern DBind' name vars exp = DBind (Bind name vars exp) +pattern DSig' name typ = DSig (Sig name typ) + +--------------------------------------------------------------------------- +-- * Apply +--------------------------------------------------------------------------- + +class Apply a where + apply :: a -> Tc a + +instance Apply Type where apply = applyType +instance Apply (T.Exp' Type) where apply = applyExp +instance Apply (T.Branch' Type) where apply = applyBranch +instance Apply (T.Pattern' Type) where apply = applyPattern +instance Apply a => Apply [a] where apply = mapM apply +instance (Apply a, Apply b) => Apply (a, b) where apply = applyPair +instance Apply T.Ident where apply = pure + +applyType :: Type -> Tc Type +applyType t = gets $ (`applyType'` t) . env + +-- | [Ξ“]A. Applies context to type until fully applied. +applyType' :: Env -> Type -> Type +applyType' cxt typ | typ == typ' = typ' + | otherwise = applyType' cxt typ' + where + typ' = case typ of + TLit _ -> typ + TData name typs -> TData name $ map (applyType' cxt) typs + -- [Ξ“]Ξ± = Ξ± + TVar _ -> typ + -- [Ξ“[Ξ¬=Ο„]]Ξ¬ = [Ξ“[Ξ¬=Ο„]]Ο„ + -- [Ξ“[Ξ¬]]Ξ¬ = [Ξ“[Ξ¬]]Ξ¬ + TEVar tevar -> fromMaybe typ $ findSolved tevar cxt + -- [Ξ“](A β†’ B) = [Ξ“]A β†’ [Ξ“]B + TFun t1 t2 -> on TFun (applyType' cxt) t1 t2 + -- [Ξ“](βˆ€Ξ±. A) = (βˆ€Ξ±. [Ξ“]A) + TAll tvar t -> TAll tvar $ applyType' cxt t + TIdent t -> typ + +applyExp :: T.Exp' Type -> Tc (T.Exp' Type) +applyExp exp = case exp of + T.ELet (T.Bind id vars rhs) exp -> do + id <- apply id + vars' <- mapM apply vars + rhs' <- apply rhs + exp' <- apply exp + pure $ T.ELet (T.Bind id vars' rhs') exp' + T.EApp e1 e2 -> liftA2 T.EApp (apply e1) (apply e2) + T.EAdd e1 e2 -> liftA2 T.EAdd (apply e1) (apply e2) + T.EAbs name e -> T.EAbs name <$> apply e + T.ECase e branches -> liftA2 T.ECase (apply e) + (mapM apply branches) + _ -> pure exp + +applyBranch :: T.Branch' Type -> Tc (T.Branch' Type) +applyBranch (T.Branch (p, t) e) = do + pt <- liftA2 (,) (apply p) (apply t) + e' <- apply e + pure $ T.Branch pt e' + +applyPattern :: T.Pattern' Type -> Tc (T.Pattern' Type) +applyPattern = \case + T.PVar id -> T.PVar <$> apply id + T.PInj name ps -> T.PInj name <$> apply ps + p -> pure p + +applyPair :: (Apply a, Apply b) => (a, b) -> Tc (a, b) +applyPair (x, y) = liftA2 (,) (apply x) (apply y) + +--------------------------------------------------------------------------- +-- * Debug +--------------------------------------------------------------------------- + +traceEnv s = do + env <- gets env + trace (s ++ " " ++ ppEnv env) pure () + +traceD s x = trace (s ++ " " ++ show x) pure () + +traceT s x = trace (s ++ " : " ++ ppT x) pure () + +traceTs s xs = trace (s ++ " [ " ++ intercalate ", " (map ppT xs) ++ " ]") pure () + +ppT = \case + TLit (UIdent s) -> s + TVar (MkTVar (LIdent s)) -> "tvar_" ++ s + TFun t1 t2 -> ppT t1 ++ "->" ++ ppT t2 + TAll (MkTVar (LIdent s)) t -> "forall " ++ s ++ ". " ++ ppT t + TEVar (MkTEVar (LIdent s)) -> "tevar_" ++ s + TData (UIdent name) typs -> name ++ " (" ++ unwords (map ppT typs) + ++ " )" + TIdent (UIdent name) -> name + +ppEnvElem = \case + EnvVar (LIdent s) t -> s ++ ":" ++ ppT t + EnvTVar (MkTVar (LIdent s)) -> "tvar_" ++ s + EnvTEVar (MkTEVar (LIdent s)) -> "tevar_" ++ s + EnvTEVarSolved (MkTEVar (LIdent s)) t -> "tevar_" ++ s ++ "=" ++ ppT t + EnvMark (MkTEVar (LIdent s)) -> "β–Ά" ++ "tevar_" ++ s + +ppEnv = \case + Empty -> "Β·" + (xs :|> x) -> ppEnv xs ++ " (" ++ ppEnvElem x ++ ")" diff --git a/src/TypeChecker/TypeCheckerHm.hs b/src/TypeChecker/TypeCheckerHm.hs new file mode 100644 index 0000000..f4ec70a --- /dev/null +++ b/src/TypeChecker/TypeCheckerHm.hs @@ -0,0 +1,945 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QualifiedDo #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} + +-- | A module for type checking and inference using algorithm W, Hindley-Milner +module TypeChecker.TypeCheckerHm where + +import Auxiliary (int, litType, maybeToRightM, unzip4) +import Auxiliary qualified as Aux +import Control.Monad.Except +import Control.Monad.Identity (Identity, runIdentity) +import Control.Monad.Reader +import Control.Monad.State +import Control.Monad.Writer +import Data.Coerce (coerce) +import Data.Function (on) +import Data.List (foldl', nub, sortOn) +import Data.List.Extra (unsnoc) +import Data.Map (Map) +import Data.Map qualified as M +import Data.Maybe (fromJust) +import Data.Set (Set) +import Data.Set qualified as S +import Debug.Trace (trace, traceShow) +import Grammar.Abs +import Grammar.Print (printTree) +import TypeChecker.TypeCheckerIr qualified as T + +{- +TODO +Prettifying the types of generated variables does only need to be done when +presenting the types to the user, i.e, when the user has made a mistake. +For succesfully typed programs the types only need to match. + +-} + +-- | Type check a program +typecheck :: Program -> Either String (T.Program' Type, [Warning]) +typecheck = onLeft msg . run . checkPrg + where + onLeft :: (Error -> String) -> Either Error a -> Either String a + onLeft f (Left x) = Left $ f x + onLeft _ (Right x) = Right x + +checkPrg :: Program -> Infer (T.Program' Type) +checkPrg (Program bs) = do + preRun bs + -- sgs <- gets sigs + bs <- map snd . sortOn fst <$> bindCount bs + bs <- checkDef bs + -- return . prettify sgs . T.Program $ bs + return . T.Program $ bs + +-- | Send the map of user declared signatures to not rename stuff the user defined +prettify :: Map T.Ident (Maybe Type) -> T.Program' Type -> T.Program' Type +prettify s (T.Program defs) = T.Program $ map (go s) defs + where + go :: Map T.Ident (Maybe Type) -> T.Def' Type -> T.Def' Type + go _ (T.DData d) = T.DData d + go m b@(T.DBind (T.Bind (name, t) args (e, et))) + | Just (Just _) <- M.lookup name m = b + | otherwise = + let fvs = nub $ freeOrdered t + m = M.fromList $ zip fvs letters + in T.DBind $ T.Bind (name, replace m t) args (fmap (replace m) e, replace m et) + +replace :: Map T.Ident T.Ident -> Type -> Type +replace m def@(TVar (MkTVar (LIdent a))) = case M.lookup (coerce a) m of + Just t -> TVar . MkTVar . LIdent $ coerce t + Nothing -> def +replace m (TFun t1 t2) = (TFun `on` replace m) t1 t2 +replace m (TData name ts) = TData name (map (replace m) ts) +replace m def@(TAll (MkTVar forall_) t) = case M.lookup (coerce forall_) m of + Just found -> TAll (MkTVar $ coerce found) (replace m t) + Nothing -> def +replace _ t = t + +bindCount :: [Def] -> Infer [(Int, Def)] +bindCount [] = return [] +bindCount (x : xs) = do + (o, d) <- go x + b <- bindCount xs + return $ (o, d) : b + where + go :: Def -> Infer (Int, Def) + go b@(DBind (Bind _ _ e)) = do + db <- gets declaredBinds + let n = runIdentity $ evalStateT (countBinds db e) mempty + return (n, b) + go (DSig sig) = pure (0, DSig sig) + go (DData data_) = pure (-1, DData data_) + + countBinds :: Set T.Ident -> Exp -> StateT (Set T.Ident) Identity Int + countBinds declared = \case + EVar i -> do + found <- get + if coerce i `S.member` declared && not (coerce i `S.member` found) + then put (S.insert (coerce i) found) >> return 1 + else return 0 + ELet _ e -> countBinds declared e + EApp e1 e2 -> (+) <$> countBinds declared e1 <*> countBinds declared e2 + EAdd e1 e2 -> (+) <$> countBinds declared e1 <*> countBinds declared e2 + EAbs _ e -> countBinds declared e + ECase e1 brnchs -> do + let f (Branch _ e2) = countBinds declared e2 + (+) . sum <$> mapM f brnchs <*> countBinds declared e1 + _ -> return 0 + +preRun :: [Def] -> Infer () +preRun [] = return () +preRun (x : xs) = case x of + DSig (Sig n t) -> do + collect (collectTVars t) + s <- gets (M.keys . sigs) + duplicateDecl n s $ Aux.do + "Multiple signatures of function" + quote $ printTree n + insertSig (coerce n) (Just t) >> preRun xs + DBind (Bind n _ e) -> do + s <- gets (S.toList . declaredBinds) + duplicateDecl n s $ Aux.do + "Multiple declarations of function" + quote $ printTree n + collect (collectTVars e) + insertBind $ coerce n + s <- gets sigs + case M.lookup (coerce n) s of + Nothing -> insertSig (coerce n) Nothing >> preRun xs + Just _ -> preRun xs + DData d@(Data t _) -> collect (collectTVars t) >> checkData d >> preRun xs + where + -- Check if function body / signature has been declared already + duplicateDecl n env msg = when (coerce n `elem` env) (uncatchableErr msg) + +checkDef :: [Def] -> Infer [T.Def' Type] +checkDef [] = return [] +checkDef (x : xs) = case x of + (DBind b) -> do + b' <- checkBind b + xs' <- checkDef xs + return $ T.DBind b' : xs' + (DData d) -> do + xs' <- checkDef xs + return $ T.DData (coerceData d) : xs' + (DSig _) -> checkDef xs + where + coerceData (Data t injs) = + T.Data t $ map (\(Inj name typ) -> T.Inj (coerce name) typ) injs + +freeOrdered :: Type -> [T.Ident] +freeOrdered (TVar (MkTVar a)) = return (coerce a) +freeOrdered (TAll (MkTVar bound) t) = return (coerce bound) ++ freeOrdered t +freeOrdered (TFun a b) = freeOrdered a ++ freeOrdered b +freeOrdered (TData _ a) = concatMap freeOrdered a +freeOrdered _ = mempty + +-- Much cleaner implementation, unfortunately one minor bug +-- checkBind :: Bind -> Infer (T.Bind' Type) +-- checkBind (Bind name args expr) = do +-- fr <- fresh +-- let lambda = makeLambda expr (reverse (coerce args)) +-- withBinding (coerce name) fr $ do +-- (sub, (e, infSig)) <- algoW lambda +-- env <- asks vars +-- let genInfSig = generalize (apply sub env) infSig +-- maybeSig <- gets (join . M.lookup (coerce name) . sigs) +-- case maybeSig of +-- Just typSig -> do +-- unless +-- (genInfSig <<= typSig) +-- ( throwError $ +-- Error +-- ( Aux.do +-- "Inferred type" +-- quote $ printTree infSig +-- "doesn't match given type" +-- quote $ printTree typSig +-- ) +-- False +-- ) +-- return $ T.Bind (coerce name, typSig) [] (apply sub e, typSig) +-- _ -> do +-- insertSig (coerce name) (Just genInfSig) +-- return $ T.Bind (coerce name, genInfSig) [] (apply sub e, genInfSig) + +checkBind :: Bind -> Infer (T.Bind' Type) +checkBind (Bind name args e) = do + let lambda = makeLambda e (reverse (coerce args)) + (e, infSig) <- inferExp lambda + s <- gets sigs + case M.lookup (coerce name) s of + Just (Just typSig) -> do + env <- asks vars + trace ("ENV IN CHECKBIND: " ++ show env) pure () + let genInfSig = generalize mempty infSig + sub <- genInfSig `unify` typSig + unless + (genInfSig <<= typSig) + ( throwError $ + Error + ( Aux.do + "Inferred type" + quote $ printTree infSig + "doesn't match given type" + quote $ printTree typSig + ) + False + ) + -- Applying sub to typSig will worsen error messages. + -- Unfortunately I do not know a better solution at the moment. + return $ T.Bind (coerce name, apply sub typSig) [] (apply sub e, typSig) + _ -> do + insertSig (coerce name) (Just infSig) + return (T.Bind (coerce name, infSig) [] (e, infSig)) + +checkData :: (MonadState Env m, Monad m, MonadError Error m) => Data -> m () +checkData err@(Data typ injs) = do + (name, tvars) <- go (skipForalls typ) + dataErr (mapM_ (\i -> checkInj i name tvars) injs) err + where + go = \case + TData name typs + | Right tvars' <- mapM toTVar typs -> + pure (name, tvars') + _ -> + uncatchableErr $ + unwords ["Bad data type definition: ", printTree typ] + +checkInj :: (MonadError Error m, MonadState Env m, Monad m) => Inj -> UIdent -> [TVar] -> m () +checkInj (Inj c inj_typ) name tvars + | TData name' typs <- returnType inj_typ + , Right tvars' <- mapM toTVar typs + , name' == name + , tvars' == tvars = do + exist <- existInj (coerce c) + case exist of + Just t -> uncatchableErr $ Aux.do + "Constructor" + quote $ coerce name + "with type" + quote $ printTree t + "already exist" + Nothing -> insertInj (coerce c) inj_typ + | otherwise = + uncatchableErr $ + unwords + [ "Bad type constructor: " + , show name + , "\nExpected: " + , printTree . TData name $ map TVar tvars + , "\nActual: " + , printTree $ returnType inj_typ + ] + +toTVar :: Type -> Either Error TVar +toTVar = \case + TVar tvar -> pure tvar + _ -> uncatchableErr "Not a type variable" + +returnType :: Type -> Type +returnType (TFun _ t2) = returnType t2 +returnType a = a + +inferExp :: Exp -> Infer (T.ExpT' Type) +inferExp e = do + (s, (e', t)) <- algoW e + let subbed = apply s t + return (e', subbed) + +class CollectTVars a where + collectTVars :: a -> Set T.Ident + +instance CollectTVars Exp where + collectTVars (EAnn e t) = collectTVars t `S.union` collectTVars e + collectTVars _ = S.empty + +instance CollectTVars Type where + collectTVars (TVar (MkTVar i)) = S.singleton (coerce i) + collectTVars (TAll _ t) = collectTVars t + collectTVars (TFun t1 t2) = (S.union `on` collectTVars) t1 t2 + collectTVars (TData _ ts) = + foldl' (\acc x -> acc `S.union` collectTVars x) S.empty ts + collectTVars _ = S.empty + +collect :: Set T.Ident -> Infer () +collect s = modify (\st -> st{takenTypeVars = s `S.union` takenTypeVars st}) + +algoW :: Exp -> Infer (Subst, T.ExpT' Type) +algoW = \case + err@(EAnn e t) -> do + (sub0, (e', t')) <- exprErr (algoW e) err + sub1 <- unify t t' + sub2 <- unify t' t + unless + (apply sub1 t <<= apply sub2 t') + ( uncatchableErr $ Aux.do + "Annotated type" + quote $ printTree t + "does not match inferred type" + quote $ printTree t' + ) + let comp = sub2 `compose` sub1 `compose` sub0 + return (comp, (apply comp e', t)) + + -- \| ------------------ + -- \| Ξ“ ⊒ i : Int, βˆ… + + ELit lit -> return (nullSubst, (T.ELit lit, litType lit)) + -- \| x : Οƒ ∈ Ξ“   Ο„ = inst(Οƒ) + -- \| ---------------------- + -- \| Ξ“ ⊒ x : Ο„, βˆ… + EVar (LIdent i) -> do + var <- asks vars + case M.lookup (coerce i) var of + Just t -> + inst t >>= \x -> + return (nullSubst, (T.EVar $ coerce i, x)) + Nothing -> do + sig <- gets sigs + case M.lookup (coerce i) sig of + Just (Just t) -> do + t <- freshen t + return (nullSubst, (T.EVar $ coerce i, t)) + Just Nothing -> do + fr <- fresh + return (nullSubst, (T.EVar $ coerce i, fr)) + Nothing -> + uncatchableErr $ + "Unbound variable: " + <> printTree i + EInj i -> do + constr <- gets injections + case M.lookup (coerce i) constr of + Just t -> do + t <- freshen t + return (nullSubst, (T.EInj $ coerce i, t)) + Nothing -> + uncatchableErr $ Aux.do + "Constructor:" + quote $ printTree i + "is not defined" + + -- \| Ο„ = newvar Ξ“, x : Ο„ ⊒ e : Ο„', S + -- \| --------------------------------- + -- \| Ξ“ ⊒ w Ξ»x. e : SΟ„ β†’ Ο„', S + + err@(EAbs name e) -> do + fr <- fresh + withBinding (coerce name) fr $ do + (s1, (e', t')) <- exprErr (algoW e) err + let varType = apply s1 fr + let newArr = TFun varType t' + return (s1, apply s1 (T.EAbs (coerce name) (e', t'), newArr)) + + -- \| Ξ“ ⊒ eβ‚€ : Ο„β‚€, Sβ‚€ Sβ‚€Ξ“ ⊒ e₁ : τ₁, S₁ + -- \| sβ‚‚ = mgu(s₁τ₀, Int) s₃ = mgu(s₂τ₁, Int) + -- \| ------------------------------------------ + -- \| Ξ“ ⊒ eβ‚€ + e₁ : Int, S₃Sβ‚‚S₁Sβ‚€ + -- This might be wrong + + err@(EAdd e0 e1) -> do + (s1, (e0', t0)) <- algoW e0 + (s2, (e1', t1)) <- algoW e1 + s3 <- exprErr (unify t0 int) err + s4 <- exprErr (unify t1 int) err + let comp = s4 `compose` s3 `compose` s2 `compose` s1 + return + ( comp + , apply comp (T.EAdd (e0', t0) (e1', t1), int) + ) + + -- \| Ξ“ ⊒ eβ‚€ : Ο„β‚€, Sβ‚€ Sβ‚€Ξ“ ⊒ e₁ : τ₁, S1 + -- \| Ο„' = newvar Sβ‚‚ = mgu(S₁τ₀, τ₁ β†’ Ο„') + -- \| -------------------------------------- + -- \| Ξ“ ⊒ eβ‚€ e₁ : Sβ‚‚Ο„', Sβ‚‚S₁Sβ‚€ + + EApp e0 e1 -> do + fr <- fresh + (s0, (e0', t0)) <- algoW e0 + applySt s0 $ do + (s1, (e1', t1)) <- algoW e1 + s2 <- unify (apply s1 t0) (TFun t1 fr) + let t = apply s2 fr + let comp = s2 `compose` s1 `compose` s0 + return (comp, apply comp (T.EApp (e0', t0) (e1', t1), t)) + + -- \| Ξ“ ⊒ eβ‚€ : Ο„, Sβ‚€ Sβ‚€Ξ“, x : SΜ…β‚€Ξ“Μ…(Ο„) ⊒ e₁ : Ο„', S₁ + -- \| ---------------------------------------------- + -- \| Ξ“ ⊒ let x = eβ‚€ in e₁ : Ο„', S₁Sβ‚€ + + -- The bar over Sβ‚€ and Ξ“ means "generalize" + + ELet (Bind name args e) e1 -> do + fr <- fresh + withBinding (coerce name) fr $ do + (s1, e@(_, t0)) <- algoW (makeLambda e (coerce args)) + env <- asks vars + let t' = generalize (apply s1 env) t0 + withBinding (coerce name) t' $ do + (s2, (e1', t2)) <- algoW e1 + let comp = s2 `compose` s1 + return + ( comp + , apply + comp + (T.ELet (T.Bind (coerce name, t0) [] e) (e1', t2), t2) + ) + ECase caseExpr injs -> do + (sub, (e', t)) <- algoW caseExpr + (subst, injs, ret_t) <- checkCase t injs + let comp = subst `compose` sub + return (comp, apply comp (T.ECase (e', t) injs, ret_t)) + +checkCase :: Type -> [Branch] -> Infer (Subst, [T.Branch' Type], Type) +checkCase _ [] = do + fr <- fresh + return (nullSubst, [], fr) +checkCase expT brnchs = do + (subs, branchTs, injs, returns) <- unzip4 <$> mapM inferBranch brnchs + let sub0 = composeAll subs + (sub1, _) <- + foldM + ( \(sub, acc) x -> + (\a -> (a `compose` sub, a `apply` acc)) <$> unify x acc + ) + (nullSubst, expT) + branchTs + (sub2, returns_type) <- + foldM + ( \(sub, acc) x -> + (\a -> (a `compose` sub, a `apply` acc)) <$> unify x acc + ) + (nullSubst, head returns) + (tail returns) + let comp = sub2 `compose` sub1 `compose` sub0 + return (comp, apply comp injs, apply comp returns_type) + +inferBranch :: Branch -> Infer (Subst, Type, T.Branch' Type, Type) +inferBranch err@(Branch pat expr) = do + pat@(_, branchT) <- inferPattern pat + (sub, newExp@(_, exprT)) <- catchError (withPattern pat (algoW expr)) (\x -> throwError Error{msg = x.msg <> " in pattern '" <> printTree err <> "'", catchable = False}) + return + ( sub + , apply sub branchT + , T.Branch (apply sub pat) (apply sub newExp) + , apply sub exprT + ) + +inferPattern :: Pattern -> Infer (T.Pattern' Type, Type) +inferPattern = \case + PLit lit -> let lt = litType lit in return (T.PLit lit, lt) + PCatch -> (T.PCatch,) <$> fresh + PVar x -> do + fr <- fresh + let pvar = T.PVar (coerce x) + return (pvar, fr) + PEnum p -> do + t <- gets (M.lookup (coerce p) . injections) + t <- + maybeToRightM + ( Error + ( Aux.do + "Constructor:" + quote $ printTree p + "does not exist" + ) + True + ) + t + unless + (typeLength t == 1) + ( catchableErr $ Aux.do + "The constructor" + quote $ printTree p + " should have " + show (typeLength t - 1) + " arguments but has been given 0" + ) + let (TData _data _ts) = t -- nasty nasty + frs <- mapM (const fresh) _ts + return (T.PEnum $ coerce p, TData _data frs) + PInj constr patterns -> do + t <- gets (M.lookup (coerce constr) . injections) + t <- + maybeToRightM + ( Error + ( Aux.do + "Constructor:" + quote $ printTree constr + "does not exist" + ) + True + ) + t + let numArgs = typeLength t - 1 + let (vs, ret) = fromJust (unsnoc $ flattenType t) + patterns <- mapM inferPattern patterns + unless + (length patterns == numArgs) + ( catchableErr $ Aux.do + "The constructor" + quote $ printTree constr + " should have " + show numArgs + " arguments but has been given " + show (length patterns) + ) + sub <- composeAll <$> zipWithM unify vs (map snd patterns) + return + ( T.PInj (coerce constr) (apply sub patterns) + , apply sub ret + ) + +-- | Unify two types producing a new substitution +unify :: Type -> Type -> Infer Subst +unify t0 t1 = + let fvs = S.toList $ free t0 `S.union` free t1 + m = M.fromList $ zip fvs letters + in case (t0, t1) of + (TFun a b, TFun c d) -> do + s1 <- unify a c + s2 <- unify (apply s1 b) (apply s1 d) + return $ s2 `compose` s1 + (TVar (MkTVar a), t@(TData _ _)) -> return $ M.singleton (coerce a) t + (t@(TData _ _), TVar (MkTVar b)) -> return $ M.singleton (coerce b) t + (TVar (MkTVar a), t) -> occurs (coerce a) t + (t, TVar (MkTVar b)) -> occurs (coerce b) t + -- Forall unification should change + (TAll _ t, b) -> unify t b + (a, TAll _ t) -> unify a t + (TLit a, TLit b) -> + if a == b + then return M.empty + else catchableErr $ + Aux.do + "Can not unify" + quote $ printTree (TLit a) + "with" + quote $ printTree (TLit b) + (TData name t, TData name' t') -> + if name == name' && length t == length t' + then do + xs <- zipWithM unify t t' + return $ foldr compose nullSubst xs + else catchableErr $ + Aux.do + "Type constructor:" + printTree name + quote $ printTree $ map (replace m) t + "does not match with:" + printTree name' + quote $ printTree $ map (replace m) t' + (TEVar a, TEVar b) -> + if a == b + then return M.empty + else catchableErr $ + Aux.do + "Can not unify" + quote $ printTree (TEVar a) + "with" + quote $ printTree (TEVar b) + (a, b) -> do + catchableErr $ + Aux.do + "Can not unify" + quote $ printTree $ replace m a + "with" + quote $ printTree $ replace m b + +{- | Check if a type is contained in another type. +I.E. { a = a -> b } is an unsolvable constraint since there is no substitution +where these are equal +-} +occurs :: T.Ident -> Type -> Infer Subst +occurs i t@(TEVar _) = return (M.singleton i t) +occurs i t@(TVar _) = return (M.singleton i t) +occurs i t = + let fvs = S.toList $ free t + m = M.fromList $ zip fvs letters + in if S.member i (free t) + then + catchableErr + ( Aux.do + "Occurs check failed, can't unify" + quote $ printTree $ replace m (TVar $ MkTVar (coerce i)) + "with" + quote $ printTree $ replace m t + ) + else return $ M.singleton i t + +{- | Generalize a type over all free variables in the substitution set + Used for let bindings to allow expression that do not type check in + equivalent lambda expressions: + Type checks: let f = \x. x in (f True, f 'a') + Does not type check: (\f. (f True, f 'a')) (\x. x) +-} +generalize :: Map T.Ident Type -> Type -> Type +generalize env t = go (S.toList $ free t S.\\ free env) (removeForalls t) + where + go :: [T.Ident] -> Type -> Type + go [] t = t + go (x : xs) t = TAll (MkTVar (coerce x)) (go xs t) + removeForalls :: Type -> Type + removeForalls (TAll _ t) = removeForalls t + removeForalls (TFun t1 t2) = TFun (removeForalls t1) (removeForalls t2) + removeForalls t = t + +{- | Instantiate a polymorphic type. The free type variables are substituted +with fresh ones. +-} +inst :: Type -> Infer Type +inst = \case + TAll (MkTVar bound) t -> do + fr <- fresh + let s = M.singleton (coerce bound) fr + apply s <$> inst t + TFun t1 t2 -> TFun <$> inst t1 <*> inst t2 + rest -> return rest + +-- | Generate a new fresh variable +fresh :: Infer Type +fresh = do + n <- gets count + modify (\st -> st{count = succ (count st)}) + return $ TVar $ MkTVar $ LIdent $ show n + +-- Is the left a subtype of the right +(<<=) :: Type -> Type -> Bool +(<<=) a b = case (a, b) of + (TVar _, _) -> True + (TFun a b, TFun c d) -> a <<= c && b <<= d + (TAll tvar1 t1, TAll tvar2 t2) -> ungo [tvar1, tvar2] t1 t2 + (TAll tvar t1, t2) -> ungo [tvar] t1 t2 + (t1, TAll tvar t2) -> ungo [tvar] t1 t2 + (TData n1 ts1, TData n2 ts2) -> + n1 == n2 + && length ts1 == length ts2 + && and (zipWith (<<=) ts1 ts2) + (t1, t2) -> t1 == t2 + where + ungo :: [TVar] -> Type -> Type -> Bool + ungo tvars t1 t2 = case run (go tvars t1 t2) of + Right (b, _) -> b + _ -> False + -- TODO: Fix the following + -- Maybe locally using the Infer monad can cause trouble. + -- Since the fresh count starts from zero + go :: [TVar] -> Type -> Type -> Infer Bool + go tvars t1 t2 = do + fr <- fresh + let sub = M.fromList [(coerce x, fr) | (MkTVar x) <- tvars] + return (apply sub t1 <<= apply sub t2) + +skipForalls :: Type -> Type +skipForalls = \case + TAll _ t -> skipForalls t + t -> t + +freshen :: Type -> Infer Type +freshen t = do + let frees = S.toList (free t) + xs <- mapM (const fresh) frees + let sub = M.fromList $ zip frees xs + return $ apply sub t + +{- + +a = TVar $ MkTVar "a" +single = TData "single" [a] +arr = a `TFun` single + +-} + +-- | A class for substitutions +class SubstType t where + -- | Apply a substitution to t + apply :: Subst -> t -> t + +class FreeVars t where + -- | Get all free variables from t + free :: t -> Set T.Ident + +instance FreeVars (T.Bind' Type) where + free (T.Bind (_, t) _ _) = free t + +instance FreeVars Type where + free :: Type -> Set T.Ident + free (TVar (MkTVar a)) = S.singleton (coerce a) + free (TAll (MkTVar bound) t) = + S.singleton (coerce bound) `S.intersection` free t + free (TLit _) = mempty + free (TFun a b) = free a `S.union` free b + free (TData _ a) = free a + free (TEVar _) = S.empty + +instance FreeVars a => FreeVars [a] where + free = let f acc x = acc `S.union` free x in foldl' f S.empty + +instance SubstType Type where + apply :: Subst -> Type -> Type + apply sub t = do + case t of + TLit _ -> t + TVar (MkTVar a) -> case M.lookup (coerce a) sub of + Nothing -> TVar (MkTVar $ coerce a) + Just t -> t + TAll (MkTVar i) t -> case M.lookup (coerce i) sub of + Nothing -> TAll (MkTVar i) (apply sub t) + Just _ -> apply sub t + TFun a b -> TFun (apply sub a) (apply sub b) + TData name a -> TData name (apply sub a) + TEVar (MkTEVar _) -> t + +instance FreeVars (Map T.Ident Type) where + free :: Map T.Ident Type -> Set T.Ident + free = free . M.elems + +instance SubstType (Map T.Ident Type) where + apply :: Subst -> Map T.Ident Type -> Map T.Ident Type + apply = M.map . apply + +instance SubstType (Map T.Ident (Maybe Type)) where + apply s = M.map (fmap $ apply s) + +instance SubstType (T.ExpT' Type) where + apply s (e, t) = (apply s e, apply s t) + +instance SubstType (T.Exp' Type) where + apply s = \case + T.EVar i -> T.EVar i + T.ELit lit -> T.ELit lit + T.ELet (T.Bind (ident, t1) args e1) e2 -> + T.ELet + (T.Bind (ident, apply s t1) args (apply s e1)) + (apply s e2) + T.EApp e1 e2 -> T.EApp (apply s e1) (apply s e2) + T.EAdd e1 e2 -> T.EAdd (apply s e1) (apply s e2) + T.EAbs ident e -> T.EAbs ident (apply s e) + T.ECase e brnch -> T.ECase (apply s e) (apply s brnch) + T.EInj i -> T.EInj i + +instance SubstType (T.Def' Type) where + apply s = \case + T.DBind (T.Bind name args e) -> + T.DBind $ T.Bind (apply s name) (apply s args) (apply s e) + d -> d + +instance SubstType (T.Branch' Type) where + apply s (T.Branch (i, t) e) = T.Branch (apply s i, apply s t) (apply s e) + +instance SubstType (T.Pattern' Type) where + apply s = \case + T.PVar iden -> T.PVar iden + T.PLit lit -> T.PLit lit + T.PInj i ps -> T.PInj i $ apply s ps + T.PCatch -> T.PCatch + T.PEnum i -> T.PEnum i + +instance SubstType (T.Pattern' Type, Type) where + apply s (p, t) = (apply s p, apply s t) + +instance SubstType a => SubstType [a] where + apply s = map (apply s) + +instance SubstType (T.Id' Type) where + apply s (name, t) = (name, apply s t) + +-- | Represents the empty substition set +nullSubst :: Subst +nullSubst = mempty + +-- | Compose two substitution sets +compose :: Subst -> Subst -> Subst +compose m1 m2 = M.map (apply m1) m2 `M.union` m1 + +-- | Compose a list of substitution sets into one +composeAll :: [Subst] -> Subst +composeAll = foldl' compose nullSubst + +{- | Convert a function with arguments to its pointfree version +> makeLambda (add x y = x + y) = add = \x. \y. x + y +-} +makeLambda :: Exp -> [T.Ident] -> Exp +makeLambda = foldl (flip (EAbs . coerce)) + +-- | Run the monadic action with an additional binding +withBinding :: (Monad m, MonadReader Ctx m) => T.Ident -> Type -> m a -> m a +withBinding i p = local (\st -> st{vars = M.insert i p (vars st)}) + +-- | Run the monadic action with several additional bindings +withBindings :: (Monad m, MonadReader Ctx m) => [(T.Ident, Type)] -> m a -> m a +withBindings xs = + local (\st -> st{vars = foldl' (flip (uncurry M.insert)) (vars st) xs}) + +-- | Run the monadic action with a pattern +withPattern :: (Monad m, MonadReader Ctx m) => (T.Pattern' Type, Type) -> m a -> m a +withPattern (p, t) ma = case p of + T.PVar x -> withBinding x t ma + T.PInj _ ps -> foldl' (flip withPattern) ma ps + T.PLit _ -> ma + T.PCatch -> ma + T.PEnum _ -> ma + +-- | Insert a function signature into the environment +insertSig :: T.Ident -> Maybe Type -> Infer () +insertSig i t = modify (\st -> st{sigs = M.insert i t (sigs st)}) + +insertBind :: T.Ident -> Infer () +insertBind i = modify (\st -> st{declaredBinds = S.insert i st.declaredBinds}) + +-- | Insert a constructor into the start with its type +insertInj :: (Monad m, MonadState Env m) => T.Ident -> Type -> m () +insertInj i t = + modify (\st -> st{injections = M.insert i t (injections st)}) + +applySt :: Subst -> Infer a -> Infer a +applySt s = local (\st -> st{vars = apply s st.vars}) + +{- | Check if an injection (constructor of data type) +with an equivalent name has been declared already +-} +existInj :: (Monad m, MonadState Env m) => T.Ident -> m (Maybe Type) +existInj n = gets (M.lookup n . injections) + +flattenType :: Type -> [Type] +flattenType (TFun a b) = flattenType a <> flattenType b +flattenType a = [a] + +typeLength :: Type -> Int +typeLength (TFun _ b) = 1 + typeLength b +typeLength _ = 1 + +{- | Catch an error if possible and add the given +expression as addition to the error message +-} +exprErr :: (Monad m, MonadError Error m) => m a -> Exp -> m a +exprErr ma exp = + catchError + ma + ( \err -> + if err.catchable + then + throwError + ( err + { msg = + err.msg + <> " in expression: \n" + <> printTree exp + , catchable = False + } + ) + else throwError err + ) + +bindErr :: (Monad m, MonadError Error m) => m a -> Bind -> m a +bindErr ma bind = + catchError + ma + ( \err -> + if err.catchable + then + throwError + ( err + { msg = + err.msg + <> " in function: \n" + <> printTree bind + , catchable = False + } + ) + else throwError err + ) + +{- | Catch an error if possible and add the given +data as addition to the error message +-} +dataErr :: (MonadError Error m, Monad m) => m a -> Data -> m a +dataErr ma d = + catchError + ma + ( \err -> + if err.catchable + then + throwError + ( err + { msg = + err.msg + <> " in data: \n" + <> printTree d + } + ) + else throwError (err{catchable = False}) + ) + +initCtx = Ctx mempty +initEnv = Env 0 'a' mempty mempty mempty mempty + +run :: Infer a -> Either Error (a, [Warning]) +run = run' initEnv initCtx + +run' :: Env -> Ctx -> Infer a -> Either Error (a, [Warning]) +run' e c = + runIdentity + . runExceptT + . runWriterT + . flip runReaderT c + . flip evalStateT e + . runInfer + +newtype Ctx = Ctx {vars :: Map T.Ident Type} + deriving (Show) + +data Env = Env + { count :: Int + , nextChar :: Char + , sigs :: Map T.Ident (Maybe Type) + , takenTypeVars :: Set T.Ident + , injections :: Map T.Ident Type + , declaredBinds :: Set T.Ident + } + deriving (Show) + +data Error = Error {msg :: String, catchable :: Bool} + deriving (Show) +type Subst = Map T.Ident Type + +newtype Warning = NonExhaustive String + deriving (Show) + +newtype Infer a = Infer {runInfer :: StateT Env (ReaderT Ctx (WriterT [Warning] (ExceptT Error Identity))) a} + deriving (Functor, Applicative, Monad, MonadReader Ctx, MonadError Error, MonadState Env) + +catchableErr :: MonadError Error m => String -> m a +catchableErr msg = throwError $ Error msg True + +uncatchableErr :: MonadError Error m => String -> m a +uncatchableErr msg = throwError $ Error msg False + +quote :: String -> String +quote s = "'" ++ s ++ "'" + +letters :: [T.Ident] +letters = map T.Ident $ [1 ..] >>= flip replicateM ['a' .. 'z'] diff --git a/src/TypeChecker/TypeCheckerIr.hs b/src/TypeChecker/TypeCheckerIr.hs new file mode 100644 index 0000000..a956ff3 --- /dev/null +++ b/src/TypeChecker/TypeCheckerIr.hs @@ -0,0 +1,196 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE PatternSynonyms #-} + +module TypeChecker.TypeCheckerIr ( + module Grammar.Abs, + module TypeChecker.TypeCheckerIr, +) where + +import Data.String (IsString) +import Grammar.Abs (Lit (..)) +import Grammar.Print +import Prelude +import qualified Prelude as C (Eq, Ord, Read, Show) + +newtype Program' t = Program [Def' t] + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +data Def' t + = DBind (Bind' t) + | DData (Data' t) + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +data Type + = TLit Ident + | TVar TVar + | TData Ident [Type] + | TFun Type Type + deriving (Eq, Ord, Show, Read) + +data Data' t = Data t [Inj' t] + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +data Inj' t = Inj Ident t + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +newtype Ident = Ident String + deriving (C.Eq, C.Ord, C.Show, C.Read, IsString) + +data Pattern' t + = PVar Ident + | PLit Lit + | PCatch + | PEnum Ident + | PInj Ident [(Pattern' t, t)] + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +data Exp' t + = EVar Ident + | EInj Ident + | ELit Lit + | ELet (Bind' t) (ExpT' t) + | EApp (ExpT' t) (ExpT' t) + | EAdd (ExpT' t) (ExpT' t) + | EAbs Ident (ExpT' t) + | ECase (ExpT' t) [Branch' t] + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +newtype TVar = MkTVar Ident + deriving (C.Eq, C.Ord, C.Show, C.Read) + +type Id' t = (Ident, t) +type ExpT' t = (Exp' t, t) + +data Bind' t = Bind (Id' t) [Id' t] (ExpT' t) + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +data Branch' t = Branch (Pattern' t, t) (ExpT' t) + deriving (C.Eq, C.Ord, C.Show, C.Read, Functor) + +instance Print Ident where + prt _ (Ident s) = doc $ showString s + +instance Print t => Print (Program' t) where + prt i (Program sc) = prt i sc + +instance Print t => Print (Bind' t) where + prt i (Bind sig parms rhs) = concatD + [ prtSig sig + , prt i parms + , doc $ showString "=" + , prt i rhs + ] + +prtSig :: Print t => Id' t -> Doc +prtSig (name, t) = + concatD + [ prt 0 name + , doc $ showString ":" + , prt 0 t + ] + +instance Print t => Print (ExpT' t) where + prt i (e, t) = + concatD + [ doc $ showString "(" + , prt i e + , doc $ showString ":" + , prt 0 t + , doc $ showString ")" + ] + +instance Print t => Print [Bind' t] where + prt _ [] = concatD [] + prt i [x] = concatD [prt i x] + prt i (x : xs) = concatD [prt i x, doc (showString ";"), prt i xs] + +instance Print t => Print (Id' t) where + prt i (name, t) = + concatD + [ doc $ showString "(" + , prt i name + , doc $ showString "," + , prt i t + , doc $ showString ")" + ] + +instance Print t => Print (Exp' t) where + prt i = \case + EVar lident -> prPrec i 3 (concatD [prt 0 lident]) + EInj uident -> prPrec i 3 (concatD [prt 0 uident]) + ELit lit -> prPrec i 3 (concatD [prt 0 lit]) + EApp exp1 exp2 -> prPrec i 2 (concatD [prt 2 exp1, prt 3 exp2]) + EAdd exp1 exp2 -> prPrec i 1 (concatD [prt 1 exp1, doc (showString "+"), prt 2 exp2]) + ELet bind exp -> prPrec i 0 (concatD [doc (showString "let"), prt 0 bind, doc (showString "in"), prt 0 exp]) + EAbs lident exp -> prPrec i 0 (concatD [doc (showString "\\"), prt 0 lident, doc (showString "."), prt 0 exp]) + ECase exp branchs -> prPrec i 0 (concatD [doc (showString "case"), prt 0 exp, doc (showString "of"), doc (showString "{"), prt 0 branchs, doc (showString "}")]) + +instance Print t => Print (Branch' t) where + prt i (Branch (pattern_, t) exp) = prPrec i 0 (concatD [doc (showString "("), prt 0 pattern_, doc (showString " : "), prt 0 t, doc (showString ")"), doc (showString "=>"), prt 0 exp]) + +instance Print t => Print [Branch' t] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print t => Print (Def' t) where + prt i = \case + DBind bind -> prPrec i 0 (concatD [prt 0 bind]) + DData data_ -> prPrec i 0 (concatD [prt 0 data_]) + +instance Print t => Print (Data' t) where + prt i = \case + Data type_ injs -> prPrec i 0 (concatD [doc (showString "data"), prt 0 type_, doc (showString "where"), doc (showString "{"), prt 0 injs, doc (showString "}")]) + +instance Print t => Print (Inj' t) where + prt i = \case + Inj uident type_ -> prPrec i 0 (concatD [prt 0 uident, doc (showString ":"), prt 0 type_]) + +instance Print t => Print [Inj' t] where + prt _ [] = concatD [] + prt i [x] = prt i x + prt i (x : xs) = prPrec i 0 $ concatD [prt i x, doc $ showString "\n ", prt i xs] + +instance Print t => Print (Pattern' t, t) where + prt i (p, t) = prPrec i 1 (concatD [prt i p, prt i t]) + +instance Print t => Print (Pattern' t) where + prt i = \case + PVar name -> prPrec i 1 (concatD [prt 0 name]) + PLit lit -> prPrec i 1 (concatD [prt 0 lit]) + PCatch -> prPrec i 1 (concatD [doc (showString "_")]) + PEnum name -> prPrec i 1 (concatD [prt 0 name]) + PInj uident patterns -> prPrec i 0 (concatD [prt 0 uident, prt 1 patterns]) + +instance Print t => Print [Def' t] where + prt _ [] = concatD [] + prt _ [x] = concatD [prt 0 x] + prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] + +instance Print [Type] where + prt _ [] = concatD [] + prt _ (x : xs) = concatD [prt 0 x, doc (showString " "), prt 0 xs] + +instance Print Type where + prt i = \case + TLit uident -> prPrec i 1 (concatD [prt 0 uident]) + TVar tvar -> prPrec i 1 (concatD [prt 0 tvar]) + TData uident types -> prPrec i 1 (concatD [prt 0 uident, doc (showString "("), prt 0 types, doc (showString ")")]) + TFun type_1 type_2 -> prPrec i 0 (concatD [prt 1 type_1, doc (showString "->"), prt 0 type_2]) + +instance Print TVar where + prt i (MkTVar ident) = prt i ident + +type Program = Program' Type +type Def = Def' Type +type Data = Data' Type +type Bind = Bind' Type +type Branch = Branch' Type +type Pattern = Pattern' Type +type Inj = Inj' Type +type Exp = Exp' Type +type ExpT = ExpT' Type +type Id = Id' Type +pattern TVar' s = TVar (MkTVar s) +pattern DBind' id vars expt = DBind (Bind id vars expt) +pattern DData' typ injs = DData (Data typ injs) diff --git a/src/TypeCheckerIr.hs b/src/TypeCheckerIr.hs deleted file mode 100644 index f6e3ec6..0000000 --- a/src/TypeCheckerIr.hs +++ /dev/null @@ -1,100 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module TypeCheckerIr - ( module Grammar.Abs - , module TypeCheckerIr - ) where - -import Grammar.Abs (Ident (..), Type (..)) -import Grammar.Print -import Prelude -import qualified Prelude as C (Eq, Ord, Read, Show) - -newtype Program = Program [Bind] - deriving (C.Eq, C.Ord, C.Show, C.Read) - -data Exp - = EId Id - | EInt Integer - | ELet Bind Exp - | EApp Type Exp Exp - | EAdd Type Exp Exp - | EAbs Type Id Exp - deriving (C.Eq, C.Ord, C.Show, C.Read) - -type Id = (Ident, Type) - -data Bind = Bind Id [Id] Exp - deriving (C.Eq, C.Ord, C.Show, C.Read) - -instance Print Program where - prt i (Program sc) = prPrec i 0 $ prt 0 sc - -instance Print Bind where - prt i (Bind name@(n, _) parms rhs) = prPrec i 0 $ concatD - [ prtId 0 name - , doc $ showString ";" - , prt 0 n - , prtIdPs 0 parms - , doc $ showString "=" - , prt 0 rhs - ] - -instance Print [Bind] where - prt _ [] = concatD [] - prt _ [x] = concatD [prt 0 x] - prt _ (x:xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs] - -prtIdPs :: Int -> [Id] -> Doc -prtIdPs i = prPrec i 0 . concatD . map (prtIdP i) - -prtId :: Int -> Id -> Doc -prtId i (name, t) = prPrec i 0 $ concatD - [ prt 0 name - , doc $ showString ":" - , prt 0 t - ] - -prtIdP :: Int -> Id -> Doc -prtIdP i (name, t) = prPrec i 0 $ concatD - [ doc $ showString "(" - , prt 0 name - , doc $ showString ":" - , prt 0 t - , doc $ showString ")" - ] - - -instance Print Exp where - prt i = \case - EId n -> prPrec i 3 $ concatD [prtIdP 0 n] - EInt i1 -> prPrec i 3 $ concatD [prt 0 i1] - ELet bs e -> prPrec i 3 $ concatD - [ doc $ showString "let" - , prt 0 bs - , doc $ showString "in" - , prt 0 e - ] - EApp t e1 e2 -> prPrec i 2 $ concatD - [ doc $ showString "@" - , prt 0 t - , prt 2 e1 - , prt 3 e2 - ] - EAdd t e1 e2 -> prPrec i 1 $ concatD - [ doc $ showString "@" - , prt 0 t - , prt 1 e1 - , doc $ showString "+" - , prt 2 e2 - ] - EAbs t n e -> prPrec i 0 $ concatD - [ doc $ showString "@" - , prt 0 t - , doc $ showString "\\" - , prtIdP 0 n - , doc $ showString "." - , prt 0 e - ] - - diff --git a/test_program.crf b/test_program.crf new file mode 100644 index 0000000..6e528dc --- /dev/null +++ b/test_program.crf @@ -0,0 +1,30 @@ +-- Peano naturals +data Nat where + Zero : Nat + Succ : Nat -> Nat + +toInt : Nat -> Int +toInt a = case a of + Succ n => 1 + toInt n + Zero => 0 + +fromInt a = case a of + 0 => Zero + n => Succ (fromInt (a - 1)) + +-- Peano arithmetic -- + +-- Peano addition +add : Nat -> Nat -> Nat +add left right = case left of + Zero => right + Succ n => Succ (add n right) + +-- Peano multiplication +mul : Nat -> Nat -> Nat +mul left right = case right of + Zero => Zero + Succ n => add left (mul left n) + +-- Returns 10_000 +main = toInt (mul (fromInt 100) (fromInt 100)) diff --git a/tests/DoStrings.hs b/tests/DoStrings.hs new file mode 100644 index 0000000..73580f8 --- /dev/null +++ b/tests/DoStrings.hs @@ -0,0 +1,4 @@ +module DoStrings where + +(>>) str1 str2 = str1 ++ "\n" ++ str2 +(>>=) str1 f = f str1 diff --git a/tests/Main.hs b/tests/Main.hs new file mode 100644 index 0000000..da4acf7 --- /dev/null +++ b/tests/Main.hs @@ -0,0 +1,16 @@ +module Main where + +import Test.Hspec +import TestAnnForall (testAnnForall) +import TestRenamer (testRenamer) +import TestReportForall (testReportForall) +import TestTypeCheckerBidir (testTypeCheckerBidir) +import TestTypeCheckerHm (testTypeCheckerHm) + +main = hspec $ do + testReportForall + testAnnForall + testRenamer + testTypeCheckerBidir + testTypeCheckerHm + diff --git a/tests/TestAnnForall.hs b/tests/TestAnnForall.hs new file mode 100644 index 0000000..9280f33 --- /dev/null +++ b/tests/TestAnnForall.hs @@ -0,0 +1,128 @@ +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE QualifiedDo #-} +{-# HLINT ignore "Use camelCase" #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +module TestAnnForall (testAnnForall, test) where + +import AnnForall (annotateForall) +import Control.Monad ((<=<)) +import Desugar.Desugar (desugar) +import DoStrings qualified as D +import Grammar.ErrM (Err, pattern Bad, pattern Ok) +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import Test.Hspec ( + describe, + hspec, + shouldBe, + shouldNotSatisfy, + shouldSatisfy, + shouldThrow, + specify, + ) +import TypeChecker.ReportTEVar (reportTEVar) +import TypeChecker.TypeChecker (TypeChecker (Bi, Hm)) +import TypeChecker.TypeCheckerBidir (typecheck) +import TypeChecker.TypeCheckerIr qualified as T + +test = hspec testAnnForall + +testAnnForall = describe "Test AnnForall" $ do + ann_data1 + ann_data2 + ann_bad_data1 + ann_bad_data2 + ann_bad_data3 + ann_sig1 + ann_sig2 + ann_bind + +ann_data1 = + specify "Annotate data type" $ + D.do + "data Either a b where" + " Left : a -> Either a b" + " Right : b -> Either a b" + `shouldBePrg` D.do + "data forall a. forall b. Either a b where" + " Left : a -> Either a b" + " Right : b -> Either a b" + +ann_data2 = + specify "Annotate constructor with additional type variable" $ + D.do + "data forall a. forall b. Either a b where" + " Left : c -> a -> Either a b" + " Right : b -> Either a b" + `shouldBePrg` D.do + "data forall a. forall b. Either a b where" + " Left : forall c. c -> a -> Either a b" + " Right : b -> Either a b" + +ann_bad_data1 = + specify "Bad data type variables" $ + D.do + "data Either Int b where" + " Left : a -> Either a b" + " Right : b -> Either a b" + `shouldBeErr` "Misformed data declaration: Non type variable argument" + +ann_bad_data2 = + specify "Bad data identifer" $ + D.do + "data Int -> Either a b where" + " Left : a -> Either a b" + " Right : b -> Either a b" + `shouldBeErr` "Misformed data declaration" + +ann_bad_data3 = + specify "Constructor forall duplicate" $ + D.do + "data Int -> Either a b where" + " Left : forall a. a -> Either a b" + " Right : b -> Either a b" + `shouldBeErr` "Misformed data declaration" + +ann_sig1 = + specify "Annotate signature" $ + "f : a -> b -> (forall a. a -> a) -> a" + `shouldBePrg` "f : forall a. forall b. a -> b -> (forall a. a -> a) -> a" + +ann_sig2 = + specify "Annotate signature 2" $ + D.do + "const : forall a. forall b. a -> b -> a" + "const x y = x" + "main = const 'a' 65" + `shouldBePrg` D.do + "const : forall a. forall b. a -> b -> a" + "const x y = x" + "main = const 'a' 65" + +ann_bind = + specify "Annotate bind" $ + "f = (\\x.\\y. x : a -> b -> a) 4" + `shouldBePrg` "f = (\\x.\\y. x : forall a. forall b. a -> b -> a) 4" + +shouldBeErr s err = run s `shouldBe` Bad err + +shouldBePrg s1 s2 + | Ok p2 <- run' s2 = run s1 `shouldBe` Ok p2 + | otherwise = error ("Faulty expectation \n" ++ show (run' s2)) + +run = annotateForall <=< run' +run' s = do + p <- run'' s + reportForall Bi p + pure p +run'' = fmap desugar . pProgram . resolveLayout True . myLexer + +runPrint = (putStrLn . either show printTree . run) $ + D.do + "data forall a. forall b. Either a b where" + " Left : c -> a -> Either a b" + " Right : b -> Either a b" diff --git a/tests/TestLambdaLifter.hs b/tests/TestLambdaLifter.hs new file mode 100644 index 0000000..d10e7ee --- /dev/null +++ b/tests/TestLambdaLifter.hs @@ -0,0 +1,106 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE QualifiedDo #-} +{-# HLINT ignore "Use camelCase" #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +module TestLambdaLifter where + +import Test.Hspec + +import AnnForall (annotateForall) +import Control.Monad ((<=<)) +import Control.Monad.Error.Class (liftEither) +import Control.Monad.Extra (eitherM) +import Desugar.Desugar (desugar) +import Grammar.ErrM (Err, pattern Bad, pattern Ok) +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import LambdaLifter +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import TypeChecker.RemoveForall (removeForall) +import TypeChecker.ReportTEVar (reportTEVar) +import TypeChecker.TypeChecker (TypeChecker (Bi)) +import TypeChecker.TypeCheckerBidir (typecheck) +import TypeChecker.TypeCheckerIr + +test = hspec testLambdaLifter + +testLambdaLifter = describe "Test Lambda Lifter" $ do + undefined + +-- frees_exp1 + +-- frees_exp1 = specify "Free variables 1" $ +-- freeVarsExp [] (EAbs "x" (EVar "x", TVar' "a"), TVar' "a") +-- `shouldBe` answer +-- where +-- answer = Ann { frees = [] +-- , term = (AAbs (Ident "x") (Ann { frees = [Ident "x"] +-- , term = (AVar (Ident "x"),TVar (MkTVar (Ident "a"))) +-- } +-- ),TVar (MkTVar (Ident "a"))) +-- } + +abs_1 = undefined + where + input = + unlines + [ "data List a where" + , " Nil : List a" + , " Cons : a -> List a -> List a" + , "map : (a -> b) -> List a -> List b" + , "add : Int -> Int -> Int" + , "f : List Int" + , "f = (\\x.\\ys. map (\\y. add y x) ys) 4 (Cons 1 (Cons 2 Nil))" + ] + +runFreeVars = either putStrLn print (runFree s2) +runAbstract = either putStrLn (putStrLn . printTree) (runAbs s2) +runCollect = either putStrLn (putStrLn . printTree) (run s2) + +s1 = + unlines + [ "add : Int -> Int -> Int" + , "f : Int -> Int -> Int" + , "f x y = add x y" + , "f = \\x. (\\y. add x y)" + ] + +s2 = + unlines + [ "data List a where" + , " Nil : List (a)" + , " Cons : a -> List a -> List a" + , "add : Int -> Int -> Int" + , "map : (a -> b) -> List a -> List b" + , -- , "map f xs = case xs of" + -- , " Nil => Nil" + -- , " Cons x xs => Cons (f x) (map f xs)" + + "f : List Int" + , "f = (\\x.\\ys. map (\\y. add y x) ys) 4 (Cons 1 (Cons 2 Nil))" + ] + +s3 = "main = (\\plussq. (\\f. f (f 0)) (plussq 3)) (\\x. \\y. y + x + x)" + +run = fmap collectScs . runAbs + +runAbs = fmap abstract . runFree + +runFree s = do + Program ds <- run' s + pure $ freeVars [b | DBind b <- ds] + +run' = + fmap removeForall + . reportTEVar + <=< typecheck + <=< run'' + +run'' s = do + p <- (fmap desugar . pProgram . resolveLayout True . myLexer) s + reportForall Bi p + (rename <=< annotateForall) p diff --git a/tests/TestRenamer.hs b/tests/TestRenamer.hs new file mode 100644 index 0000000..dc71d38 --- /dev/null +++ b/tests/TestRenamer.hs @@ -0,0 +1,114 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE QualifiedDo #-} +{-# HLINT ignore "Use camelCase" #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +module TestRenamer (testRenamer, test, runPrint) where + +import AnnForall (annotateForall) +import Control.Exception ( + ErrorCall (ErrorCall), + Exception (displayException), + SomeException (SomeException), + evaluate, + try, + ) +import Control.Exception.Extra (try_) +import Control.Monad (unless, (<=<)) +import Control.Monad.Except (throwError) +import Data.Either.Extra (fromEither) +import Desugar.Desugar (desugar) +import DoStrings qualified as D +import GHC.Generics (Generic, Generic1) +import Grammar.Abs (Program (Program)) +import Grammar.ErrM (Err, pattern Bad, pattern Ok) +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import Renamer.Renamer (rename) +import System.IO.Error (catchIOError, tryIOError) +import Test.Hspec ( + anyErrorCall, + anyException, + describe, + hspec, + shouldBe, + shouldNotSatisfy, + shouldReturn, + shouldSatisfy, + shouldThrow, + specify, + ) +import TypeChecker.ReportTEVar (reportTEVar) +import TypeChecker.TypeCheckerBidir (typecheck) +import TypeChecker.TypeCheckerIr qualified as T + +-- FIXME tests sucks + +test = hspec testRenamer + +testRenamer = describe "Test Renamer" $ do + rn_data1 + rn_data2 + rn_sig + rn_bind1 + rn_bind2 + +rn_data1 = specify "Rename data type" . shouldSatisfyOk $ + D.do + "data forall a. forall b. Either a b where" + " Left : a -> Either a b" + " Right : b -> Either a b" + +rn_data2 = specify "Rename data type forall in constructor " . shouldSatisfyOk $ + D.do + "data forall a. forall b. Either a b where" + " Left : forall c. c -> a -> Either a b" + " Right : b -> Either a b" + +rn_sig = + specify "Rename signature" $ + shouldSatisfyOk + "f : forall a. forall b. a -> b -> (forall a. a -> a) -> a" + +rn_bind1 = + specify "Rename simple bind" $ + shouldSatisfyOk + "f x = (\\y. let y2 = y + 1 in y2) (x + 1)" + +rn_bind2 = specify "Rename bind with case" . shouldSatisfyOk $ + D.do + "data forall a. List a where" + " Nil : List a " + " Cons : a -> List a -> List a" + + "length : forall a. List a -> Int" + "length list = case list of" + " Nil => 0" + " Cons x Nil => 1" + " Cons x (Cons y ys) => 2 + length ys" + +runPrint = putStrLn . either show printTree . run $ + D.do + "data forall a. List a where" + " Nil : List a " + " Cons : a -> List a -> List a" + + "length : forall a. List a -> Int" + "length list = case list of" + " Nil => 0" + " Cons x Nil => 1" + " Cons x (Cons y ys) => 2 + length ys" + +shouldSatisfyOk s = run s `shouldSatisfy` ok + +ok = \case + Ok !_ -> True + Bad !_ -> False + +shouldBeErr s err = run s `shouldBe` Bad err + +run = rename <=< run' +run' = fmap desugar . pProgram . resolveLayout True . myLexer diff --git a/tests/TestReportForall.hs b/tests/TestReportForall.hs new file mode 100644 index 0000000..2d3371d --- /dev/null +++ b/tests/TestReportForall.hs @@ -0,0 +1,54 @@ +{-# LANGUAGE PatternSynonyms #-} +{-# HLINT ignore "Use camelCase" #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +module TestReportForall (testReportForall, test) where + +import AnnForall (annotateForall) +import Control.Monad ((<=<)) +import Desugar.Desugar (desugar) +import DoStrings qualified as D +import Grammar.ErrM (Err, pattern Bad, pattern Ok) +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import Test.Hspec ( + describe, + hspec, + shouldBe, + shouldNotSatisfy, + shouldSatisfy, + shouldThrow, + specify, + ) +import TypeChecker.TypeChecker (TypeChecker (Bi, Hm)) + +testReportForall = describe "Test ReportForall" $ do + rp_unused1 + rp_unused2 + rp_forall + +test = hspec testReportForall + +rp_unused1 = + specify "Unused forall 1" $ + "g : forall a. forall a. a -> (forall a. a -> a) -> a" + `shouldBeErrBi` "Unused forall" + +rp_unused2 = + specify "Unused forall 2" $ + "g : forall a. (forall a. a -> a) -> Int" + `shouldBeErrBi` "Unused forall" + +rp_forall = + specify "Rank2 forall with Hm" $ + "f : a -> b -> (forall a. a -> a) -> a" + `shouldBeErrHm` "Higher rank forall not allowed" + +shouldBeErrBi = shouldBeErr Bi +shouldBeErrHm = shouldBeErr Hm +shouldBeErr tc s err = run tc s `shouldBe` Bad err + +run tc = reportForall tc <=< fmap desugar . pProgram . resolveLayout True . myLexer diff --git a/tests/TestTypeCheckerBidir.hs b/tests/TestTypeCheckerBidir.hs new file mode 100644 index 0000000..15e0c1f --- /dev/null +++ b/tests/TestTypeCheckerBidir.hs @@ -0,0 +1,333 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} +{-# HLINT ignore "Use camelCase" #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +module TestTypeCheckerBidir (test, testTypeCheckerBidir) where + +import Test.Hspec + +import AnnForall (annotateForall) +import Control.Monad ((<=<)) +import Desugar.Desugar (desugar) +import Grammar.Abs (Program) +import Grammar.ErrM (Err, pattern Bad, pattern Ok) +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import TypeChecker.RemoveForall (removeForall) +import TypeChecker.ReportTEVar (reportTEVar) +import TypeChecker.TypeChecker (TypeChecker (Bi)) +import TypeChecker.TypeCheckerBidir (typecheck) +import TypeChecker.TypeCheckerIr qualified as T + +test = hspec testTypeCheckerBidir + +testTypeCheckerBidir = describe "Test Bidirectional type checker" $ do + tc_id + tc_double + tc_add_lam + tc_const + tc_simple_rank2 + tc_rank2 + tc_identity + tc_pair + tc_tree + tc_mono_case + tc_pol_case + tc_infer_case + tc_rec1 + tc_rec2 + +tc_id = + specify "Basic identity function polymorphism" $ + run + [ "id : a -> a" + , "id x = x" + , "main = id 4" + ] + `shouldSatisfy` ok + +tc_double = + specify "Addition inference" $ + run + ["double x = x + x"] + `shouldSatisfy` ok + +tc_add_lam = + specify "Addition lambda inference" $ + run + ["four = (\\x. x + x) 2"] + `shouldSatisfy` ok + +tc_const = + specify "Basic polymorphism with multiple type variables" $ + run + [ "const : a -> b -> a" + , "const x y = x" + , "main = const 'a' 65" + ] + `shouldSatisfy` ok + +tc_simple_rank2 = + specify "Simple rank two polymorphism" $ + run + [ "id : a -> a" + , "id x = x" + , "f : a -> (forall b. b -> b) -> a" + , "f x g = g x" + , "main = f 4 id" + ] + `shouldSatisfy` ok + +tc_rank2 = + specify "Rank two polymorphism is ok" $ + run + [ "const : a -> b -> a" + , "const x y = x" + , "rank2 : a -> (forall c. c -> Int) -> b -> Int" + , "rank2 x f y = f x + f y" + , "main = rank2 3 (\\x. const 5 x : a -> Int) 'h'" + ] + `shouldSatisfy` ok + +tc_identity = describe "(βˆ€b. b β†’ b) should only accept the identity function" $ do + specify "identityα΅’β‚™β‚œ is rejected" $ run (fs ++ id_int) `shouldNotSatisfy` ok + specify "identity is accepted" $ run (fs ++ id) `shouldSatisfy` ok + where + fs = + [ "f : a -> (forall b. b -> b) -> a" + , "f x g = g x" + , "id : a -> a" + , "id x = x" + , "id_int : Int -> Int" + , "id_int x = x" + ] + id = + [ "main : Int" + , "main = f 4 id" + ] + id_int = + [ "main : Int" + , "main = f 4 id_int" + ] + +tc_pair = describe "Pair. Type variables in Pair a b typechecked" $ do + specify "Wrong arguments are rejected" $ run (fs ++ wrong) `shouldNotSatisfy` ok + specify "Correct arguments are accepted" $ run (fs ++ correct) `shouldSatisfy` ok + where + fs = + [ "data Pair a b where" + , " Pair : a -> b -> Pair a b" + , "main : Pair Int Char" + ] + wrong = ["main = Pair 'a' 65"] + correct = ["main = Pair 65 'a'"] + +tc_tree = describe "Tree. Recursive data type" $ do + specify "Wrong tree is rejected" $ run (fs ++ wrong) `shouldNotSatisfy` ok + specify "Correct tree is accepted" $ run (fs ++ correct) `shouldSatisfy` ok + where + fs = + [ "data Tree a where" + , " Node : a -> Tree a -> Tree a -> Tree a" + , " Leaf : a -> Tree a" + ] + wrong = ["tree = Node 1 (Node 2 (Node 4) (Leaf 5)) (Leaf 3)"] + correct = ["tree = Node 1 (Node 2 (Leaf 4) (Leaf 5)) (Leaf 3)"] + +tc_mono_case = describe "Monomorphic pattern matching" $ do + specify "First wrong case expression rejected" $ + run wrong1 `shouldNotSatisfy` ok + specify "Second wrong case expression rejected" $ + run wrong2 `shouldNotSatisfy` ok + specify "Third wrong case expression rejected" $ + run wrong3 `shouldNotSatisfy` ok + specify "First correct case expression accepted" $ + run correct1 `shouldSatisfy` ok + specify "Second correct case expression accepted" $ + run correct2 `shouldSatisfy` ok + where + wrong1 = + [ "simple : Int -> Int" + , "simple c = case c of" + , " 'F' => 0" + , " 'T' => 1" + ] + wrong2 = + [ "simple : Char -> Int" + , "simple c = case c of" + , " 'F' => 0" + , " 1 => 1" + ] + wrong3 = + [ "simple : Char -> Int" + , "simple c = case c of" + , " 'F' => 0" + , " 'T' => '1'" + ] + correct1 = + [ "simple : Char -> Int" + , "simple c = case c of" + , " 'F' => 0" + , " 'T' => 1" + ] + correct2 = + [ "simple : Char -> Int" + , "simple c = case c of" + , " 'F' => 0" + , " _ => 1" + ] + +tc_pol_case = describe "Polymophic and recursive pattern matching" $ do + specify "First wrong case expression rejected" $ + run (fs ++ wrong1) `shouldNotSatisfy` ok + specify "Second wrong case expression rejected" $ + run (fs ++ wrong2) `shouldNotSatisfy` ok + specify "Third wrong case expression rejected" $ + run (fs ++ wrong3) `shouldNotSatisfy` ok + specify "Forth wrong case expression rejected" $ + run (fs ++ wrong4) `shouldNotSatisfy` ok + specify "First correct case expression accepted" $ + run (fs ++ correct1) `shouldSatisfy` ok + specify "Second correct case expression accepted" $ + run (fs ++ correct2) `shouldSatisfy` ok + specify "Third correct case expression accepted" $ + run (fs ++ correct3) `shouldSatisfy` ok + specify "Forth correct case expression accepted" $ + run (fs ++ correct4) `shouldSatisfy` ok + where + fs = + [ "data List a where" + , " Nil : List a" + , " Cons : a -> List a -> List a" + ] + wrong1 = + [ "length : List c -> Int" + , "length = \\list. case list of" + , " Nil => 0" + , " Cons 6 xs => 1 + length xs" + ] + wrong2 = + [ "length : List c -> Int" + , "length = \\list. case list of" + , " Cons => 0" + , " Cons x xs => 1 + length xs" + ] + wrong3 = + [ "length : List c -> Int" + , "length = \\list. case list of" + , " 0 => 0" + , " Cons x xs => 1 + length xs" + ] + wrong4 = + [ "elems : List (List c) -> Int" + , "elems = \\list. case list of" + , " Nil => 0" + , " Cons Nil Nil => 0" + , " Cons Nil xs => elems xs" + , " Cons (Cons Nil ys) xs => 1 + elems (Cons ys xs)" + ] + correct1 = + [ "length : List c -> Int" + , "length = \\list. case list of" + , " Nil => 0" + , " Cons x xs => 1 + length xs" + , " Cons x (Cons y Nil) => 2" + ] + correct2 = + [ "length : List c -> Int" + , "length = \\list. case list of" + , " Nil => 0" + , " non_empty => 1" + ] + correct3 = + [ "length : List Int -> Int" + , "length = \\list. case list of" + , " Nil => 0" + , " Cons 1 Nil => 1" + , " Cons x (Cons 2 xs) => 2 + length xs" + ] + correct4 = + [ "elems : List (List c) -> Int" + , "elems = \\list. case list of" + , " Nil => 0" + , " Cons Nil Nil => 0" + , " Cons Nil xs => elems xs" + , " Cons (Cons _ ys) xs => 1 + elems (Cons ys xs)" + ] + +tc_if = specify "Test if else case expression" $ do + run + [ "data Bool where" + , " True : Bool" + , " False : Bool" + , "ifThenElse : Bool -> a -> a -> a" + , "ifThenElse b if else = case b of" + , " True => if" + , " False => else" + ] + `shouldSatisfy` ok + +tc_infer_case = describe "Infer case expression" $ do + specify "Wrong case expression rejected" $ + run (fs ++ wrong) `shouldNotSatisfy` ok + specify "Correct case expression accepted" $ + run (fs ++ correct) `shouldSatisfy` ok + where + fs = + [ "data Bool where" + , " True : Bool" + , " False : Bool" + ] + + correct = + [ "toBool = case 0 of" + , " 0 => False" + , " _ => True" + ] + + wrong = + [ "toBool = case 0 of" + , " 0 => False" + , " _ => 1" + ] + +tc_rec1 = + specify "Infer simple recursive definition" $ + run ["test x = 1 + test (x + 1)"] `shouldSatisfy` ok + +tc_rec2 = + specify "Infer recursive definition with pattern matching" $ + run + [ "data Bool where" + , " False : Bool" + , " True : Bool" + , "test = \\x. case x of" + , " 10 => True" + , " _ => test (x+1)" + ] + `shouldSatisfy` ok + +run :: [String] -> Err T.Program +run = + fmap removeForall + . reportTEVar + <=< typecheck + <=< run' + +run' s = do + p <- (fmap desugar . pProgram . resolveLayout True . myLexer . unlines) s + reportForall Bi p + (rename <=< annotateForall) p + +runPrint = + (putStrLn . either show printTree . run') + ["double x = x + x"] + +ok = \case + Ok _ -> True + Bad _ -> False diff --git a/tests/TestTypeCheckerHm.hs b/tests/TestTypeCheckerHm.hs new file mode 100644 index 0000000..8137937 --- /dev/null +++ b/tests/TestTypeCheckerHm.hs @@ -0,0 +1,265 @@ +{-# LANGUAGE QualifiedDo #-} + +module TestTypeCheckerHm where + +import Control.Monad (sequence_, (<=<)) +import Test.Hspec + +import AnnForall (annotateForall) +import Desugar.Desugar (desugar) +import DoStrings qualified as D +import Grammar.Layout (resolveLayout) +import Grammar.Par (myLexer, pProgram) +import Grammar.Print (printTree) +import Renamer.Renamer (rename) +import ReportForall (reportForall) +import TypeChecker.TypeChecker (TypeChecker (Hm)) +import TypeChecker.TypeCheckerHm (typecheck) +import TypeChecker.TypeCheckerIr (Program) + +testTypeCheckerHm = describe "Hindley-Milner type checker test" $ do + sequence_ goods + sequence_ bads + sequence_ bes + +goods = + [ testSatisfy + "Basic polymorphism with multiple type variables" + ( D.do + _const + "main = const 'a' 65 ;" + ) + ok + , testSatisfy + "Head with a correct signature is accepted" + ( D.do + _List + _headSig + _head + ) + ok + , testSatisfy + "Most simple inference possible" + ( D.do + _id + ) + ok + , testSatisfy + "Pattern matching on a nested list" + ( D.do + _List + "main : List (List a) -> Int;" + "main xs = case xs of {" + " Cons Nil _ => 1;" + " _ => 0;" + "};" + ) + ok + ] + +bads = + [ testSatisfy + "Infinite type unification should not succeed" + ( D.do + "main = \\x. x x ;" + ) + bad + , testSatisfy + "Pattern matching using different types should not succeed" + ( D.do + _List + "bad xs = case xs of {" + " 1 => 0 ;" + " Nil => 0 ;" + "};" + ) + bad + , testSatisfy + "Using a concrete function (data type) on a skolem variable should not succeed" + ( D.do + _Bool + _not + "f : a -> Bool ;" + "f x = not x ;" + ) + bad + , testSatisfy + "Using a concrete function (primitive type) on a skolem variable should not succeed" + ( D.do + "plusOne : Int -> Int ;" + "plusOne x = x + 1 ;" + "f : a -> Int ;" + "f x = plusOne x ;" + ) + bad + , testSatisfy + "A function without signature used in an incompatible context should not succeed" + ( D.do + "main = _id 1 2 ;" + "_id x = x ;" + ) + bad + , testSatisfy + "Pattern matching on literal and _List should not succeed" + ( D.do + _List + "length : List c -> Int;" + "length _List = case _List of {" + " 0 => 0;" + " Cons x xs => 1 + length xs;" + "};" + ) + bad + , testSatisfy + "List of function Int -> Int functions should not be usable on Char" + ( D.do + _List + "main : List (Int -> Int) -> Int ;" + "main xs = case xs of {" + " Cons f _ => f 'a' ;" + " Nil => 0 ;" + " };" + ) + bad + -- FIXME FAILING TEST + -- , testSatisfy + -- "id with incorrect signature" + -- ( D.do + -- "id : a -> b;" + -- "id x = x;" + -- ) + -- bad + -- FIXME FAILING TEST + -- , testSatisfy + -- "incorrect signature on const" + -- ( D.do + -- "const : a -> b -> b;" + -- "const x y = x" + -- ) + -- bad + -- FIXME FAILING TEST + -- , testSatisfy + -- "incorrect type signature on id lambda" + -- ( D.do + -- "id = ((\\x. x) : a -> b);" + -- ) + -- bad + ] + +bes = + [ testBe + "A basic arithmetic function should be able to be inferred" + ( D.do + "plusOne x = x + 1 ;" + "main x = plusOne x ;" + ) + ( D.do + "plusOne : Int -> Int ;" + "plusOne x = x + 1 ;" + "main : Int -> Int ;" + "main x = plusOne x ;" + ) + , testBe + "A basic arithmetic function should be able to be inferred" + ( D.do + "plusOne x = x + 1 ;" + ) + ( D.do + "plusOne : Int -> Int ;" + "plusOne x = x + 1 ;" + ) + , testBe + "List of function Int -> Int functions should be inferred corretly" + ( D.do + _List + "main xs = case xs of {" + " Cons f _ => f 1 ;" + " Nil => 0 ;" + " };" + ) + ( D.do + _List + "main : List (Int -> Int) -> Int ;" + "main xs = case xs of {" + " Cons f _ => f 1 ;" + " Nil => 0 ;" + " };" + ) + , testBe + "length function on int list infers correct signature" + ( D.do + "data List where " + " Nil : List" + " Cons : Int -> List -> List" + + "length xs = case xs of" + " Nil => 0" + " Cons _ xs => 1 + length xs" + ) + ( D.do + "data List where" + " Nil : List" + " Cons : Int -> List -> List" + + "length : List -> Int" + "length xs = case xs of" + " Nil => 0" + " Cons _ xs => 1 + length xs" + ) + ] + +testSatisfy desc test satisfaction = specify desc $ run test `shouldSatisfy` satisfaction +testBe desc test shouldbe = specify desc $ run test `shouldBe` run shouldbe + +run = fmap (printTree . fst) . typecheck <=< fmap desugar . pProgram . myLexer + +ok (Right _) = True +ok (Left _) = False + +bad = not . ok + +-- FUNCTIONS + +_const = D.do + "const : a -> b -> a ;" + "const x y = x ;" +_List = D.do + "data List a where {" + " Nil : List a;" + " Cons : a -> List a -> List a;" + "};" + +_headSig = D.do + "head : List a -> a ;" + +_head = D.do + "head xs = " + " case xs of {" + " Cons x xs => x ;" + " };" + +_Bool = D.do + "data Bool where {" + " True : Bool" + " False : Bool" + "};" + +_not = D.do + "not : Bool -> Bool ;" + "not x = case x of {" + " True => False ;" + " False => True ;" + "};" +_id = "id x = x ;" + +_Maybe = D.do + "data Maybe a where {" + " Nothing : Maybe a" + " Just : a -> Maybe a" + " };" + +_fmap = D.do + "fmap f ma = case ma of {" + " Nothing => Nothing ;" + " Just a => Just (f a) ;" + "};"