Compare commits

...
Author SHA1 Message Date
selimaj-dev e5df8df9b0 Release 0.1.7-alpha.1
[email protected]
[email protected]
[email protected]

Generated by cargo-workspaces
2026-06-01 13:50:49 +02:00
selimaj-dev ee40450f3a Merge pull request #57 from mist-go/module-system
Module system
2026-06-01 13:49:21 +02:00
selimaj-dev be6d2de39c improved code quality 2026-06-01 13:10:46 +02:00
selimaj-dev aff15f67c7 Working module system 2026-06-01 12:26:20 +02:00
selimaj-dev cfd1910f39 Working transpiler 2026-06-01 12:10:33 +02:00
selimaj-dev 082981f0bd Working module reading 2026-06-01 11:40:01 +02:00
selimaj-dev b384f55c77 Updated analyzer to remove the need for .mist/lib 2026-05-31 12:56:54 +02:00
selimaj-dev c4756262e1 ts sucks 2026-05-31 12:47:24 +02:00
selimaj-dev 74f10cc74b Removed lsp dev 2026-05-31 12:45:53 +02:00
selimaj-dev acef0888a3 Thinking of better ways to make analyzer work 2026-05-31 12:42:55 +02:00
selimaj-dev 18ab88af64 Thinking of better ways to make analyzer work 2026-05-31 12:41:48 +02:00
selimaj-dev 5e6cdc84b9 Updated cargo version 2026-05-31 12:39:10 +02:00
selimaj-dev 2dc5cdc9d9 Release 0.1.7-alpha.0
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

Generated by cargo-workspaces
2026-05-31 12:36:23 +02:00
selimaj-dev 893c981a41 Merge pull request #56 from mist-go/future-proofed-modules
Future proofed module stucture
2026-05-29 20:35:12 +02:00
selimaj-dev 0b3c4b8143 Module structure 2026-05-29 20:33:30 +02:00
selimaj-dev 86a1df7ad5 Mist Module system basic structure 2026-05-29 16:13:52 +02:00
selimaj-dev 3fa04cddd0 mist api lsp 2026-05-29 09:17:51 +02:00
selimaj-dev 371365b8cf Separated mist api 2026-05-29 09:04:58 +02:00
selimaj-dev b74da3255a Init mist-api 2026-05-29 08:58:42 +02:00
selimaj-dev 83e5e98641 Added mist.toml 2026-05-29 08:52:30 +02:00
selimaj-dev c774737074 Merge pull request #53 from mist-go/inheritance
Inheritance
2026-05-28 17:43:56 +02:00
selimaj-dev 9e1b9ad564 Fixed attributes 2026-05-28 16:28:20 +02:00
selimaj-dev 97b2cc4413 Working inheritance 2026-05-28 16:21:36 +02:00
selimaj-dev 99ff0ead2d Inheritance gen 2026-05-28 16:08:31 +02:00
selimaj-dev b0f3dccc87 Inheritance parsing 2026-05-28 15:55:00 +02:00
selimaj-dev 86a781c3f2 Merge pull request #52 from mist-go/parser-patches
Parser patches
2026-05-28 15:47:44 +02:00
selimaj-dev 583d51141f Fixed empty items 2026-05-28 15:44:52 +02:00
selimaj-dev ad11a3bd6a Improved match item span 2026-05-28 12:16:28 +02:00
selimaj-dev 7a2ba74d9c Working mut pattern 2026-05-28 11:52:40 +02:00
selimaj-dev 7007aa32f1 Refactored mutability 2026-05-28 11:45:26 +02:00
selimaj-dev 3444f93546 Updated codegen 2026-05-28 11:36:28 +02:00
selimaj-dev e09c7926e5 Updated pattern ast 2026-05-28 11:34:14 +02:00
selimaj-dev 83e98573aa Updated pattern grammar 2026-05-28 11:30:47 +02:00
selimaj-dev 3368696523 Merge pull request #51 from mist-go/bootstrapped-transpiler
Bootstrapped transpiler in mist
2026-05-25 19:45:57 +02:00
selimaj-dev ec1864334c Bootstrapped transpiler in mist 2026-05-25 16:06:04 +02:00
selimaj-dev 7c4595aeb9 Updated cargo.toml for lsp 2026-05-24 18:36:13 +02:00
selimaj-dev 8202cd6773 Merge pull request #48 from mist-go/lsp-patches-and-completions
Lsp patches and completions
2026-05-24 17:44:37 +02:00
selimaj-dev ecdbc9416a Build all on initialize 2026-05-24 17:38:35 +02:00
selimaj-dev 24134ec925 Production safe analyzer 2026-05-24 17:24:37 +02:00
selimaj-dev dbf3a80387 Working completions 2026-05-24 17:04:08 +02:00
selimaj-dev cdffc87161 Using ropey 2026-05-24 16:49:53 +02:00
selimaj-dev fbf60944a8 using ropey 2026-05-24 16:24:22 +02:00
selimaj-dev 5a6adbc5e4 updated capabilities 2026-05-24 16:19:51 +02:00
selimaj-dev 354965b425 Completion 2026-05-24 15:45:01 +02:00
selimaj-dev f5fcbbacb6 did change and close 2026-05-24 15:11:24 +02:00
selimaj-dev e358636e41 Updated version 2026-05-24 14:51:01 +02:00
selimaj-dev 2c5a845c57 Merge pull request #47 from mist-go/closures-and-bodies
Closures and fix statement bodies
2026-05-24 14:47:32 +02:00
selimaj-dev f21cd5a927 Fixed statement bodies 2026-05-24 14:43:09 +02:00
selimaj-dev 63cc20107c Soft returning refactor 2026-05-24 13:20:08 +02:00
selimaj-dev f4fe38140a statement body parsing 2026-05-24 12:55:33 +02:00
selimaj-dev 6551aee03b Fixed block propaganda 2026-05-24 12:43:35 +02:00
selimaj-dev 1c2cc94cb9 Closures 2026-05-24 12:29:42 +02:00
selimaj-dev fde41b9a22 Merge pull request #46 from mist-go/working-lsp
Working lsp
2026-05-24 12:00:29 +02:00
selimaj-dev 9eec07ca2e Improved compiler error message 2026-05-24 11:57:17 +02:00
selimaj-dev 5bfccb0fc4 Improved error handling 2026-05-24 10:41:28 +02:00
selimaj-dev bad6034ba5 Working goto with mist 2026-05-24 10:11:06 +02:00
selimaj-dev f05849ee45 Working did open and goto 2026-05-24 09:34:02 +02:00
selimaj-dev c36d07f0dd Working goto request 2026-05-24 07:56:31 +02:00
selimaj-dev f181806f65 Working request 2026-05-24 07:34:04 +02:00
selimaj-dev 8b0f2ac1b9 Working req res 2026-05-24 07:08:23 +02:00
selimaj-dev 64c612fe3c Removed unnecessary package 2026-05-24 07:03:46 +02:00
selimaj-dev 831fa544fc Pending 2026-05-24 07:01:53 +02:00
selimaj-dev 9b1acb8cc3 Working req res 2026-05-24 06:29:58 +02:00
selimaj-dev b2f5f2fdc8 Sending goto to rust 2026-05-23 15:40:47 +02:00
selimaj-dev c405a2059e Improved rust analyzer client 2026-05-23 15:26:15 +02:00
selimaj-dev ff58a92b3f Rust analyzer init 2026-05-23 14:55:44 +02:00
selimaj-dev 763473ef57 Merge pull request #45 from mist-go/working-lsp-diagnostics
Working lsp diagnostics
2026-05-23 11:27:45 +02:00
selimaj-dev eb24767617 idk 2026-05-23 11:27:05 +02:00
selimaj-dev fa00b3a199 Position injection 2026-05-23 10:14:23 +02:00
selimaj-dev b149bcde4a Refactored transpiler LSP 2026-05-23 09:50:04 +02:00
selimaj-dev 77b6991226 Improved error system LSp 2026-05-23 08:52:45 +02:00
selimaj-dev b96a6f154d errors 2026-05-23 04:36:56 +02:00
selimaj-dev 9f6ec4a20d Working LSP error checking 2026-05-22 15:53:25 +02:00
selimaj-dev 52efdda744 On save 2026-05-22 09:59:13 +02:00
selimaj-dev 97e8f32473 Working lsp build 2026-05-22 09:29:35 +02:00
selimaj-dev 21019cd54f Inject cargo error fix 2026-05-22 04:39:37 +02:00
selimaj-dev bb7e78d042 Fixed error line 2026-05-22 04:35:53 +02:00
selimaj-dev a8ec265c1c Refactored cargo structure 2026-05-22 04:25:33 +02:00
selimaj-dev b7c68da6de Updated tags 2026-05-22 04:15:18 +02:00
selimaj-dev 8d0adb3bb9 Include mist build 2026-05-22 04:04:43 +02:00
selimaj-dev 76f5eccddf Improved cargo structure 2026-05-22 04:01:16 +02:00
selimaj-dev 5539ebde61 Updated versions 2026-05-22 03:49:54 +02:00
selimaj-dev ae25b0044b Merge pull request #44 from mist-go/statement-patches-and-errors
Statement patches and errors
2026-05-22 03:48:17 +02:00
selimaj-dev 1a026f69cb Fixed errors 2026-05-22 03:44:44 +02:00
selimaj-dev c5c5e885bf Improved loop bodies 2026-05-22 03:25:05 +02:00
selimaj-dev a26c1c31fb Added forever loop 2026-05-22 03:05:08 +02:00
selimaj-dev d33763be2e Fixed block statements 2026-05-22 03:00:43 +02:00
selimaj-dev b7cfa9fbe6 Improved for loops 2026-05-22 02:52:22 +02:00
selimaj-dev 960cc40886 Improved codegen 2026-05-22 02:34:01 +02:00
selimaj-dev c9a3c4693c Optimised main.mist 2026-05-21 15:21:04 +02:00
selimaj-dev 76b267a886 Merge pull request #43 from mist-go/rewritten-codegen
Rewritten codegen
2026-05-21 15:16:38 +02:00
selimaj-dev 119f93cf79 Prettier codegen output 2026-05-21 15:14:51 +02:00
selimaj-dev 4112dcac3b Improved match statements 2026-05-21 14:38:37 +02:00
selimaj-dev 80ff10503a Working constructor and statements 2026-05-21 14:19:32 +02:00
selimaj-dev f2257a4e81 Fixed some bugs 2026-05-21 14:04:12 +02:00
selimaj-dev 8703ac4254 Finished expr, and removed old codegen 2026-05-21 13:48:09 +02:00
selimaj-dev 70a1fa332b Top level 2026-05-21 13:43:42 +02:00
selimaj-dev 7b94969379 Top level 2026-05-21 13:36:38 +02:00
selimaj-dev 357a25a859 base top level 2026-05-21 13:14:48 +02:00
selimaj-dev 7af6416921 Statements 2026-05-21 13:03:46 +02:00
selimaj-dev 827b674be2 Expression 2026-05-21 12:25:06 +02:00
selimaj-dev 87bc8a0d69 Rewriting codegen' 2026-05-21 11:29:01 +02:00
selimaj-dev aba8badd90 Merge pull request #42 from mist-go/init-and-expr-statements
Init and expression statements
2026-05-21 11:16:48 +02:00
selimaj-dev 224b367ff1 Removed trailing semicolons 2026-05-21 11:10:44 +02:00
selimaj-dev 9da4a50ef5 Removed invalid statement 2026-05-21 11:07:49 +02:00
selimaj-dev 2fcb8c3831 Fixed naming error 2026-05-21 11:05:00 +02:00
selimaj-dev 702af9da3b Fixed self and added tests back 2026-05-21 08:09:26 +02:00
selimaj-dev 7688599504 Working soft return 2026-05-21 07:59:00 +02:00
selimaj-dev 70e6eb6276 Control flow 2026-05-21 07:28:19 +02:00
selimaj-dev 197afbfb35 bin op stuff 2026-05-21 07:23:11 +02:00
selimaj-dev 0878b9f0b9 Improving operators and suffix 2026-05-21 07:05:58 +02:00
selimaj-dev b28591f9e6 Working expr statements 2026-05-21 06:51:34 +02:00
selimaj-dev 0c8dc53617 Rewriting statement system for expr statements 2026-05-21 06:34:27 +02:00
selimaj-dev cc7bc49efe Added init to list 2026-05-21 06:16:51 +02:00
selimaj-dev 959f786dc8 Working init 2026-05-21 06:14:50 +02:00
selimaj-dev da819c22f6 Init project 2026-05-21 05:43:10 +02:00
selimaj-dev d408d01002 Using .mist/src 2026-05-21 05:33:23 +02:00
selimaj-dev 856c9dfdfa Rewriting mist project structure 2026-05-21 05:26:52 +02:00
selimaj-dev 812fa5d540 Merge pull request #39 from mist-go/lsp-base
Lsp base
2026-05-20 13:34:21 +02:00
selimaj-dev b55b35623b Preparing for mapping 2026-05-20 13:14:48 +02:00
selimaj-dev ff38c809e7 Simple completion example 2026-05-20 10:17:14 +02:00
selimaj-dev 64418cb52d cargo lock 2026-05-20 09:31:58 +02:00
selimaj-dev 674b809586 cargo lock 2026-05-20 09:31:50 +02:00
selimaj-dev 6b14ab0308 Working hello world lsp 2026-05-20 09:03:00 +02:00
selimaj-dev b86b4831ce Added analyzer 2026-05-20 08:54:56 +02:00
selimaj-dev 949135bd3b Include 2026-05-19 12:37:49 +02:00
selimaj-dev c30d686eb5 Merge pull request #38 from mist-go/snake
A snake is eating itself
2026-05-19 12:31:25 +02:00
selimaj-dev 47e62f96d9 Updated version 2026-05-19 12:30:29 +02:00
selimaj-dev b856450cc1 Header for rust IDE support 2026-05-19 12:27:32 +02:00
selimaj-dev 3ed17e007f Multiple commands bootstrapped 2026-05-19 12:23:57 +02:00
selimaj-dev bffc9f073b Match multiple patterns 2026-05-19 12:21:20 +02:00
selimaj-dev 318480f0b5 Fixed string and macro, and main 2026-05-19 12:14:25 +02:00
selimaj-dev 1a469689a7 Fixed amgibuitiy 2026-05-19 11:25:14 +02:00
selimaj-dev 6d7beb20ca Bootstrapped main 2026-05-19 11:19:49 +02:00
selimaj-dev 5f7dcc859c Preparing for bootstrapping 2026-05-19 11:06:26 +02:00
selimaj-dev 7febf84cd8 Updated version (again) 2026-05-19 11:02:06 +02:00
selimaj-dev 93eb467814 Updated quick patch version 2026-05-19 10:47:54 +02:00
selimaj-dev 0e27344012 Merge pull request #37 from mist-go/quick-patches
Quick patches
2026-05-19 10:45:50 +02:00
selimaj-dev 8f820bfb50 Fix: future ambiguities via !keyword 2026-05-19 10:44:51 +02:00
selimaj-dev 0031fb7152 Fix: statement 2026-05-19 10:39:35 +02:00
selimaj-dev 28a7658ce7 Updated version 2026-05-19 10:18:26 +02:00
selimaj-dev 67b60a9e4f Fix: statement order 2026-05-19 10:14:24 +02:00
selimaj-dev 16bca21981 Merge pull request #36 from mist-go/refactors-and-patches
Refactors and patches
2026-05-19 10:02:25 +02:00
selimaj-dev 349f9ba59e Refactor: Error handling in builder 2026-05-19 10:01:29 +02:00
selimaj-dev 3620f0432a Fix: mappings 2026-05-19 09:46:24 +02:00
selimaj-dev 69e5ab2a5e Dyn type 2026-05-19 06:55:58 +02:00
selimaj-dev bcefabe2d2 Fixed expression statement bug 2026-05-19 06:39:38 +02:00
selimaj-dev 551f14f81e Merge pull request #35 from mist-go/errors-and-caching
Errors and caching
2026-05-19 06:36:42 +02:00
selimaj-dev a5ccd9651a Added check command and updated help 2026-05-19 06:24:35 +02:00
selimaj-dev 9d051c68e9 Impl spanned functions 2026-05-19 06:11:52 +02:00
selimaj-dev fd7455c71e Fixed traits 2026-05-19 06:06:04 +02:00
selimaj-dev 1e191cf3c8 Class items, struct items, enum items, mapping 2026-05-19 06:00:35 +02:00
selimaj-dev 6412daa514 Dramatically improved transpile times by caching 2026-05-19 05:28:14 +02:00
selimaj-dev 1b4c925f9f Improved transpiler output 2026-05-19 05:24:59 +02:00
selimaj-dev bfd768a162 Working app stdout 2026-05-19 05:20:16 +02:00
selimaj-dev ffe868e0cd Fixed build stdout 2026-05-19 05:08:27 +02:00
selimaj-dev 8343740b11 Fixed build error on inner dir 2026-05-19 04:40:33 +02:00
selimaj-dev 4e98257438 Improved paths 2026-05-19 04:36:35 +02:00
selimaj-dev 95ae7b8d52 Improved paths, and added rust specific errors 2026-05-19 04:35:12 +02:00
selimaj-dev e30722dde3 Warning 2026-05-19 03:32:17 +02:00
selimaj-dev eb84103ed6 Improved diagnostic conversion 2026-05-19 03:24:12 +02:00
selimaj-dev 49a3186d26 Diagnostic conversion 2026-05-19 02:58:57 +02:00
selimaj-dev 670835a5e7 Added cargo_metadata and renamed compiler module 2026-05-19 02:04:37 +02:00
selimaj-dev 2b43e0c004 Working mapping 2026-05-19 01:47:02 +02:00
selimaj-dev 11e408cc17 find mapping 2026-05-19 00:46:07 +02:00
selimaj-dev 5e8946a126 Mapping 2026-05-19 00:40:28 +02:00
selimaj-dev 6b314dabf4 Spanned statements 2026-05-18 21:56:07 +02:00
selimaj-dev c5d8c12c14 Fix: visibility spacing 2026-05-18 21:42:22 +02:00
selimaj-dev d1330500b2 Spanned 2026-05-18 21:40:01 +02:00
selimaj-dev a88ff4c8dd Spanned impl 2026-05-18 14:42:41 +02:00
selimaj-dev 5648c1da61 Spanned 2026-05-18 13:58:59 +02:00
selimaj-dev de1784f914 Merge pull request #32 from mist-go/refactor-generics
Refactor generics & Sidefiles
2026-05-17 20:10:36 +02:00
selimaj-dev aa948a50cb Moving instead of borrowing in codegen 2026-05-17 20:02:07 +02:00
selimaj-dev f9f86fcc67 Implementation: sidefiles 2026-05-17 19:39:21 +02:00
selimaj-dev 907d9d7f9d Fix: Generics decl constraints 2026-05-17 19:30:20 +02:00
selimaj-dev 1d4473906f Fix: Generics decl not working 2026-05-17 19:21:10 +02:00
selimaj-dev 7fe91b8e36 Fix: Generics 2026-05-17 11:39:18 +02:00
selimaj-dev 94e113d227 Fix: Generics decl 2026-05-17 11:26:04 +02:00
selimaj-dev c566ac9a54 Fix: reveresed type postfix 2026-05-17 11:13:29 +02:00
selimaj-dev 5fa3e77b8f Added expr? syntax 2026-05-17 06:08:53 +02:00
selimaj-dev e270ec727e Merge pull request #31 from mist-go/assignments-expressions
Improved Assignments & expressions
2026-05-17 06:03:11 +02:00
selimaj-dev e89f5e805c Cleaned up AST 2026-05-17 06:00:26 +02:00
selimaj-dev dd647afd59 Indentation increment 2026-05-17 05:55:43 +02:00
selimaj-dev 46c6f5ffdd Fixed range 2026-05-17 05:52:23 +02:00
selimaj-dev 212d5d69b5 Fixed as 2026-05-17 05:49:37 +02:00
selimaj-dev a893f9a12d Increment and decrement via ++ or -- 2026-05-17 05:43:16 +02:00
selimaj-dev 77f35e0517 Removed incrementing tmp 2026-05-17 05:32:46 +02:00
selimaj-dev 1bcbca00b8 Fixed loose error 2026-05-17 05:13:28 +02:00
selimaj-dev c7529412f4 Adding increment 2026-05-17 04:44:38 +02:00
selimaj-dev 9b632fcc0e New generics 2026-05-17 04:35:00 +02:00
selimaj-dev 4742fbebf7 Codegen generics 2026-05-17 04:30:00 +02:00
selimaj-dev 82d748224f Fixed expression 2026-05-17 04:13:27 +02:00
selimaj-dev 16f169cdb0 Codegen 2026-05-17 04:00:15 +02:00
selimaj-dev 2a95ad4eb0 extended expression 2026-05-17 03:49:34 +02:00
selimaj-dev 33fae13c8a Updated AST for extensive expressions 2026-05-17 03:28:22 +02:00
selimaj-dev 23cf00975d Updated grammar for more extensive expressions 2026-05-17 03:25:02 +02:00
selimaj-dev 2c67d4e316 Tuple fix 2026-05-17 02:37:18 +02:00
selimaj-dev bfaaa4006b Codegen 2026-05-17 02:32:41 +02:00
selimaj-dev 50c98cf5f7 Adapted parser and ast with grammar 2026-05-17 02:30:03 +02:00
selimaj-dev 020eebdaba Updated expr ast 2026-05-17 02:21:12 +02:00
selimaj-dev 675e357297 Using term based expressions: grammar 2026-05-17 02:18:09 +02:00
selimaj-dev 6a0011c009 Restored grammar for now 2026-05-16 23:40:45 +02:00
selimaj-dev 95f253c0ce Refactored ast structure 2026-05-16 23:04:05 +02:00
selimaj-dev b802c51369 updated expr grammar 2026-05-16 22:53:08 +02:00
selimaj-dev 0bd8bc2f03 track caller on bug_unimplemented 2026-05-16 22:43:44 +02:00
selimaj-dev 13480b2c54 removed var assign statement struct 2026-05-16 22:40:39 +02:00
selimaj-dev c9030809fd Compound assign statement 2026-05-16 22:40:01 +02:00
61 changed files with 6002 additions and 1852 deletions
+3 -2
View File
@@ -26,5 +26,6 @@ target
/target /target
/mist-test/build **/build
/mist-test/output.json
.mist/
Generated
+857 -3
View File
@@ -2,6 +2,40 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "auto_impl"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@@ -11,6 +45,45 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "camino"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
dependencies = [
"serde_core",
]
[[package]]
name = "cargo-platform"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba"
dependencies = [
"serde",
"serde_core",
]
[[package]]
name = "cargo_metadata"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.4" version = "1.0.4"
@@ -26,6 +99,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.7" version = "0.1.7"
@@ -36,6 +115,33 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "dashmap"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@@ -46,6 +152,112 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-io"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-macro"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"slab",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@@ -56,6 +268,121 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "icu_collections"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
[[package]]
name = "icu_properties"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
dependencies = [
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
[[package]]
name = "icu_provider"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.18" version = "1.0.18"
@@ -68,6 +395,34 @@ version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "litemap"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "lsp-types"
version = "0.94.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
dependencies = [
"bitflags 1.3.2",
"serde",
"serde_json",
"serde_repr",
"url",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.0" version = "2.8.0"
@@ -75,17 +430,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]] [[package]]
name = "mist-lang" name = "mio"
version = "0.0.2-alpha0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [ dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "mist-analyzer"
version = "0.1.7-alpha.1"
dependencies = [
"cargo_metadata",
"dashmap 6.1.0",
"mist-codegen",
"mist-parser",
"ropey",
"serde",
"serde_json",
"tokio",
"tower-lsp",
]
[[package]]
name = "mist-api"
version = "0.1.7-alpha.1"
dependencies = [
"cargo_metadata",
"mist-codegen",
"mist-parser", "mist-parser",
"serde", "serde",
"serde_json", "serde_json",
] ]
[[package]]
name = "mist-codegen"
version = "0.1.7-alpha.0"
dependencies = [
"mist-parser",
]
[[package]]
name = "mist-lang"
version = "0.1.7-alpha.1"
dependencies = [
"mist-analyzer",
"mist-api",
]
[[package]] [[package]]
name = "mist-parser" name = "mist-parser"
version = "0.1.1" version = "0.1.7-alpha.0"
dependencies = [ dependencies = [
"pest", "pest",
"pest_derive", "pest_derive",
@@ -93,6 +491,41 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.8.6" version = "2.8.6"
@@ -136,6 +569,41 @@ dependencies = [
"sha2", "sha2",
] ]
[[package]]
name = "pin-project"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "potential_utf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [
"zerovec",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@@ -154,6 +622,41 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.11.1",
]
[[package]]
name = "ropey"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5"
dependencies = [
"smallvec",
"str_indices",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
dependencies = [
"serde",
"serde_core",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@@ -197,6 +700,17 @@ dependencies = [
"zmij", "zmij",
] ]
[[package]]
name = "serde_repr"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.9" version = "0.10.9"
@@ -208,6 +722,50 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "str_indices"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.117" version = "2.0.117"
@@ -219,6 +777,179 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "tokio"
version = "1.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-util"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-lsp"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4ba052b54a6627628d9b3c34c176e7eda8359b7da9acd497b9f20998d118508"
dependencies = [
"async-trait",
"auto_impl",
"bytes",
"dashmap 5.5.3",
"futures",
"httparse",
"lsp-types",
"memchr",
"serde",
"serde_json",
"tokio",
"tokio-util",
"tower",
"tower-lsp-macros",
"tracing",
]
[[package]]
name = "tower-lsp-macros"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.20.0" version = "1.20.0"
@@ -237,12 +968,135 @@ version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
"serde_derive",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.5" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "writeable"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "yoke"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerotrie"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "zmij" name = "zmij"
version = "1.0.21" version = "1.0.21"
+34 -7
View File
@@ -1,19 +1,46 @@
[package] [package]
name = "mist-lang" name = "mist-lang"
version = "0.0.2-alpha0" version = "0.1.7-alpha.1"
edition = "2024" edition = "2024"
description = "The Mist programming language compiler" description = "The Mist programming language compiler"
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/mist-go/mist" repository = "https://github.com/mist-go/mist"
readme = "README.md" readme = "README.md"
keywords = ["compiler", "language", "mist"] keywords = ["compiler", "language", "mist", "lang"]
categories = ["compilers"] categories = ["compilers", "command-line-interface", "development-tools", "development-tools::build-utils"]
default-run = "mist"
include = [
".mist/src/**",
"Cargo.toml",
"README.md",
]
[dependencies] [dependencies]
serde = { version = "1.0.228", features = ["serde_derive"] } mist-analyzer = { workspace = true }
serde_json = "1.0.149" mist-api = { workspace = true }
mist-parser = { path = "./parser", version = "0.1.1"}
[workspace]
members = [
"crates/parser",
"crates/analyzer",
"crates/codegen",
"crates/mist-api",
]
exclude = [
"mist-test",
]
[workspace.dependencies]
mist-parser = { path = "crates/parser", version = "0.1.7-alpha.0" }
mist-analyzer = { path = "crates/analyzer", version = "0.1.7-alpha.0" }
mist-codegen = { path = "crates/codegen", version = "0.1.7-alpha.0" }
mist-api = { path = "crates/mist-api", version = "0.1.7-alpha.0" }
[[bin]] [[bin]]
name = "mist" name = "mist"
path = "src/main.rs" path = ".mist/src/main.rs"
[[bin]]
name = "mist-analyzer"
path = ".mist/src/analyzer.rs"
+1
View File
@@ -0,0 +1 @@
package = "main.mist"
+9
View File
@@ -0,0 +1,9 @@
@echo off
cd D:\projects\mist\mist
mist build >nul 2>&1
cd D:\projects\mist\mist-lsp-test
D:\projects\mist\mist\target\debug\mist-analyzer.exe
+863
View File
@@ -0,0 +1,863 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "auto_impl"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "dashmap"
version = "6.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-io"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-macro"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"slab",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "icu_collections"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
[[package]]
name = "icu_properties"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
dependencies = [
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
[[package]]
name = "icu_provider"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "litemap"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "lsp-types"
version = "0.94.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
dependencies = [
"bitflags 1.3.2",
"serde",
"serde_json",
"serde_repr",
"url",
]
[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "mio"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "mist-analyzer"
version = "0.0.1"
dependencies = [
"dashmap 6.2.1",
"tokio",
"tower-lsp",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "potential_utf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [
"zerovec",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.11.1",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "serde_repr"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "tokio"
version = "1.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-util"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-lsp"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4ba052b54a6627628d9b3c34c176e7eda8359b7da9acd497b9f20998d118508"
dependencies = [
"async-trait",
"auto_impl",
"bytes",
"dashmap 5.5.3",
"futures",
"httparse",
"lsp-types",
"memchr",
"serde",
"serde_json",
"tokio",
"tokio-util",
"tower",
"tower-lsp-macros",
"tracing",
]
[[package]]
name = "tower-lsp-macros"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
"serde_derive",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "writeable"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "yoke"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerotrie"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+22
View File
@@ -0,0 +1,22 @@
[package]
name = "mist-analyzer"
version = "0.1.7-alpha.1"
edition = "2024"
description = "The Mist programming language Analyzer LSP"
license = "Apache-2.0"
repository = "https://github.com/mist-go/mist"
keywords = ["language-server", "language", "mist"]
categories = ["compilers"]
[dependencies]
mist-parser = { workspace = true }
mist-codegen = { workspace = true }
dashmap = "6.1.0"
tokio = { version = "1.52.3", features = ["full", "macros", "rt", "rt-multi-thread"] }
tower-lsp = "0.20.0"
cargo_metadata = "0.23.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
ropey = "1"
+139
View File
@@ -0,0 +1,139 @@
use std::{
collections::HashMap,
env, fs,
path::{MAIN_SEPARATOR, PathBuf},
process::{Command, Stdio},
};
use cargo_metadata::{CompilerMessage, Message};
use mist_parser::rev_mapper::{RustMap, find_mapping, get_mapping};
#[derive(Debug, Clone)]
pub struct MistDiagnosticMessage {
pub message: String,
pub file_path: PathBuf,
pub file_name: String,
pub line: usize,
pub column: usize,
}
#[derive(Debug, Clone)]
pub enum MistDiagnostic {
Error(MistDiagnosticMessage),
Warning(MistDiagnosticMessage),
Rust(CompilerMessage),
}
pub fn build(mut args: Vec<String>, root: PathBuf) -> Vec<MistDiagnostic> {
args.insert(1, "--message-format=json".to_string());
let is_root = root == env::current_dir().expect("Failed getting env");
let mut command = Command::new("cargo")
.args(args)
.stdout(Stdio::piped())
.spawn()
.expect("Failed to run cargo");
let mut reader = std::io::BufReader::new(command.stdout.take().expect("Failed to get reader"));
let mut diagnostics = Vec::new();
let mut mapping = HashMap::new();
let mist_src = format!(".mist{MAIN_SEPARATOR}lsp");
for message in cargo_metadata::Message::parse_stream(&mut reader) {
match message {
Ok(Message::CompilerMessage(msg)) => {
for span in &msg.message.spans {
if span.is_primary {
let rust_path = root.join(&span.file_name);
let mist_file = span
.file_name
.replacen(&mist_src, "src", 1)
.trim_end_matches(".rs")
.to_string()
+ ".mist";
let mist_path = root.join(&mist_file);
if !fs::exists(&mist_path).expect("Unable to check if mist file exists") {
diagnostics.push(MistDiagnostic::Rust(msg));
break;
}
let map = mapping.entry(rust_path.clone()).or_insert_with(|| {
get_mapping(
&fs::read_to_string(rust_path)
.expect("Failed to read file for mapping"),
)
});
let mist_span =
find_mapping(&map, &RustMap(span.line_end, span.column_start))
.expect("Unable to find mapping");
let mist_msg = MistDiagnosticMessage {
message: format!(
"{}: {}",
msg.message.message,
span.label.clone().unwrap_or_default()
),
file_name: if is_root {
mist_file
} else {
mist_path.to_string_lossy().to_string()
},
file_path: mist_path,
line: mist_span.1.0,
column: mist_span.1.1,
};
match msg.message.level {
cargo_metadata::diagnostic::DiagnosticLevel::Error => {
diagnostics.push(MistDiagnostic::Error(mist_msg))
}
cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
diagnostics.push(MistDiagnostic::Warning(mist_msg))
}
_ => {}
}
}
}
}
Ok(Message::BuildFinished(_)) => {
command.wait().unwrap();
return diagnostics;
}
Ok(Message::TextLine(text)) => println!("{text}"),
_ => {}
}
}
diagnostics
}
pub fn get_line(
files: &mut HashMap<PathBuf, Vec<String>>,
msg: &MistDiagnosticMessage,
) -> Option<String> {
let src_path = msg.file_path.clone();
let lines = files.entry(src_path.clone()).or_insert_with(|| {
fs::read_to_string(src_path)
.expect("Unable to read mist file")
.lines()
.into_iter()
.map(String::from)
.collect()
});
lines.get(msg.line - 1).map(|v| v.trim().to_string())
}
+671
View File
@@ -0,0 +1,671 @@
pub mod builder;
pub mod rust_analyzer;
pub mod transpiler;
use std::collections::{HashMap, HashSet};
use std::path::{Component, PathBuf};
use std::sync::Arc;
use mist_parser::rev_mapper;
use ropey::Rope;
use tokio::sync::Mutex;
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::notification::Notification;
use tower_lsp::lsp_types::{self, *};
use tower_lsp::{Client, LanguageServer, LspService, Server};
use crate::builder::MistDiagnostic;
use crate::rust_analyzer::RustAnalyzer;
#[derive(Debug)]
struct Backend {
client: Client,
workspace_folder: Arc<Mutex<Option<PathBuf>>>,
previous_diagnostics: Arc<Mutex<HashMap<Url, Vec<Diagnostic>>>>,
rust_analyzer: Arc<Mutex<RustAnalyzer>>,
mapping: Arc<Mutex<HashMap<PathBuf, HashSet<(rev_mapper::RustMap, rev_mapper::MistMap)>>>>,
documents: Arc<Mutex<HashMap<PathBuf, Rope>>>,
}
/// Helper function to force percent-encoding on Windows drive colons
/// so that the URLs exactly match what VS Code/LSP clients send.
fn clean_lsp_url(path: &std::path::Path) -> Option<Url> {
let mut url_str = Url::from_file_path(path).ok()?.to_string();
// Look for Windows patterns like file:///D: or file:///d: and switch to %3A
if url_str.starts_with("file:///I:") || url_str.starts_with("file:///i:") || // Catch-all or explicit check:
(url_str.len() > 10 && url_str.as_bytes()[11] == b':')
{
// Safely replace the first colon occurring after "file:///"
if let Some(pos) = url_str.find(':') {
if pos == 11 {
// Double check it's the drive letter colon
url_str.replace_range(pos..=pos, "%3A");
}
}
}
Url::parse(&url_str).ok()
}
impl Backend {
async fn get_mist_location(&self, rs_loc: Location) -> Location {
let rs_path = match rs_loc.uri.to_file_path() {
Ok(path) => path,
Err(_) => return rs_loc,
};
match self.mapping.lock().await.get(&rs_path) {
Some(mapping) => {
// FIX: Match the find_mapping operation instead of calling .expect("Failed to map")
match rev_mapper::find_mapping(
mapping,
&rev_mapper::RustMap(
rs_loc.range.start.line as usize,
rs_loc.range.start.character as usize,
),
) {
Some((_, rev_mapper::MistMap(line, character))) => Location {
uri: Url::from_file_path(from_rust_to_mist(rs_path)).unwrap(),
range: Range {
start: Position {
line: line as u32 - 1,
character: character as u32,
},
end: Position {
line: line as u32 - 1,
character: character as u32 + 1,
},
},
},
None => rs_loc,
}
}
None => rs_loc,
}
}
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
let mut res = InitializeResult::default();
res.capabilities.text_document_sync = Some(TextDocumentSyncCapability::Options(
TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::FULL),
will_save: Some(false),
will_save_wait_until: Some(false),
save: Some(SaveOptions::default().into()),
},
));
res.capabilities.completion_provider = Some(CompletionOptions {
resolve_provider: Some(true),
trigger_characters: Some(vec![
":".to_owned(),
".".to_owned(),
"'".to_owned(),
"(".to_owned(),
]),
all_commit_characters: None,
completion_item: Some(CompletionOptionsCompletionItem {
label_details_support: None,
}),
work_done_progress_options: WorkDoneProgressOptions {
work_done_progress: None,
},
});
res.capabilities.definition_provider = Some(OneOf::Left(true));
let folder_path = params
.workspace_folders
.as_ref()
.and_then(|folders| folders.first())
.and_then(|folder| folder.uri.to_file_path().ok());
if let Some(ref path) = folder_path {
*self.workspace_folder.lock().await = Some(path.clone());
}
let workspace_folder = self.workspace_folder.clone();
let analyzer = self.rust_analyzer.clone();
let documents = self.documents.clone();
let mapping = self.mapping.clone();
tokio::spawn(async move {
if let Some(root) = &*workspace_folder.lock().await {
let src_root = root.join("src");
transpiler::build(root);
analyzer
.lock()
.await
.initialize(root)
.await
.expect("Failed to initialize rust analyzer");
// ---- LOAD ALL .MIST FILES ----
let mut files = Vec::new();
collect_mist_files(&src_root, &mut files);
for file in files {
if let Ok(text) = std::fs::read_to_string(&file) {
if let Ok(transpiled) = transpiler::transpile_text(&text) {
let rust_path = from_mist_to_rust(file.clone());
// store document
documents
.lock()
.await
.insert(file.clone(), Rope::from_str(&text));
// store mapping
mapping
.lock()
.await
.insert(rust_path, rev_mapper::get_mapping(&transpiled));
}
}
}
eprintln!("Ready to use");
}
});
Ok(res)
}
async fn initialized(&self, _: InitializedParams) {
self.rust_analyzer
.lock()
.await
.initialized()
.await
.expect("Failed to initialize rust analyzer");
self.client
.log_message(MessageType::INFO, "server initialized!")
.await;
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
async fn did_save(&self, _: DidSaveTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "Processing did_save event")
.await;
if let Some(root) = &*self.workspace_folder.lock().await {
transpiler::build(root);
}
let workspace_root = match self.workspace_folder.lock().await.clone() {
Some(root) => root,
None => {
self.client
.log_message(
MessageType::WARNING,
"Skipping diagnostics: No active workspace folder found",
)
.await;
return;
}
};
let diagnostics_raw = builder::build(
vec![
"check".to_string(),
"--workspace".to_string(),
"--all-targets".to_string(),
],
workspace_root,
);
let mut diagnostics = HashMap::new();
for diag in diagnostics_raw.iter() {
let (msg, severity) = match diag {
MistDiagnostic::Error(msg) => (msg, DiagnosticSeverity::ERROR),
MistDiagnostic::Warning(msg) => (msg, DiagnosticSeverity::WARNING),
MistDiagnostic::Rust(_) => {
continue;
}
};
let line = (msg.line as u32).saturating_sub(1);
let column = (msg.column as u32).saturating_sub(1);
let url = match clean_lsp_url(&msg.file_path) {
Some(u) => u,
None => continue,
};
let diagnostic_item = Diagnostic {
range: Range {
start: Position {
line,
character: column,
},
end: Position {
line,
character: u32::MAX,
},
},
severity: Some(severity),
code: None,
source: Some("mist-analyzer".to_string()),
message: msg.message.clone(),
related_information: None,
tags: None,
data: None,
code_description: None,
};
diagnostics
.entry(url)
.or_insert_with(Vec::new)
.push(diagnostic_item);
}
for (file, _) in self.previous_diagnostics.lock().await.iter() {
self.client
.publish_diagnostics(file.clone(), Vec::new(), None)
.await;
}
for (file, diag) in &diagnostics {
self.client
.publish_diagnostics(file.clone(), diag.clone(), None)
.await;
}
*self.previous_diagnostics.lock().await = diagnostics;
}
async fn did_open(&self, mut params: DidOpenTextDocumentParams) {
if params.text_document.language_id == "mist" {
let original_text = params.text_document.text.clone();
self.documents.lock().await.insert(
params.text_document.uri.to_file_path().unwrap(),
Rope::from_str(&original_text),
);
params.text_document.language_id = "rust".to_string();
match transpiler::transpile_text(&original_text) {
Ok(transpiled_text) => {
params.text_document.text = transpiled_text;
let rust_path =
from_mist_to_rust(params.text_document.uri.to_file_path().unwrap());
params.text_document.uri = Url::from_file_path(&rust_path).unwrap();
self.mapping.lock().await.insert(
rust_path,
rev_mapper::get_mapping(&params.text_document.text),
);
}
Err(e) => {
self.client
.log_message(
MessageType::WARNING,
format!("MIST-LSP: Syntax invalid during open/change: {:?}", e),
)
.await;
return;
}
}
}
if let Ok(mut ra) = self.rust_analyzer.try_lock() {
let _ = ra
.notify(notification::DidOpenTextDocument::METHOD, params)
.await;
}
}
async fn did_change(&self, mut params: DidChangeTextDocumentParams) {
let mist_path = params.text_document.uri.to_file_path().unwrap();
let rust_path = from_mist_to_rust(mist_path.clone());
let rust_uri = Url::from_file_path(&rust_path).unwrap();
if let Some(change) = params.content_changes.first_mut() {
self.documents
.lock()
.await
.insert(mist_path, Rope::from_str(&change.text));
match transpiler::transpile_text(&change.text) {
Ok(transpiled_text) => {
change.text = transpiled_text;
self.mapping
.lock()
.await
.insert(rust_path, rev_mapper::get_mapping(&change.text));
}
Err(e) => {
self.client
.log_message(
MessageType::WARNING,
format!("MIST-LSP: Syntax invalid during change: {:?}", e),
)
.await;
return;
}
}
}
params.text_document.uri = rust_uri;
if let Ok(mut ra) = self.rust_analyzer.try_lock() {
let _ = ra
.notify(notification::DidChangeTextDocument::METHOD, params)
.await;
}
}
async fn did_close(&self, mut params: DidCloseTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "MIST-LSP: Processing did_close event")
.await;
let rust_path = from_mist_to_rust(params.text_document.uri.to_file_path().unwrap());
let mist_path = params.text_document.uri.to_file_path().unwrap();
self.documents.lock().await.remove(&mist_path);
self.mapping.lock().await.remove(&rust_path);
params.text_document.uri = Url::from_file_path(&rust_path).unwrap();
if let Ok(mut ra) = self.rust_analyzer.try_lock() {
let _ = ra
.notify(notification::DidCloseTextDocument::METHOD, params)
.await;
}
}
async fn goto_definition(
&self,
params: GotoDefinitionParams,
) -> Result<Option<GotoDefinitionResponse>> {
let file_path = params
.text_document_position_params
.text_document
.uri
.to_file_path()
.unwrap();
let source = match self.documents.lock().await.get(&file_path) {
Some(doc) => doc.clone(),
None => return Ok(None),
};
let inject = "__mist_23";
let injected_source = insert_at_position(
&source,
params.text_document_position_params.position.line as usize + 1,
params.text_document_position_params.position.character as usize,
&inject,
);
let output = Rope::from_str(
&match transpiler::transpile_text(&injected_source.to_string()) {
Ok(out) => out,
Err(_) => return Ok(None),
},
);
let (line, character) = match find_row_col(&output, inject) {
Some(coords) => coords,
None => return Ok(None),
};
let uri =
Url::from_file_path(from_mist_to_rust(file_path)).expect("failed to generate rs url");
let rs_res = self
.rust_analyzer
.lock()
.await
.request::<request::GotoDefinition>(lsp_types::GotoDefinitionParams {
text_document_position_params: lsp_types::TextDocumentPositionParams {
position: lsp_types::Position {
line: line as u32,
character: character as u32,
},
text_document: lsp_types::TextDocumentIdentifier { uri },
},
partial_result_params: lsp_types::PartialResultParams::default(),
work_done_progress_params: lsp_types::WorkDoneProgressParams::default(),
})
.await
.expect("Failed to send to rust");
Ok(match rs_res {
Some(GotoDefinitionResponse::Array(arr)) => {
let mut mapped_arr = Vec::new();
for rs_loc in arr {
let mapped_loc = self.get_mist_location(rs_loc).await;
mapped_arr.push(mapped_loc);
}
Some(GotoDefinitionResponse::Array(mapped_arr))
}
_ => rs_res,
})
}
async fn completion(&self, mut params: CompletionParams) -> Result<Option<CompletionResponse>> {
self.client
.log_message(MessageType::INFO, "COMPLETEING!")
.await;
let file_path = params
.text_document_position
.text_document
.uri
.to_file_path()
.unwrap();
let source = match self.documents.lock().await.get(&file_path) {
Some(doc) => doc.clone(),
None => return Ok(None),
};
let inject = "__mist_23";
let injected_source = insert_at_position(
&source,
params.text_document_position.position.line as usize + 1,
params.text_document_position.position.character as usize,
&inject,
);
let output = Rope::from_str(
&match transpiler::transpile_text(&injected_source.to_string()) {
Ok(out) => out,
Err(_) => return Ok(None),
},
);
let (line, character) = match find_row_col(&output, inject) {
Some(coords) => coords,
None => return Ok(None),
};
let uri =
Url::from_file_path(from_mist_to_rust(file_path)).expect("failed to generate rs url");
params.text_document_position.text_document.uri = uri;
params.text_document_position.position.line = line as u32;
params.text_document_position.position.character = character as u32;
let rs_res = self
.rust_analyzer
.lock()
.await
.request::<request::Completion>(params)
.await
.expect("Failed to send to rust");
Ok(rs_res.map(|rs_res| match rs_res {
CompletionResponse::Array(items) => {
CompletionResponse::Array(items.into_iter().map(simplify_item).collect())
}
CompletionResponse::List(list) => {
CompletionResponse::Array(list.items.into_iter().map(simplify_item).collect())
}
}))
}
async fn completion_resolve(&self, params: CompletionItem) -> Result<CompletionItem> {
match self
.rust_analyzer
.lock()
.await
.request::<request::ResolveCompletionItem>(params.clone())
.await
{
Ok(o) => Ok(o),
_ => Ok(params),
}
}
}
#[tokio::main]
pub async fn start() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(|client| Backend {
client,
workspace_folder: Arc::new(Mutex::new(None)),
previous_diagnostics: Arc::new(Mutex::new(HashMap::new())),
mapping: Arc::new(Mutex::new(HashMap::new())),
documents: Arc::new(Mutex::new(HashMap::new())),
rust_analyzer: Arc::new(Mutex::new(
RustAnalyzer::new().expect("Failed to create rust analyzer"),
)),
});
Server::new(stdin, stdout, socket).serve(service).await;
}
pub fn from_mist_to_rust(mut path: PathBuf) -> PathBuf {
path.set_extension("rs");
let mut comps: Vec<Component> = path.components().collect();
if let Some(pos) = comps.iter().rposition(|c| c.as_os_str() == "src") {
let replacement = std::path::Path::new(".mist/src");
comps.splice(pos..=pos, replacement.components());
comps.iter().collect()
} else {
path
}
}
pub fn from_rust_to_mist(mut path: PathBuf) -> PathBuf {
// reverse extension
path.set_extension("mist");
let comps: Vec<Component> = path.components().collect();
let pattern: Vec<Component> = std::path::Path::new(".mist/src").components().collect();
// find the last occurrence of the pattern
if let Some(pos) = comps
.windows(pattern.len())
.rposition(|window| window == pattern.as_slice())
{
let mut new_comps = comps.clone();
// replace the matched range with "src"
new_comps.splice(
pos..pos + pattern.len(),
std::iter::once(Component::Normal(std::ffi::OsStr::new("src"))),
);
new_comps.iter().collect()
} else {
path
}
}
fn insert_at_position(rope: &Rope, line: usize, col: usize, insert: &str) -> Rope {
let mut rope = rope.clone();
let line_idx = line.saturating_sub(1);
let col_idx = col.saturating_sub(1);
let line_idx = line_idx.min(rope.len_lines().saturating_sub(1));
let line_start = rope.line_to_char(line_idx);
let line_slice = rope.line(line_idx);
let line_len = line_slice.len_chars();
let col_idx = col_idx.min(line_len);
let idx = line_start + col_idx;
rope.insert(idx, insert);
rope
}
fn find_row_col(rope: &Rope, needle: &str) -> Option<(usize, usize)> {
let text = rope.to_string();
let byte_idx = text.find(needle)?;
let char_idx = text[..byte_idx].chars().count();
let line_idx = rope.char_to_line(char_idx);
let line_start = rope.line_to_char(line_idx);
let col_idx = char_idx - line_start;
Some((line_idx, col_idx + 1))
}
fn simplify_item(mut item: CompletionItem) -> CompletionItem {
item.text_edit = None;
item.additional_text_edits = None;
item.command = None;
item
}
fn collect_mist_files(dir: &PathBuf, out: &mut Vec<PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_mist_files(&path, out);
} else if path.extension().and_then(|e| e.to_str()) == Some("mist") {
out.push(path);
}
}
}
+297
View File
@@ -0,0 +1,297 @@
use std::{collections::HashMap, path::PathBuf, process::Stdio, sync::Arc, time::Duration};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::{Value, json};
use tokio::{
io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader},
sync::{Mutex, oneshot},
time::timeout,
};
use tower_lsp::lsp_types::{
self, ClientCapabilities, InitializeParams, InitializedParams, Url, WorkspaceFolder,
notification::{Initialized, Notification},
request::{self, Request},
};
const MAX_CONTENT_LENGTH: usize = 50 * 1024 * 1024;
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Deserialize)]
pub struct JsonRpcResponse<T> {
pub jsonrpc: String,
pub id: Option<serde_json::Value>,
pub result: Option<T>,
pub error: Option<JsonRpcError>,
}
#[derive(Debug, Deserialize)]
pub struct JsonRpcError {
pub code: i64,
pub message: String,
pub data: Option<serde_json::Value>,
}
type PendingMap = Arc<Mutex<HashMap<usize, oneshot::Sender<Result<Value, String>>>>>;
#[derive(Debug)]
pub struct RustAnalyzer {
// Wrapped in a Mutex to support safe concurrent sharing if the design expands
stdin: Arc<Mutex<tokio::process::ChildStdin>>,
pending: PendingMap,
id: usize,
// Keep child handler to explicitly manage child process lifecycle and prevent zombie processes
_child: tokio::process::Child,
}
async fn send_lsp_message<W: AsyncWriteExt + Unpin>(
writer: &mut W,
value: &serde_json::Value,
) -> std::io::Result<()> {
let payload = serde_json::to_string(value)?;
let frame = format!("Content-Length: {}\r\n\r\n{}", payload.len(), payload);
writer.write_all(frame.as_bytes()).await?;
writer.flush().await?;
Ok(())
}
async fn read_lsp_message<R: AsyncBufReadExt + Unpin>(
reader: &mut R,
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let mut line = String::new();
let mut content_length = 0;
// Guard against infinite header reading attacks/bugs (Max 100 headers)
for _ in 0..100 {
line.clear();
let bytes_read = reader.read_line(&mut line).await?;
if bytes_read == 0 || line == "\r\n" || line.is_empty() {
break;
}
if line.to_ascii_lowercase().starts_with("content-length:") {
if let Some(val_str) = line.split(':').nth(1) {
content_length = val_str.trim().parse::<usize>()?;
}
}
}
// Explode early if payload size violates strict guard rails to prevent memory-exhaustion (OOM)
if content_length == 0 {
return Err("Missing, invalid, or zero Content-Length header".into());
}
if content_length > MAX_CONTENT_LENGTH {
return Err(format!(
"Content-Length {} exceeds maximum threshold",
content_length
)
.into());
}
// Explicitly secure pre-allocation limit
let mut buffer = vec![0u8; content_length];
reader.read_exact(&mut buffer).await?;
Ok(String::from_utf8(buffer)?)
}
impl RustAnalyzer {
pub fn new() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let mut child = tokio::process::Command::new("rust-analyzer")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?;
let stdin = child
.stdin
.take()
.ok_or("Failed to open child stdin pipe")?;
let stdout = child
.stdout
.take()
.ok_or("Failed to open child stdout pipe")?;
let pending: PendingMap = Arc::new(Mutex::new(HashMap::new()));
let pending_clone = pending.clone();
// Background supervisor task loop
tokio::spawn(async move {
let mut stdout = BufReader::new(stdout);
loop {
let raw = match read_lsp_message(&mut stdout).await {
Ok(v) => v,
Err(err) => {
eprintln!("LSP fatal stream read failure: {err}");
// CRITICAL: Notify all pending channels that the bridge broke down
let mut lock = pending_clone.lock().await;
for (_, tx) in lock.drain() {
let _ = tx.send(Err(format!("LSP reader task dropped: {}", err)));
}
break;
}
};
let value: Value = match serde_json::from_str(&raw) {
Ok(v) => v,
Err(err) => {
eprintln!("Corrupted JSON received: {err}");
continue; // Keep the connection running despite malformed frame
}
};
// Filter server notification frames
if value.get("method").is_some() && value.get("id").is_none() {
continue;
}
let id = value.get("id").and_then(|v| v.as_u64()).map(|v| v as usize);
if let Some(id) = id {
let tx = pending_clone.lock().await.remove(&id);
if let Some(tx) = tx {
let _ = tx.send(Ok(value));
} else {
eprintln!("Received orphaned or delayed frame for ID: {id}");
}
} else {
eprintln!("Received unhandled protocol notification framework: {raw}");
}
}
});
Ok(Self {
stdin: Arc::new(Mutex::new(stdin)),
pending,
id: 0,
_child: child,
})
}
pub async fn request<R: Request>(
&mut self,
params: R::Params,
) -> Result<R::Result, Box<dyn std::error::Error + Send + Sync>>
where
R::Result: DeserializeOwned,
{
let id = {
self.id += 1;
self.id
};
let (tx, rx) = oneshot::channel();
// Scope the lock allocation tightly
{
self.pending.lock().await.insert(id, tx);
}
let payload = json!({
"jsonrpc": "2.0",
"id": id,
"method": R::METHOD,
"params": params,
});
// Acquire lock on writing stream to ensure thread safety
let mut stdin_lock = self.stdin.lock().await;
if let Err(err) = send_lsp_message(&mut *stdin_lock, &payload).await {
// Rollback the pending map operation to avoid internal memory memory-leaks if serialization/IO errors trigger
self.pending.lock().await.remove(&id);
return Err(Box::new(err));
}
// Explicit drop of write lock early so other operations can pipe messages synchronously
drop(stdin_lock);
// Enforce an absolute time constraint limit to break free from hanging processes
let response_payload = match timeout(REQUEST_TIMEOUT, rx).await {
Ok(Ok(Ok(value))) => value,
Ok(Ok(Err(task_err))) => return Err(task_err.into()),
Ok(Err(_oneshot_canceled)) => {
return Err(
"Bridge connection closed down; reader channel dropped unexpectedly".into(),
);
}
Err(_timeout_elapsed) => {
// Clear state tracking entries dynamically upon expiration failure
self.pending.lock().await.remove(&id);
return Err(
format!("Request ID {} timed out after {:?}", id, REQUEST_TIMEOUT).into(),
);
}
};
let envelope: JsonRpcResponse<R::Result> =
serde_json::from_value(response_payload.clone())?;
if let Some(err) = envelope.error {
return Err(format!("LSP Engine Error ({}): {}", err.code, err.message).into());
}
envelope.result.ok_or_else(|| {
format!(
"Missing inner structural payload result: {:?}",
response_payload
)
.into()
})
}
pub async fn notify<T: Serialize>(
&mut self,
method: &str,
req: T,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let payload = json!({
"jsonrpc": "2.0",
"method": method,
"params": req,
});
let mut stdin_lock = self.stdin.lock().await;
send_lsp_message(&mut *stdin_lock, &payload).await?;
Ok(())
}
}
impl RustAnalyzer {
pub async fn initialize(
&mut self,
root: &PathBuf,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let project_uri = Url::from_directory_path(root)
.map_err(|_| "Failed to convert path to valid file:// URL")?;
#[allow(deprecated)]
let init_params = InitializeParams {
process_id: Some(std::process::id()),
root_uri: Some(project_uri.clone()),
workspace_folders: Some(vec![WorkspaceFolder {
uri: project_uri,
name: "workspace".to_string(),
}]),
capabilities: ClientCapabilities {
workspace: Some(lsp_types::WorkspaceClientCapabilities {
workspace_folders: Some(true),
..Default::default()
}),
text_document: Some(lsp_types::TextDocumentClientCapabilities {
..Default::default()
}),
..Default::default()
},
..Default::default()
};
self.request::<request::Initialize>(init_params).await?;
Ok(())
}
pub async fn initialized(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.notify(Initialized::METHOD, InitializedParams {})
.await?;
Ok(())
}
}
+160
View File
@@ -0,0 +1,160 @@
use std::{
fs,
path::{Path, PathBuf},
};
use mist_parser::{ast::TopLevel, error::ParseError};
pub fn build(root: &PathBuf) {
let src_dir = root.join("src");
let out_dir = root.join(".mist/src");
if let Err(e) = build_dir(root, &src_dir, &src_dir, &out_dir) {
eprintln!("Warning: Build directory run aborted safely: {e}");
}
}
fn build_dir(
root: &Path,
base_src: &Path,
current_dir: &Path,
out_dir: &Path,
) -> Result<(), String> {
let entries = fs::read_dir(current_dir)
.map_err(|e| format!("failed to read directory {}: {}", current_dir.display(), e))?;
for entry in entries {
let entry = match entry {
Ok(entry) => entry,
Err(e) => {
eprintln!("Warning: Skipping invalid directory entry: {e}");
continue; // Skip corrupted entry instead of crashing
}
};
let path = entry.path();
// Recurse into nested directories
if path.is_dir() {
if let Err(e) = build_dir(root, base_src, &path, out_dir) {
eprintln!("Warning: Nested build directory failed: {e}");
}
continue;
}
// Safe prefix stripping fallback
let relative = match path.strip_prefix(base_src) {
Ok(p) => p,
Err(_) => {
eprintln!(
"Warning: Path {} is outside base source directory",
path.display()
);
continue;
}
};
// Handle non-mist files with a cache check
if path.extension().and_then(|e| e.to_str()) != Some("mist") {
let dest_path = out_dir.join(relative);
// Create parent directories for static assets if needed
if let Some(parent) = dest_path.parent() {
let _ = fs::create_dir_all(parent);
}
if should_skip(&path, &dest_path) {
continue;
}
if let Err(e) = fs::copy(&path, &dest_path) {
eprintln!(
"Warning: Failed to copy non-mist file {}: {}",
path.display(),
e
);
}
continue;
}
let output_path = out_dir.join(relative).with_extension("rs");
// Cache layer: Skip if the generated .rs file is newer than the .mist source
if should_skip(&path, &output_path) {
continue;
}
if let Err(e) = transpile_file(&path, &output_path) {
eprintln!(
"Warning: Transpilation failed for {}: {}",
path.display(),
e
);
}
}
Ok(())
}
pub fn transpile_file(path: &Path, output_path: &Path) -> Result<(), String> {
// Create parent directories
if let Some(parent) = output_path.parent() {
fs::create_dir_all(parent).map_err(|e| {
format!(
"failed to create output directory {}: {}",
parent.display(),
e
)
})?;
}
// Read source
let source = fs::read_to_string(path)
.map_err(|e| format!("failed to read file {}: {}", path.display(), e))?;
let parser_result = mist_parser::parse(&source).map_err(|e| match e {
ParseError::Ast(e) => {
// Using components carefully to prevent out-of-bounds or zero layout crashes
let start_pos = e.span.start_pos().line_col();
let span = e.span.as_str();
format!(
"\n{}:{}:{}\n Error: {}\n\t{}{}\t{}",
path.display(),
start_pos.0,
start_pos.1,
e.error_message,
span,
if span.ends_with('\n') { "" } else { "\n" },
"^".repeat(span.trim().len()),
)
}
ParseError::PreAst(e) => format!("{e}"),
});
// If parsing fails, return the error string back gracefully so the LSP can show it
let ast = parser_result.map_err(|e| format!("parse failed in {}:\n{}", path.display(), e))?;
let mut gc = mist_codegen::RustCodegen::new();
let output = gc.generate(ast);
fs::write(output_path, output)
.map_err(|e| format!("failed to write output {}: {}", output_path.display(), e))?;
Ok(())
}
pub fn transpile_text<'a>(source: &'a str) -> Result<String, ParseError<'a, Vec<TopLevel>>> {
let mut gc = mist_codegen::RustCodegen::new();
Ok(gc.generate(mist_parser::parse(&source)?))
}
fn should_skip(source: &Path, output: &Path) -> bool {
if let (Ok(src_meta), Ok(out_meta)) = (fs::metadata(source), fs::metadata(output)) {
if let (Ok(src_time), Ok(out_time)) = (src_meta.modified(), out_meta.modified()) {
return out_time >= src_time;
}
}
false
}
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "mist-codegen"
version = "0.1.7-alpha.0"
edition = "2024"
description = "The Mist programming language Rust code generator"
license = "Apache-2.0"
repository = "https://github.com/mist-go/mist"
keywords = ["compiler", "language", "mist"]
categories = ["compilers"]
[dependencies]
mist-parser = { workspace = true }
+268
View File
@@ -0,0 +1,268 @@
use mist_parser::ast::*;
use crate::Context;
use crate::{GenRust, GetRust, RustCodegen};
impl GetRust for ExprPath {
fn get_rust(&self) -> String {
self.0
.iter()
.map(ExprPathSegment::get_rust)
.collect::<Vec<_>>()
.join("::")
}
}
impl GetRust for ExprPathSegment {
fn get_rust(&self) -> String {
format!(
"{}{}",
self.ident.get_rust(),
self.generics
.as_ref()
.map(|v| format!("::{}", v.get_rust()))
.unwrap_or_default()
)
}
}
impl GenRust for Literal {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::Int(n) => cg.add(&n.to_string()),
Self::Float(n) => cg.add(&format!("{n:?}")),
Self::Bool(b) => cg.add(&b.to_string()),
Self::String(s) => cg.add(&format!("\"{s}\"")),
Self::Tuple(values) => {
cg.add("(");
for val in values {
val.gen_rust(ctx, cg);
}
cg.add(")");
}
Self::Array(values) => {
cg.add("[");
for val in values {
val.gen_rust(ctx, cg);
}
cg.add("]");
}
Self::ArrayRepeat(value, repeat) => {
cg.add("[");
value.gen_rust(ctx, cg);
cg.add("; ");
repeat.gen_rust(ctx, cg);
cg.add("]");
}
}
}
}
impl GenRust for Expression {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
let ensure_semicolon = if ctx.expr_ensure_semicolon {
ctx.expr_ensure_semicolon = false;
true
} else {
false
};
match self {
Expression::Path(path) => cg.add(&path.get_rust()),
Expression::Literal(literal) => literal.gen_rust(ctx, cg),
Expression::Statement(stmt) => stmt.gen_rust(ctx, cg),
Expression::Fix {
initial,
prefixes,
postfixes,
} => {
prefixes.gen_rust(ctx, cg);
initial.gen_rust(ctx, cg);
cg.add(&Some(prefixes).get_rust());
for postfix in postfixes {
postfix.gen_rust(ctx, cg);
}
}
// Safely integrated to handle the tree structure built by the Pratt Parser
Expression::Binary { lhs, op, rhs } => {
lhs.gen_rust(ctx, cg);
cg.add(op);
rhs.gen_rust(ctx, cg);
}
}
if ensure_semicolon {
ctx.expr_ensure_semicolon = true;
if !self.is_block() {
cg.add(";");
}
}
}
}
impl GenRust for Prefix {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::Deref => cg.add("*"),
Self::Ref => cg.add("&"),
Self::RefMut => cg.add("&mut "),
Self::Not => cg.add("!"),
Self::New(_) => cg.add(""),
Self::Neg => cg.add("-"),
Self::Closure(ty, args) => {
cg.add("|");
for (i, arg) in args.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
arg.gen_rust(ctx, cg);
}
cg.add("| ");
if let Some(ty) = ty {
cg.add("-> ");
cg.add(&ty.get_rust());
cg.add(" ");
}
}
}
}
}
impl GenRust for Vec<Prefix> {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
for prefix in self {
prefix.gen_rust(ctx, cg);
}
}
}
impl GetRust for Option<&Vec<Prefix>> {
fn get_rust(&self) -> String {
if let Some(prefixes) = self {
prefixes
.into_iter()
.last()
.map(|p| match p {
Prefix::New(generics) => format!(
"::new{}",
generics
.clone()
.map(|v| format!("::{}", v.get_rust()))
.unwrap_or_default(),
),
_ => String::new(),
})
.unwrap_or_default()
.to_string()
} else {
String::new()
}
}
}
impl GenRust for Postfix {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Postfix::FieldAccess(field, generics) => cg.add(&format!(
".{}{}",
field.get_rust(),
generics
.iter()
.map(|v| format!("::{}", v.get_rust()))
.collect::<String>()
)),
Postfix::Call(args) => {
cg.add("(");
for (i, arg) in args.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
arg.gen_rust(ctx, cg);
}
cg.add(")");
}
Postfix::MacroCall(inner) => {
cg.add("!(");
cg.add(inner);
cg.add(")");
}
Postfix::StructCall(fields) => {
cg.add("{");
for (name, expr) in fields {
cg.add(&name.get_rust());
cg.add(": ");
expr.gen_rust(ctx, cg);
cg.add(",");
}
cg.add("}");
}
Postfix::Index(idx) => {
cg.add("[");
idx.gen_rust(ctx, cg);
cg.add("]");
}
Postfix::As(ty) => {
cg.add(" as ");
cg.add(&ty.get_rust());
}
Postfix::Try => cg.add("?"),
Postfix::Assign(cmp, expr) => {
cg.add(" ");
cg.add(cmp);
expr.gen_rust(ctx, cg);
}
Postfix::Increment => cg.add("+=1"),
Postfix::Decrement => cg.add("-=1"),
}
}
}
impl GetRust for Generics {
fn get_rust(&self) -> String {
if self.0.len() == 0 {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(Generic::get_rust)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetRust for Generic {
fn get_rust(&self) -> String {
match self {
Self::Lifetime(name) => format!("'{}", name.get_rust()),
Self::Type(ty) => ty.get_rust(),
}
}
}
+278
View File
@@ -0,0 +1,278 @@
pub mod expr;
pub mod statement;
pub mod top_level;
use mist_parser::ast::*;
pub struct Context {
pub expr_ensure_semicolon: bool,
}
pub trait GenRust {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen);
}
pub trait GetRust {
fn get_rust(&self) -> String;
}
#[derive(Default)]
pub struct RustCodegen {
output: String,
indent: usize,
}
impl RustCodegen {
pub fn new() -> Self {
Self {
output: String::new(),
indent: 0,
}
}
fn indent_str(&self) -> String {
" ".repeat(self.indent)
}
fn add(&mut self, s: &str) {
self.output.push_str(s);
}
fn addln(&mut self, s: &str) {
self.add(s);
self.add("\n");
}
fn add_indented(&mut self, s: &str) {
let line = format!("{}{}", self.indent_str(), s);
self.add(&line);
}
fn add_indentedln(&mut self, s: &str) {
let line = format!("{}{}\n", self.indent_str(), s);
self.add(&line);
}
pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
let mut ctx = Context {
expr_ensure_semicolon: true,
};
for tl in toplevels {
tl.gen_rust(&mut ctx, self);
}
self.output.clone()
}
pub fn ensure_brackets(&mut self, ctx: &mut Context, stmt: &Box<Statement>) {
match &**stmt {
Statement::Block(_) => stmt.gen_rust(ctx, self),
_ => {
self.add("{");
self.indent += 1;
stmt.gen_rust(ctx, self);
self.indent -= 1;
self.add("}");
}
}
}
pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) {
match expr {
Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt),
_ => {
self.add("{");
self.indent += 1;
expr.gen_rust(ctx, self);
self.indent -= 1;
self.add("}");
}
}
}
pub fn ensure_brackets_body(&mut self, ctx: &mut Context, body: &StatementBody) {
match body {
StatementBody::Expression(expr) => self.ensure_brackets_expr(ctx, expr),
StatementBody::Statement(expr) => {
ctx.expr_ensure_semicolon = true;
self.ensure_brackets_expr(ctx, expr);
}
}
}
}
impl GenRust for Attribute {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::Path(path) => cg.add(&path.get_rust()),
Self::NameValue { path, value } => {
cg.add(&format!("{} = ", path.get_rust()));
value.gen_rust(ctx, cg);
}
Self::List { path, items } => {
cg.add(&path.get_rust());
cg.add("(");
for (i, item) in items.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
item.gen_rust(ctx, cg);
}
cg.add(")");
}
}
}
}
impl<T: GetRust> GetRust for Spanned<T> {
fn get_rust(&self) -> String {
format!(
"/* {}:{} */ {}",
self.line,
self.column,
self.item.get_rust()
)
}
}
impl<T: GenRust> GenRust for Spanned<T> {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column));
cg.add_indented("");
self.item.gen_rust(ctx, cg);
}
}
impl GetRust for Path {
fn get_rust(&self) -> String {
self.0
.iter()
.map(Identifier::get_rust)
.collect::<Vec<String>>()
.join("::")
}
}
impl GetRust for TypePostfix {
fn get_rust(&self) -> String {
match self {
TypePostfix::Ref => format!("&"),
TypePostfix::RefMut => format!("&mut "),
TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
TypePostfix::Dyn => format!("dyn "),
}
}
}
impl GetRust for Visibility {
fn get_rust(&self) -> String {
match self {
Visibility::Public => "pub ".to_string(),
Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
Visibility::Private => "".to_string(),
}
}
}
impl GetRust for Identifier {
fn get_rust(&self) -> String {
self.0.clone()
}
}
impl GetRust for TypeExpr {
fn get_rust(&self) -> String {
self.1
.iter()
.map(TypePostfix::get_rust)
.rev()
.collect::<String>()
+ &self.0.get_rust()
}
}
pub fn get_static_type_path(path: &Path) -> String {
let rust_path = path.get_rust();
if rust_path == "void" {
format!("()")
} else {
rust_path
}
}
impl GetRust for TypeExprKind {
fn get_rust(&self) -> String {
match self {
TypeExprKind::Path(path) => get_static_type_path(path),
TypeExprKind::Lifetime(name) => format!("'{}", name.get_rust()),
TypeExprKind::PathParams(path, params) => {
format!(
"{}<{}>",
get_static_type_path(path),
params
.into_iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", ")
)
}
TypeExprKind::Tuple(types) => format!(
"({})",
types
.into_iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
impl GenRust for Pattern {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::Path(mutable, path) => {
if *mutable {
cg.add("mut ");
};
cg.add(&path.get_rust())
}
Self::Literal(lit) => lit.gen_rust(ctx, cg),
Self::Struct(path, inner) => {
cg.add(&path.get_rust());
cg.add(" {");
for pat in inner {
pat.gen_rust(ctx, cg);
cg.add(",");
}
cg.add("}");
}
Self::NamedTuple(path, inner) => {
cg.add(&path.get_rust());
cg.add(" (");
for pat in inner {
pat.gen_rust(ctx, cg);
cg.add(",");
}
cg.add(")");
}
Self::Tuple(inner) => {
cg.add("(");
for pat in inner {
pat.gen_rust(ctx, cg);
cg.add(",");
}
cg.add(")");
}
}
}
}
+201
View File
@@ -0,0 +1,201 @@
use mist_parser::ast::*;
use crate::Context;
use crate::{GenRust, GetRust, RustCodegen};
impl GenRust for Block {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.addln("{");
cg.indent += 1;
for stmt in &self.0 {
ctx.expr_ensure_semicolon = true;
stmt.gen_rust(ctx, cg);
cg.addln("");
}
if let Some(soft_return) = &self.1 {
ctx.expr_ensure_semicolon = false;
soft_return.gen_rust(ctx, cg);
cg.addln("");
}
cg.indent -= 1;
cg.add_indented("}");
}
}
impl GenRust for StatementBody {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::Expression(expr) => expr.gen_rust(ctx, cg),
Self::Statement(stmt) => {
ctx.expr_ensure_semicolon = true;
stmt.gen_rust(ctx, cg);
}
}
}
}
impl GenRust for Statement {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Statement::Block(block) => block.gen_rust(ctx, cg),
Statement::VarDecl(VarDeclStmt { decl, init }) => {
cg.add("let ");
decl.gen_rust(ctx, cg);
if let Some(init) = init {
cg.add(" = ");
init.gen_rust(ctx, cg);
}
}
Statement::Match(expr, match_items) => {
cg.add("match ");
expr.gen_rust(ctx, cg);
cg.add(" {");
cg.indent += 1;
for match_item in match_items {
cg.add_indentedln(&match_item.get_comment());
let MatchItem(pat, body) = &match_item.item;
for (i, p) in pat.iter().enumerate() {
cg.addln("");
cg.add_indented("");
if i > 0 {
cg.add(" | ");
}
p.gen_rust(ctx, cg);
}
cg.add(" => ");
cg.ensure_brackets_expr(ctx, body);
}
cg.indent -= 1;
cg.addln("");
cg.add_indented("}");
}
Statement::If {
initial,
else_if,
else_branch,
} => {
cg.add("if ");
initial.condition.gen_rust(ctx, cg);
cg.add(" ");
cg.ensure_brackets_body(ctx, &initial.body);
for else_if_branch in else_if {
cg.add("else if");
else_if_branch.condition.gen_rust(ctx, cg);
cg.add(" ");
cg.ensure_brackets_body(ctx, &else_if_branch.body);
}
if let Some(else_br) = else_branch {
cg.add(" else ");
cg.ensure_brackets_body(ctx, else_br);
}
}
Statement::While(StatementBranch { condition, body }) => {
cg.add("while ");
condition.gen_rust(ctx, cg);
cg.add(" ");
cg.ensure_brackets_body(ctx, body);
}
Statement::Loop(body) => {
cg.add("loop ");
cg.ensure_brackets_body(ctx, body);
}
Statement::CStyleFor {
init,
condition,
update,
body,
} => {
cg.addln("{");
cg.indent += 1;
ctx.expr_ensure_semicolon = true;
cg.add_indented("");
init.gen_rust(ctx, cg);
cg.addln("");
cg.add_indented("while ");
ctx.expr_ensure_semicolon = false;
condition.gen_rust(ctx, cg);
cg.add(" ");
cg.add("{");
cg.indent += 1;
ctx.expr_ensure_semicolon = true;
body.gen_rust(ctx, cg);
update.gen_rust(ctx, cg);
cg.addln("");
cg.indent -= 1;
cg.add_indentedln("}");
cg.indent -= 1;
cg.add_indented("}");
}
Statement::For {
pattern,
iterator,
body,
} => {
cg.add("for ");
pattern.gen_rust(ctx, cg);
cg.add(" in ");
iterator.gen_rust(ctx, cg);
cg.ensure_brackets_body(ctx, body);
}
Statement::Return(expr) => {
cg.add("return ");
if let Some(expr) = expr {
expr.gen_rust(ctx, cg);
}
}
Statement::Break => cg.add_indentedln("break"),
Statement::Continue => cg.add_indentedln("continue"),
}
}
}
impl GenRust for VarDecl {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
self.name.gen_rust(ctx, cg);
cg.add(
&self
.type_
.as_ref()
.map(|t| format!(": {}", t.get_rust()))
.unwrap_or_default(),
);
}
}
+440
View File
@@ -0,0 +1,440 @@
use mist_parser::ast::*;
use crate::Context;
use crate::{GenRust, GetRust, RustCodegen};
impl GetRust for GenericsDecl {
fn get_rust(&self) -> String {
if self.0.len() == 0 {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(|v| v.get_rust())
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetRust for GenericDecl {
fn get_rust(&self) -> String {
match self {
GenericDecl::Lifetime(name) => format!("'{}", name.get_rust()),
GenericDecl::Type(name, requirements) => {
name.get_rust()
+ &(if requirements.len() != 0 {
format!(
": {}",
requirements
.into_iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join("+")
)
} else {
String::new()
})
}
}
}
}
impl GenRust for ImplDecl {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
if let Some(trait_) = &self.trait_ {
cg.add_indentedln(&format!(
"impl{} {} for {} {{",
self.generics.get_rust(),
trait_.get_rust(),
self.target.get_rust()
));
} else {
cg.add_indentedln(&format!(
"impl{} {} {{",
self.generics.get_rust(),
self.target.get_rust()
));
}
cg.indent += 1;
for method in &self.methods {
method.gen_rust(ctx, cg);
}
cg.indent -= 1;
cg.add_indentedln("}");
}
}
impl GenRust for FunctionDecl {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add(&format!(
"{}fn {}{}(",
self.visibility.get_rust(),
self.name.get_rust(),
self.generics.get_rust(),
));
for (i, param) in self.params.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_rust(ctx, cg);
}
cg.add(") -> ");
cg.add(&self.return_type.get_rust());
if let Some(body) = &self.body {
cg.add(" ");
body.gen_rust(ctx, cg);
} else {
cg.add(";");
}
}
}
impl GetRust for FieldDecl {
fn get_rust(&self) -> String {
format!(
"{}{}: {},",
self.visibility.get_rust(),
self.name.get_rust(),
self.type_.get_rust()
)
}
}
impl GetRust for EnumItem {
fn get_rust(&self) -> String {
match self {
Self::Named(id) => id.get_rust(),
Self::Struct(id, s) => format!(
"{} {{{}}}",
id.get_rust(),
s.into_iter()
.map(|field| format!("{}: {}", field.name.get_rust(), field.type_.get_rust()))
.collect::<Vec<_>>()
.join(", ")
),
Self::Tuple(id, t) => format!(
"{} ({})",
id.get_rust(),
t.into_iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
impl GenRust for ParamList {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
for (i, param) in self.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_rust(ctx, cg);
}
}
}
impl GenRust for TopLevel {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
if let TopLevelKind::ModAttribute = self.0.item {
for attr in &self.1 {
cg.add("#![");
attr.gen_rust(ctx, cg);
cg.addln("]");
}
} else {
for attr in &self.1 {
cg.add("#[");
attr.gen_rust(ctx, cg);
cg.addln("]");
}
}
self.0.gen_rust(ctx, cg);
}
}
impl GenRust for (&Vec<Spanned<FieldDeclStmt>>, &Spanned<ClassConstructor>) {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add_indented(&format!(
"{}fn new{}(",
self.1.item.visibility.get_rust(),
self.1.item.generics.get_rust()
));
self.1.item.params.gen_rust(ctx, cg);
cg.addln(") -> Self {");
cg.indent += 1;
cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };");
for field in self.0 {
let comment = field.get_comment();
if let Some(init) = &field.item.init {
cg.add_indentedln(&comment);
cg.add_indentedln(&format!("this.{} = ", field.item.decl.name.get_rust()));
init.gen_rust(ctx, cg);
}
}
cg.add_indented(&format!("this.constructor("));
for (i, param) in self.1.item.params.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.name.gen_rust(ctx, cg);
}
cg.addln(");");
cg.add_indentedln("this");
cg.indent -= 1;
cg.add_indentedln("}\n");
let mut constructor_params = vec![VarDecl {
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
type_: Some(TypeExpr(
TypeExprKind::Path(Path(vec![Identifier(String::from("Self"))])),
vec![TypePostfix::RefMut],
)),
}];
constructor_params.append(&mut self.1.item.params.0.clone());
Spanned {
line: self.1.line,
column: self.1.column,
item: FunctionDecl {
visibility: self.1.item.visibility.clone(),
name: Identifier(String::from("constructor")),
generics: self.1.item.generics.clone(),
params: ParamList(constructor_params),
return_type: TypeExpr::no_px(TypeExprKind::Tuple(Vec::new())),
body: Some(self.1.item.body.clone()),
},
}
.gen_rust(ctx, cg);
}
}
impl GenRust for TopLevelKind {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self {
Self::ModAttribute => {}
Self::Import(vis, path) => {
cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust()))
}
Self::Mod(vis, id) => cg.addln(&format!("{}mod {};", vis.get_rust(), id.get_rust())),
Self::FunctionDecl(decl) => decl.gen_rust(ctx, cg),
Self::ImplDecl(impl_) => impl_.gen_rust(ctx, cg),
Self::StructDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}struct {}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
for field in fields {
cg.add_indentedln(&field.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::EnumDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}enum {}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
for field in fields {
cg.add_indentedln(&(field.get_rust() + ","));
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::TraitDecl {
visibility,
name,
generics,
requirements,
items,
} => {
cg.addln(&format!(
"{}trait {}{}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust(),
if requirements.len() != 0 {
String::from(": ")
+ &requirements
.into_iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join("+")
} else {
String::new()
},
));
cg.indent += 1;
for item in items {
item.gen_rust(ctx, cg);
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::ClassDecl {
visibility,
name,
generics,
inherits,
fields,
constructor,
items,
} => {
// Struct decl
cg.addln(&format!(
"{}struct {}{} {{",
visibility.get_rust(),
name.clone().get_rust(),
generics.clone().get_rust()
));
cg.indent += 1;
if let Some(inherits) = inherits {
cg.add_indented("pub _super: ");
cg.add(&inherits.get_rust());
cg.addln(",");
}
for field in fields.clone() {
cg.add_indentedln(&field.get_comment());
cg.add_indentedln(&field.item.decl.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
// Constructor
cg.addln(&format!(
"impl{} {}{} {{",
generics.clone().get_rust(),
name.clone().get_rust(),
format!(
"<{}>",
generics
.clone()
.0
.into_iter()
.map(|v| Generic::from(v).get_rust())
.collect::<Vec<_>>()
.join(", ")
)
));
cg.indent += 1;
let constructor_comment = constructor.get_comment();
cg.add_indentedln("#[allow(invalid_value)]");
cg.add_indentedln(&constructor_comment);
(fields, constructor).gen_rust(ctx, cg);
for item in items.clone() {
match item {
ClassItem::ImplDecl(_) => {}
ClassItem::Method(method) => method.gen_rust(ctx, cg),
}
}
cg.indent -= 1;
cg.addln("}\n");
for item in items {
match item {
ClassItem::ImplDecl(impl_) => {
let mut impl_ = impl_.clone();
impl_.item.trait_ = Some(impl_.item.target);
impl_.item.target =
TypeExpr(TypeExprKind::Path(Path(vec![name.clone()])), Vec::new());
impl_.gen_rust(ctx, cg);
}
ClassItem::Method(_) => {}
}
}
if let Some(inherits) = inherits {
cg.add("impl std::ops::Deref for ");
cg.add(&name.get_rust());
cg.addln(" {");
cg.indent += 1;
cg.add_indented("type Target = ");
cg.add(&inherits.get_rust());
cg.addln(";");
cg.add_indentedln("fn deref(&self) -> &Self::Target {&self._super}");
cg.indent -= 1;
cg.addln("}");
// Mut
cg.add("impl std::ops::DerefMut for ");
cg.add(&name.get_rust());
cg.addln(" {");
cg.indent += 1;
cg.add_indentedln(
"fn deref_mut(&mut self) -> &mut Self::Target {&mut self._super}",
);
cg.indent -= 1;
cg.addln("}");
}
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
[package]
name = "mist-api"
version = "0.1.7-alpha.1"
edition = "2024"
description = "The Mist programming language module system"
license = "Apache-2.0"
repository = "https://github.com/mist-go/mist"
keywords = ["compiler", "language", "mist", "module-system"]
categories = ["compilers"]
include = [
".mist/src/**",
"Cargo.toml",
"README.md",
]
[dependencies]
serde = { version = "1.0.228", features = ["serde_derive"] }
serde_json = "1.0.149"
cargo_metadata = "0.23.1"
mist-parser = { workspace = true }
mist-codegen = { workspace = true }
[lib]
name = "mist_api"
path = ".mist/src/lib.rs"
+187
View File
@@ -0,0 +1,187 @@
use std::{
collections::HashMap,
env, fs,
path::{MAIN_SEPARATOR, PathBuf},
process::{Command, Stdio},
};
use cargo_metadata::{CompilerMessage, Message};
use mist_parser::rev_mapper::{RustMap, find_mapping, get_mapping};
#[derive(Debug, Clone)]
pub struct MistDiagnosticMessage {
pub message: String,
pub file_path: PathBuf,
pub file_name: String,
pub line: usize,
pub column: usize,
}
#[derive(Debug, Clone)]
pub enum MistDiagnostic {
Error(MistDiagnosticMessage),
Warning(MistDiagnosticMessage),
Rust(CompilerMessage),
}
pub fn build(mut args: Vec<String>, root: PathBuf) -> bool {
args.remove(0);
args.insert(1, "--message-format=json".to_string());
let is_root = root == env::current_dir().expect("Failed getting env");
let mut command = Command::new("cargo")
.args(args)
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.stdin(Stdio::inherit())
.spawn()
.expect("Failed to run cargo");
let mut reader = std::io::BufReader::new(command.stdout.take().expect("Failed to get reader"));
let mut diagnostics = Vec::new();
let mut mapping = HashMap::new();
let mist_src = format!(".mist{MAIN_SEPARATOR}src");
for message in cargo_metadata::Message::parse_stream(&mut reader) {
match message {
Ok(Message::CompilerMessage(msg)) => {
for span in &msg.message.spans {
if span.is_primary {
let rust_path = root.join(&span.file_name);
let mist_file = span
.file_name
.replacen(&mist_src, "src", 1)
.trim_end_matches(".rs")
.to_string()
+ ".mist";
let mist_path = root.join(&mist_file);
if !fs::exists(&mist_path).expect("Unable to check if mist file exists") {
diagnostics.push(MistDiagnostic::Rust(msg));
break;
}
let map = mapping.entry(rust_path.clone()).or_insert_with(|| {
get_mapping(
&fs::read_to_string(rust_path)
.expect("Failed to read file for mapping"),
)
});
let mist_span =
find_mapping(&map, &RustMap(span.line_end, span.column_start))
.expect("Unable to find mapping");
let mist_msg = MistDiagnosticMessage {
message: format!(
"{}: {}",
msg.message.message,
span.label.clone().unwrap_or_default()
),
file_name: if is_root {
mist_file
} else {
mist_path.to_string_lossy().to_string()
},
file_path: mist_path,
line: mist_span.1.0,
column: mist_span.1.1,
};
match msg.message.level {
cargo_metadata::diagnostic::DiagnosticLevel::Error => {
diagnostics.push(MistDiagnostic::Error(mist_msg))
}
cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
diagnostics.push(MistDiagnostic::Warning(mist_msg))
}
_ => {}
}
}
}
}
Ok(Message::BuildFinished(finish)) => {
print_diagnostics(&diagnostics);
let mut raw_reader = reader.into_inner();
let mut stdout = std::io::stdout();
std::io::copy(&mut raw_reader, &mut stdout)
.map_err(|v| v.to_string())
.expect("(Mist) Failed to copy IO");
command.wait().unwrap();
return finish.success;
}
Ok(Message::TextLine(text)) => println!("{text}"),
_ => {}
}
}
false
}
pub fn print_diagnostics(diagnostics: &Vec<MistDiagnostic>) {
let mut files = HashMap::new();
for diag in diagnostics {
match diag {
MistDiagnostic::Error(msg) => {
let line = get_line(&mut files, &msg);
println!(
"\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}",
msg.file_name,
msg.line,
msg.column,
msg.message,
line.unwrap_or_default(),
)
}
MistDiagnostic::Warning(msg) => {
let line = get_line(&mut files, &msg);
println!(
"\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}",
msg.file_name,
msg.line,
msg.column,
msg.message,
line.unwrap_or_default(),
)
}
MistDiagnostic::Rust(rs) => println!("{rs}"),
}
}
}
pub fn get_line(
files: &mut HashMap<PathBuf, Vec<String>>,
msg: &MistDiagnosticMessage,
) -> Option<String> {
let src_path = msg.file_path.clone();
let lines = files.entry(src_path.clone()).or_insert_with(|| {
fs::read_to_string(src_path)
.expect("Unable to read mist file")
.lines()
.into_iter()
.map(String::from)
.collect()
});
lines.get(msg.line - 1).map(|v| v.trim().to_string())
}
+3
View File
@@ -0,0 +1,3 @@
pub mod builder;
pub mod transpiler;
pub mod modules;
+5
View File
@@ -0,0 +1,5 @@
pub mod builder;
pub mod transpiler;
pub mod modules;
void main() {}
+117
View File
@@ -0,0 +1,117 @@
use <std::path::Path>;
use <std::path::PathBuf>;
use <std::fs>;
use <std::process>;
#[derive(Debug)]
pub class Module {
pub String name;
pub PathBuf path;
pub Vec<Self> children;
pub constructor(String name, PathBuf mist_path, PathBuf rust_path) {
self.children = new Vec();
self.name = name;
self.path = mist_path;
if (self.path.is_dir()) {
PathBuf dir = self.path.clone();
// Behavior 2: It's a directory node. Check for gateway package.mist first.
PathBuf pkg_gate = self.path.join("package.mist");
if (pkg_gate.exists()) {
self.path = pkg_gate;
}
self.scan_directory(&dir, &rust_path);
}
}
void scan_directory(self mut*, Path* search_dir, Path* rust_path) {
var entries = match (fs::read_dir(search_dir)) {
Ok[entries] => entries;
Err[e] => {
eprintln!("error: failed to read directory {}\n {}", search_dir.display(), e);
process::exit(1);
}
};
for (entry : entries) {
var entry = match (entry) {
Ok[entry] => entry;
Err[e] => {
eprintln!("error: failed to read directory entry\n {}", e);
process::exit(1);
}
};
PathBuf child_path = entry.path();
if (child_path == self.path) {
continue;
}
String child_name = child_path.file_stem()
.and_then(|var s| s.to_str())
.expect("Failed to get module name")
.to_string();
PathBuf child_output = rust_path.join(&child_name).with_extension("rs");
if (!child_path.is_dir() && should_skip(&child_path, &child_output)) {
continue;
}
self.children.push(new Module(child_name, child_path, child_output));
}
}
pub PathBuf output_dir(self*, PathBuf* parent_dir) {
if (self.path.is_dir() || Some("package.mist") == self.path.file_name().unwrap().to_str()) {
parent_dir.join(&self.name)
} else {
parent_dir.clone()
}
}
pub PathBuf output_path(self*, PathBuf* parent_dir) {
if (self.path.is_dir() || Some("package.mist") == self.path.file_name().unwrap().to_str()) {
parent_dir.join(&self.name).join("mod.rs")
} else {
parent_dir.join(&self.name).with_extension("rs")
}
}
}
pub Module master_package(PathBuf mist_path, PathBuf rust_path) {
String name = mist_path.file_stem()
.and_then(|var s| s.to_str())
.expect("Failed to get module name")
.to_string();
var mut root_mod = new Module(name, mist_path.clone(), rust_path.clone());
if (!mist_path.is_dir()) {
PathBuf parent_dir = mist_path.parent()
.expect("Failed to get parent directory of root file")
.to_path_buf();
root_mod.scan_directory(&parent_dir, &rust_path);
}
root_mod
}
bool should_skip(Path* source, Path* output) {
var src_time = fs::metadata(source)
.ok()
.and_then(|var v| v.modified().ok());
var out_time = fs::metadata(output)
.ok()
.and_then(|var v| v.modified().ok());
out_time
.map(|var out_time| out_time >= src_time.unwrap())
.unwrap_or_default()
}
+122
View File
@@ -0,0 +1,122 @@
use <std::fs>;
use <std::path::Path>;
use <std::path::PathBuf>;
use <std::process>;
use <std::time>;
use <std::env>;
use <mist_parser::error>;
use <crate::modules>;
pub PathBuf build(bool force) {
var start = time::Instant::now();
var root = env::current_dir().expect("Unable to find project root");
PathBuf src = root.join("src");
PathBuf out = root.join(".mist/src");
var master = modules::master_package(src.join("main.mist"), out.join("main.rs"));
master.transpile(&out);
var elapsed = start.elapsed();
println!(
"\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m",
elapsed
);
root
}
impl modules::Module {
String transpile(self*, PathBuf* parent_dir) {
PathBuf dir = self.output_dir(&parent_dir);
PathBuf output_file = self.output_path(&parent_dir);
var _ = fs::create_dir_all(&dir);
String mut output = String::new();
for (child : &self.children) {
output.push_str(&child.transpile(&dir));
}
if (self.path.is_dir()) {
var res = fs::write(&output_file, output);
if (res.is_err()) {
eprintln!(
"error: failed to write output {}\n {}",
output_file.display(),
res.unwrap_err(),
);
process::exit(1);
}
} else {
transpile_file(&self.path, &output_file, &output);
}
format!("pub mod {};\n", self.name)
}
}
void transpile_file(PathBuf* path, PathBuf* output_file, str* mod_decl) {
String source = match (fs::read_to_string(path)) {
Ok[s] => s;
Err[e] => {
eprintln!("error: failed to read file {}\n {}", path.display(), e);
process::exit(1);
}
};
var mut gc = mist_codegen::RustCodegen::new();
String output = gc.generate(match (mist_parser::parse(&source)) {
Ok[ast] => ast;
Err[e] => {
match (e) {
error::ParseError::Ast[e] => {
var start_pos = e.span.start_pos().line_col();
var span = e.span.as_str();
eprintln!(
"\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}",
path.as_os_str().display(),
start_pos.0,
start_pos.1,
e.error_message,
span,
if span.ends_with("\n") { "" } else { "\n" },
"^".repeat(span.trim().len()),
);
process::exit(1);
}
error::ParseError::PreAst[e] => {
eprintln!("error: parse failed in {}\n{}", path.display(), e);
process::exit(1);
}
}
}
});
var res = fs::write(&output_file, format!("{mod_decl}{output}"));
if (res.is_err()) {
eprintln!(
"error: failed to write output {}\n {}",
output_file.display(),
res.unwrap_err(),
);
process::exit(1);
}
}
@@ -1,12 +1,12 @@
[package] [package]
name = "mist-parser" name = "mist-parser"
version = "0.1.1" version = "0.1.7-alpha.0"
edition = "2024" edition = "2024"
description = "The Mist programming language parser" description = "The Mist programming language parser"
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/mist-go/mist" repository = "https://github.com/mist-go/mist"
keywords = ["compiler", "language", "mist"] keywords = ["compiler", "language", "mist"]
categories = ["compilers"] categories = ["compilers", "parser-implementations", "parsing"]
[dependencies] [dependencies]
pest = "2.8.6" pest = "2.8.6"
+93
View File
@@ -0,0 +1,93 @@
use serde::Serialize;
use super::*;
#[derive(Debug, Clone, Serialize)]
pub enum Expression {
Literal(Literal),
Path(ExprPath),
Statement(Box<Statement>),
Fix {
initial: Box<Expression>,
prefixes: Vec<Prefix>,
postfixes: Vec<Postfix>,
},
Binary {
lhs: Box<Expression>,
op: String,
rhs: Box<Expression>,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum Literal {
String(String),
Int(i64),
Float(f64),
Bool(bool),
Tuple(Vec<Expression>),
Array(Vec<Expression>),
ArrayRepeat(Box<Expression>, Box<Expression>),
}
#[derive(Debug, Clone, Serialize)]
pub enum Pattern {
NamedTuple(Path, Vec<Box<Pattern>>),
Struct(Path, Vec<Box<Pattern>>),
Tuple(Vec<Box<Pattern>>),
Literal(Literal),
Path(bool, Path),
}
#[derive(Debug, Clone, Serialize)]
pub enum Postfix {
FieldAccess(Identifier, Option<Generics>),
Call(Vec<Expression>),
MacroCall(String),
StructCall(Vec<(Identifier, Expression)>),
Assign(String, Box<Expression>),
Index(Expression),
As(TypeExpr),
Increment,
Decrement,
Try,
}
#[derive(Debug, Clone, Serialize)]
pub enum Prefix {
Ref,
RefMut,
Deref,
New(Option<Generics>),
Not,
Neg,
Closure(Option<TypeExpr>, Vec<VarDecl>),
}
#[derive(Debug, Clone, Serialize)]
pub struct ExprPathSegment {
pub ident: Identifier,
pub generics: Option<Generics>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ExprPath(pub Vec<ExprPathSegment>);
#[derive(Debug, Clone, Serialize)]
pub struct Generics(pub Vec<Generic>);
#[derive(Debug, Clone, Serialize)]
pub enum Generic {
Lifetime(Identifier),
Type(TypeExpr),
}
impl Expression {
pub fn is_block(&self) -> bool {
if let Expression::Statement(stmt) = self {
stmt.is_block()
} else {
false
}
}
}
+68
View File
@@ -0,0 +1,68 @@
use serde::Serialize;
pub mod expr;
pub mod statement;
pub mod top_level;
pub use expr::*;
pub use statement::*;
pub use top_level::*;
#[derive(Debug, Clone, Serialize)]
pub struct Path(pub Vec<Identifier>);
#[derive(Debug, Clone, Serialize)]
pub struct Identifier(pub String);
#[derive(Debug, Clone, Serialize, Default)]
pub struct ParamList(pub Vec<VarDecl>);
#[derive(Debug, Clone, Serialize)]
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>);
#[derive(Debug, Clone, Serialize)]
pub enum TypePostfix {
Ref,
RefMut,
RefLifetime(Identifier),
RefMutLifetime(Identifier),
Dyn,
}
#[derive(Debug, Clone, Serialize)]
pub enum TypeExprKind {
Path(Path),
PathParams(Path, Vec<TypeExpr>),
Tuple(Vec<TypeExpr>),
Lifetime(Identifier),
}
#[derive(Debug, Clone, Serialize)]
pub struct Spanned<T> {
pub line: usize,
pub column: usize,
pub item: T,
}
impl TypeExpr {
pub fn no_px(kind: TypeExprKind) -> Self {
Self(kind, Vec::new())
}
}
impl From<GenericDecl> for Generic {
fn from(value: GenericDecl) -> Self {
match value {
GenericDecl::Lifetime(life) => Generic::Lifetime(life),
GenericDecl::Type(ty, _) => {
Generic::Type(TypeExpr(TypeExprKind::Path(Path(vec![ty])), Vec::new()))
}
}
}
}
impl<T> Spanned<T> {
pub fn get_comment(&self) -> String {
format!("/* {}:{} */", self.line, self.column)
}
}
+89
View File
@@ -0,0 +1,89 @@
use serde::Serialize;
use super::*;
#[derive(Debug, Clone, Serialize, Default)]
pub struct Block(
pub Vec<Spanned<Expression>>,
pub Option<Spanned<Expression>>,
);
#[derive(Debug, Clone, Serialize)]
pub enum StatementBody {
Statement(Expression),
Expression(Expression),
}
#[derive(Debug, Clone, Serialize)]
pub enum Statement {
Block(Block),
If {
initial: StatementBranch,
else_if: Vec<StatementBranch>,
else_branch: Option<StatementBody>,
},
Loop(StatementBody),
While(StatementBranch),
CStyleFor {
init: Expression,
condition: Expression,
update: Expression,
body: StatementBody,
},
For {
pattern: Pattern,
iterator: Expression,
body: StatementBody,
},
Match(Expression, Vec<Spanned<MatchItem>>),
VarDecl(VarDeclStmt),
Return(Option<Expression>),
Break,
Continue,
}
#[derive(Debug, Clone, Serialize)]
pub struct MatchItem(pub Vec<Pattern>, pub Expression);
#[derive(Debug, Clone, Serialize)]
pub struct VarDecl {
pub name: Pattern,
pub type_: Option<TypeExpr>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VarDeclStmt {
pub decl: VarDecl,
pub init: Option<Expression>,
}
#[derive(Debug, Clone, Serialize)]
pub struct StatementBranch {
pub condition: Expression,
pub body: Box<StatementBody>,
}
impl Statement {
pub fn is_block(&self) -> bool {
match self {
Self::Block(_)
| Self::Match(_, _)
| Self::While(_)
| Self::For { .. }
| Self::Loop(..)
| Self::CStyleFor { .. }
| Self::If { .. } => true,
_ => false,
}
}
}
impl StatementBody {
pub fn is_soft_return(&self) -> bool {
match self {
Self::Expression(_) => true,
_ => false,
}
}
}
+123
View File
@@ -0,0 +1,123 @@
use serde::Serialize;
use super::*;
#[derive(Debug, Clone, Serialize)]
pub enum Visibility {
Public,
PublicTarget(Path),
Private,
}
#[derive(Debug, Clone, Serialize)]
pub enum Attribute {
/// #[test]
Path(Path),
/// #[name = "value"]
NameValue { path: Path, value: Literal },
/// #[derive(Clone, Copy)]
List { path: Path, items: Vec<Attribute> },
}
#[derive(Debug, Clone, Serialize)]
pub struct TopLevel(pub Spanned<TopLevelKind>, pub Vec<Attribute>);
#[derive(Debug, Clone, Serialize)]
pub enum TopLevelKind {
ModAttribute,
Import(Visibility, Path),
Mod(Visibility, Identifier),
ImplDecl(ImplDecl),
TraitDecl {
visibility: Visibility,
name: Identifier,
generics: GenericsDecl,
requirements: Vec<TypeExpr>,
items: Vec<Spanned<FunctionDecl>>,
},
EnumDecl {
visibility: Visibility,
name: Identifier,
generics: GenericsDecl,
fields: Vec<Spanned<EnumItem>>,
},
StructDecl {
visibility: Visibility,
name: Identifier,
generics: GenericsDecl,
fields: Vec<Spanned<FieldDecl>>,
},
FunctionDecl(FunctionDecl),
ClassDecl {
visibility: Visibility,
name: Identifier,
generics: GenericsDecl,
inherits: Option<TypeExpr>,
fields: Vec<Spanned<FieldDeclStmt>>,
constructor: Spanned<ClassConstructor>,
items: Vec<ClassItem>,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum ClassItem {
Method(Spanned<FunctionDecl>),
ImplDecl(Spanned<ImplDecl>),
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct GenericsDecl(pub Vec<GenericDecl>);
#[derive(Debug, Clone, Serialize)]
pub enum GenericDecl {
Lifetime(Identifier),
Type(Identifier, Vec<TypeExpr>),
}
#[derive(Debug, Clone, Serialize)]
pub enum EnumItem {
Named(Identifier),
Tuple(Identifier, Vec<TypeExpr>),
Struct(Identifier, Vec<FieldDecl>),
}
#[derive(Debug, Clone, Serialize)]
pub struct ClassConstructor {
pub visibility: Visibility,
pub generics: GenericsDecl,
pub params: ParamList,
pub body: Block,
}
#[derive(Debug, Clone, Serialize)]
pub struct FunctionDecl {
pub visibility: Visibility,
pub name: Identifier,
pub generics: GenericsDecl,
pub params: ParamList,
pub return_type: TypeExpr,
pub body: Option<Block>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ImplDecl {
pub generics: GenericsDecl,
pub target: TypeExpr,
pub trait_: Option<TypeExpr>,
pub methods: Vec<Spanned<FunctionDecl>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct FieldDecl {
pub visibility: Visibility,
pub type_: TypeExpr,
pub name: Identifier,
}
#[derive(Debug, Clone, Serialize)]
pub struct FieldDeclStmt {
pub decl: FieldDecl,
pub init: Option<Expression>,
}
@@ -48,11 +48,19 @@ impl<'a, F> AstError<'a, F> {
} }
} }
#[track_caller]
pub fn bug_unimplemented<T>(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> { pub fn bug_unimplemented<T>(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> {
let loc = std::panic::Location::caller();
Err(Self { Err(Self {
span: pair.as_span(), span: pair.as_span(),
error_code: ErrorCode::AstGenBug, error_code: ErrorCode::AstGenBug,
error_message: format!("Possible bug, unimplemented: {:#?}", pair.as_rule()), error_message: format!(
"Possible bug, unimplemented: {:#?}, at {}:{}",
pair.as_rule(),
loc.file(),
loc.line(),
),
recovered: None, recovered: None,
}) })
} }
@@ -9,7 +9,32 @@ COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
// PRIMITIVES // PRIMITIVES
// ------------------------------------------------------ // ------------------------------------------------------
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } keyword = {
"if"
| "else"
| "for"
| "while"
| "match"
| "return"
| "break"
| "continue"
| "struct"
| "enum"
| "class"
| "trait"
| "impl"
| "pub"
| "mut"
| "var"
| "true"
| "false"
| "dyn"
| "loop"
}
identifier = @{
!(keyword ~ !(ASCII_ALPHANUMERIC | "_")) ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")*
}
integer = @{ ASCII_DIGIT+ } integer = @{ ASCII_DIGIT+ }
@@ -52,18 +77,13 @@ visibility = { "pub" ~ ("(" ~ static_path ~ ")")? }
mutable = { "mut" } mutable = { "mut" }
var = { "var" } var = { "var" }
// ======================================================
// ERROR RECOVERY
// ======================================================
unexpected_statement = {
(!(semicolon | "}" | statement) ~ ANY)+
}
// ====================================================== // ======================================================
// GENERICS // GENERICS
// ====================================================== // ======================================================
generic = { lifetime | (identifier ~ (":" ~ type_expr_param ~ ("+" ~ type_expr_param)*)?) } generic_decl = { lifetime | (identifier ~ (":" ~ type_expr_param ~ ("+" ~ type_expr_param)*)?) }
generics_decl = { "<" ~ (generic_decl ~ ("," ~ generic_decl)*)? ~ ">" }
generic = { lifetime | type_expr_param }
generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" } generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" }
// ====================================================== // ======================================================
@@ -71,7 +91,7 @@ generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" }
// ====================================================== // ======================================================
tuple_type = { tuple_type = {
"(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")" "[" ~ (type_expr ~ ("," ~ type_expr)*)? ~ "]"
} }
path_type = { path_type = {
@@ -82,8 +102,12 @@ ref_type = {
mutable? ~ lifetime? ~ "*" mutable? ~ lifetime? ~ "*"
} }
dyn_type = {
"dyn"
}
type_expr = { type_expr = {
(path_type | tuple_type) ~ ref_type* (path_type | tuple_type) ~ (ref_type | dyn_type)*
} }
lifetime = { lifetime = {
@@ -110,16 +134,24 @@ literal = {
// PATTERNS // PATTERNS
// ====================================================== // ======================================================
multi_pat_template = _{
(pattern ~ ("," ~ pattern)*)?
}
tuple_pattern = { tuple_pattern = {
"(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" "[" ~ multi_pat_template ~ "]"
} }
named_tuple_pattern = { named_tuple_pattern = {
static_path ~ "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" static_path ~ "[" ~ multi_pat_template ~ "]"
} }
struct_pattern = { struct_pattern = {
static_path ~ "{" ~ (identifier ~ ("," ~ identifier)*)? ~ "}" static_path ~ "{" ~ multi_pat_template ~ "}"
}
path_pattern = {
mutable? ~ static_path
} }
pattern = _{ pattern = _{
@@ -127,7 +159,7 @@ pattern = _{
| tuple_pattern | tuple_pattern
| struct_pattern | struct_pattern
| literal | literal
| static_path | path_pattern
} }
// ====================================================== // ======================================================
@@ -147,7 +179,7 @@ meta = {
} }
meta_list = { meta_list = {
meta ~ ("," ~ meta)* ~ ","? (meta ~ ("," ~ meta)* ~ ","?)?
} }
attributes = { attributes = {
@@ -158,7 +190,7 @@ attributes = {
// DECLARATION HELPERS // DECLARATION HELPERS
// ====================================================== // ======================================================
var_decl = { var_decl = {
(var | type_expr) ~ mutable? ~ pattern (var | type_expr) ~ pattern
} }
field = { field = {
@@ -166,11 +198,11 @@ field = {
} }
field_list = { field_list = {
field ~ ("," ~ field)* ~ ","? (field ~ ("," ~ field)* ~ ","?)?
} }
param_list = { param_list = {
var_decl ~ ("," ~ var_decl)* ~ ","? (var_decl ~ ("," ~ var_decl)* ~ ","?)?
} }
// ====================================================== // ======================================================
@@ -190,7 +222,7 @@ mod_package = {
// ====================================================== // ======================================================
struct_decl = { struct_decl = {
visibility? ~ "struct" ~ identifier ~ generics? ~ "{" ~ field_list? ~ "}" visibility? ~ "struct" ~ identifier ~ generics_decl? ~ "{" ~ field_list? ~ "}"
} }
// ====================================================== // ======================================================
@@ -220,7 +252,7 @@ enum_fields = _{
} }
enum_decl = { enum_decl = {
visibility? ~ "enum" ~ identifier ~ generics? ~ "{" ~ enum_fields ~ "}" visibility? ~ "enum" ~ identifier ~ generics_decl? ~ "{" ~ enum_fields ~ "}"
} }
// ====================================================== // ======================================================
@@ -228,7 +260,7 @@ enum_decl = {
// ====================================================== // ======================================================
class_constructor = { class_constructor = {
visibility? ~ "constructor" ~ generics? ~ "(" ~ param_list? ~ ")" ~ block visibility? ~ "constructor" ~ generics_decl? ~ "(" ~ param_list ~ ")" ~ block
} }
class_fields = { class_fields = {
@@ -244,7 +276,7 @@ self_param = {
} }
method = { method = {
visibility? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ block visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list)? ~ ")" ~ block
} }
class_item = _{ class_item = _{
@@ -253,18 +285,18 @@ class_item = _{
} }
class_decl = { class_decl = {
visibility? ~ "class" ~ identifier ~ generics? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" visibility? ~ "class" ~ identifier ~ generics_decl? ~ (":" ~ type_expr)? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}"
} }
// ====================================================== // ======================================================
// IMPL // IMPL
// ====================================================== // ======================================================
impl_for_decl = { impl_for_decl = {
"impl" ~ generics? ~ type_expr ~ "for" ~ type_expr ~ "{" ~ method* ~ "}" "impl" ~ generics_decl? ~ type_expr ~ "for" ~ type_expr ~ "{" ~ method* ~ "}"
} }
impl_decl = { impl_decl = {
"impl" ~ generics? ~ type_expr ~ "{" ~ method* ~ "}" "impl" ~ generics_decl? ~ type_expr ~ "{" ~ method* ~ "}"
} }
// ====================================================== // ======================================================
@@ -273,7 +305,7 @@ impl_decl = {
trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* } trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* }
method_no_body = { method_no_body = {
visibility? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ semicolon visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list)? ~ ")" ~ semicolon
} }
trait_item = _{ trait_item = _{
@@ -282,7 +314,7 @@ trait_item = _{
} }
trait_decl = { trait_decl = {
visibility? ~ "trait" ~ identifier ~ generics? ~ trait_requirements? ~ "{" ~ trait_item* ~ "}" visibility? ~ "trait" ~ identifier ~ generics_decl? ~ trait_requirements? ~ "{" ~ trait_item* ~ "}"
} }
// ====================================================== // ======================================================
@@ -290,7 +322,7 @@ trait_decl = {
// ====================================================== // ======================================================
function_decl = { function_decl = {
visibility? ~ type_expr ~ identifier ~ "(" ~ param_list? ~ ")" ~ block visibility? ~ type_expr ~ identifier ~ "(" ~ param_list ~ ")" ~ block
} }
// ====================================================== // ======================================================
@@ -307,57 +339,64 @@ top_level = {
// ====================================================== // ======================================================
block = { block = {
"{" ~ (statement | unexpected_statement)* ~ "}" "{" ~ statement_list ~ expr? ~ "}"
}
statement_list = {
statement*
} }
statement = _{ statement = _{
expr_stmt control_flow
| match_stmt | (expr ~ semicolon)
| assign_statement
| if_stmt
| while_stmt
| c_for_stmt
| for_stmt
| return_stmt
| break_stmt
| continue_stmt
| block
| var_decl_statement
} }
statement_wrapper = { statement }
statement_body = { statement_wrapper | expr }
// ------------------------------------------------------ // ------------------------------------------------------
// BASIC STATEMENTS // BASIC STATEMENTS
// ------------------------------------------------------ // ------------------------------------------------------
expr_stmt = { basic_stmt = {
expr ~ semicolon return_stmt
| break_stmt
| continue_stmt
| var_decl_statement
} }
return_stmt = { return_stmt = {
"return" ~ expr? ~ semicolon "return" ~ expr?
} }
break_stmt = { break_stmt = {
"break" ~ semicolon "break"
} }
continue_stmt = { continue_stmt = {
"continue" ~ semicolon "continue"
} }
var_decl_statement = { var_decl_statement = {
var_decl ~ ("=" ~ expr)? ~ semicolon var_decl ~ ("=" ~ expr)?
}
assign_statement = {
expr ~ "=" ~ expr ~ semicolon
} }
// ------------------------------------------------------ // ------------------------------------------------------
// CONDITIONALS // CONDITIONALS
// ------------------------------------------------------ // ------------------------------------------------------
statement_branch = { "(" ~ expr ~ ")" ~ statement } control_flow = {
if_stmt
| while_stmt
| c_for_stmt
| for_stmt
| match_stmt
| loop_stmt
| block
}
statement_branch = { "(" ~ expr ~ ")" ~ statement_body }
else_if = { else_if = {
"else" ~ "if" ~ statement_branch "else" ~ "if" ~ statement_branch
@@ -368,7 +407,7 @@ else_if_list = {
} }
if_stmt = { if_stmt = {
"if" ~ statement_branch ~ else_if_list ~ ("else" ~ statement)? "if" ~ statement_branch ~ else_if_list ~ ("else" ~ statement_body)?
} }
// ------------------------------------------------------ // ------------------------------------------------------
@@ -380,19 +419,25 @@ while_stmt = {
} }
c_for_stmt = { c_for_stmt = {
"for" ~ "(" ~ statement ~ expr ~ semicolon ~ statement ~ ")" ~ statement "for" ~ "(" ~ statement ~ statement ~ expr ~ ")" ~ statement_body
} }
for_stmt = { for_stmt = {
"for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement "for" ~ "(" ~ pattern ~ ":" ~ expr ~ ")" ~ statement_body
}
loop_stmt = {
"loop" ~ statement_body
} }
// ------------------------------------------------------ // ------------------------------------------------------
// MATCH // MATCH
// ------------------------------------------------------ // ------------------------------------------------------
pattern_list = { pattern ~ ("|" ~ pattern)* }
match_item = { match_item = {
pattern ~ "=>" ~ block pattern_list ~ "=>" ~ statement
} }
match_stmt = { match_stmt = {
@@ -404,19 +449,32 @@ match_stmt = {
// ====================================================== // ======================================================
// ------------------------------------------------------ // ------------------------------------------------------
// TUPLES // CLOSURES
// ------------------------------------------------------
closure = { type_expr? ~ "|" ~ param_list ~ "|" }
// ------------------------------------------------------
// TUPLES & ARRAYS
// ------------------------------------------------------ // ------------------------------------------------------
tuple = { tuple = {
"(" ~ (expr ~ ("," ~ expr)*)? ~ ")" "(" ~ (expr ~ ("," ~ expr)*)? ~ ")"
} }
array = {
"[" ~ expr ~ ";" ~ expr ~ "]" // Repeat notation: [0; 10]
| "[" ~ (expr ~ ("," ~ expr)* ~ ","?)? ~ "]" // Standard elements initialization
}
// ------------------------------------------------------ // ------------------------------------------------------
// MACROS // MACROS
// ------------------------------------------------------ // ------------------------------------------------------
macro_inner_v = { macro_inner_v = @{
"(" ~ macro_inner_v* ~ ")" string_lit
| ("(" ~ macro_inner_v* ~ ")")
| (!("(" | ")") ~ ANY) | (!("(" | ")") ~ ANY)
} }
@@ -424,10 +482,21 @@ macro_inner_v = {
// PRIMARY EXPRESSIONS // PRIMARY EXPRESSIONS
// ------------------------------------------------------ // ------------------------------------------------------
expr_path_segment = {
identifier ~ ("::" ~ generics)?
}
expr_path = {
expr_path_segment ~ ("::" ~ expr_path_segment)*
}
primary = { primary = {
literal control_flow
| static_path | basic_stmt
| literal
| expr_path
| tuple | tuple
| array
} }
// ------------------------------------------------------ // ------------------------------------------------------
@@ -435,7 +504,7 @@ primary = {
// ------------------------------------------------------ // ------------------------------------------------------
field_px = { field_px = {
"." ~ identifier "." ~ identifier ~ ("::" ~ generics)?
} }
call_px = { call_px = {
@@ -458,8 +527,20 @@ index_px = {
"[" ~ expr ~ "]" "[" ~ expr ~ "]"
} }
binary_px = { as_px = {
bin_op ~ expr "as" ~ type_expr
}
try_px = {
"?"
}
increment = {
"++"
}
decrement = {
"--"
} }
postfix = { postfix = {
@@ -468,43 +549,31 @@ postfix = {
| macro_call_px | macro_call_px
| struct_px | struct_px
| index_px | index_px
| binary_px | as_px
| try_px
| increment
| decrement
} }
// ------------------------------------------------------ // ------------------------------------------------------
// PREFIX EXPRESSIONS // PREFIX EXPRESSIONS
// ------------------------------------------------------ // ------------------------------------------------------
deref_px = { deref_px = { "*" }
"*" mut_ref_px = { "&" ~ mutable }
} ref_px = { "&" }
new_px = { "new" ~ generics? }
mut_ref_px = { not_px = { "!" }
"&" ~ mutable neg_px = { "-" }
}
ref_px = {
"&"
}
new_px = {
"new"
}
not_px = {
"!"
}
prefix = { prefix = {
deref_px closure
| deref_px
| mut_ref_px | mut_ref_px
| ref_px | ref_px
| new_px | new_px
| not_px | not_px
} | neg_px
prefix_list = {
prefix*
} }
// ------------------------------------------------------ // ------------------------------------------------------
@@ -512,7 +581,20 @@ prefix_list = {
// ------------------------------------------------------ // ------------------------------------------------------
bin_op = { bin_op = {
"<=" "+="
| "-="
| "/="
| "%="
| "&="
| "|="
| "^="
| "<<="
| ">>="
| "<<"
| ">>"
| "..="
| ".."
| "<="
| ">=" | ">="
| "==" | "=="
| "!=" | "!="
@@ -525,12 +607,16 @@ bin_op = {
| "%" | "%"
| "<" | "<"
| ">" | ">"
| "&"
| "|"
| "^"
| "="
} }
// ------------------------------------------------------ // ------------------------------------------------------
// EXPRESSIONS // EXPRESSIONS
// ------------------------------------------------------ // ------------------------------------------------------
expr = { expr = { term ~ (bin_op ~ term)* }
prefix_list ~ primary ~ postfix*
} term = { prefix* ~ primary ~ postfix* }
+14 -3
View File
@@ -4,6 +4,7 @@ use pest_derive::Parser;
pub mod ast; pub mod ast;
pub mod error; pub mod error;
pub mod parser; pub mod parser;
pub mod rev_mapper;
use ast::*; use ast::*;
@@ -34,14 +35,14 @@ pub fn parse<'a>(source: &'a str) -> Result<Vec<TopLevel>, ParseError<'a, Vec<To
#[macro_export] #[macro_export]
macro_rules! ast_ensure { macro_rules! ast_ensure {
($pair:expr, $rule:expr => $body:block) => { ($pair:expr, $rule:expr $(, $rules:expr)* => $body:block) => {
if $pair.as_rule() == $rule if $pair.as_rule() == $rule $(|| $pair.as_rule() == $rules)*
$body $body
else { else {
Err(AstError { Err(AstError {
span: $pair.as_span(), span: $pair.as_span(),
error_code: crate::error::ErrorCode::AstGenBug, error_code: crate::error::ErrorCode::AstGenBug,
error_message: format!("Possible bug: expected {:?}, got {}", $rule, $pair), error_message: format!("Possible bug: expected {:?}, got {:?}", $rule, $pair.as_rule()),
recovered: None, recovered: None,
}) })
} }
@@ -50,6 +51,16 @@ macro_rules! ast_ensure {
#[macro_export] #[macro_export]
macro_rules! ast_expr { macro_rules! ast_expr {
(use $r:expr, $($v:expr),* $(,)?) => {{
let mut analyzer = $crate::error::AstErrorAnalyzer(None);
$(
analyzer.get($v).get()?;
)*
analyzer.build($r)
}};
($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{ ($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{
let mut analyzer = $crate::error::AstErrorAnalyzer(None); let mut analyzer = $crate::error::AstErrorAnalyzer(None);
@@ -2,8 +2,7 @@ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_expr, ast_expr,
error::{AstError, AstResult, IntoErr}, error::{AstError, IntoErr},
parser::listen_rule,
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
@@ -63,13 +62,10 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
}) })
.transpose(); .transpose();
let mutable: AstResult<'_, bool> = Ok(listen_rule(&mut inner, Rule::mutable));
let name = Pattern::try_from(inner.next().unwrap()); let name = Pattern::try_from(inner.next().unwrap());
ast_expr!(VarDecl { ast_expr!(VarDecl {
type_: type_, type_: type_,
mutable: mutable,
name: name, name: name,
}) })
} }
+203
View File
@@ -0,0 +1,203 @@
use crate::{
Rule,
ast::*,
ast_ensure, ast_expr,
error::{AstError, AstResult, GetLength, IntoErr, collect_recovered, collect_recovered_map},
parser::consume_rule,
};
use pest::pratt_parser::PrattParser;
use std::sync::OnceLock;
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::expr => {
static PRATT_PARSER: OnceLock<PrattParser<Rule>> = OnceLock::new();
let pratt = PRATT_PARSER.get_or_init(|| {
use pest::pratt_parser::{Assoc::*, Op};
PrattParser::new().op(Op::infix(Rule::bin_op, Left))
});
pratt
.map_primary(|primary_pair| Expression::try_from(primary_pair))
.map_infix(|expr, op, rhs| {
ast_expr!(Expression::Binary {
lhs: expr.map(Box::new).get_map(Box::new),
op: Ok(op.as_str().to_string()) as AstResult<'_, String>,
rhs: rhs.map(Box::new).get_map(Box::new),
})
})
.parse(inner)
}
Rule::term => {
let mut prefix_pairs = Vec::new();
let mut primary_pair = None;
let mut postfix_pairs = Vec::new();
for p in inner {
match p.as_rule() {
Rule::prefix => prefix_pairs.push(p),
Rule::primary => primary_pair = Some(p),
Rule::postfix => postfix_pairs.push(p),
_ => {}
}
}
let prefixes = collect_recovered::<Prefix, Prefix>(prefix_pairs.into_iter());
let exp = Expression::try_from(
primary_pair.expect("Term must contain a primary expression"),
);
let postfixes = collect_recovered::<Postfix, Postfix>(postfix_pairs.into_iter());
if postfixes.len() > 0 || prefixes.len() > 0 {
ast_expr!(Expression::Fix {
initial: exp.map(Box::new),
prefixes: prefixes,
postfixes: postfixes,
})
} else {
ast_expr!(use exp?, prefixes, postfixes)
}
}
Rule::tuple => {
ast_expr!(Expression::Literal(
collect_recovered(pair.into_inner())
.map(Literal::Tuple)
.get_map(Literal::Tuple)
))
}
Rule::primary => pair.into_inner().next().unwrap().try_into(),
Rule::static_path => ast_expr!(Expression::Path(pair.try_into())),
Rule::literal => ast_expr!(Expression::Literal(pair.try_into())),
Rule::expr_path => ast_expr!(Expression::Path(pair.try_into())),
Rule::statement_wrapper => {
let i = inner.next().unwrap();
match i.as_rule() {
Rule::expr => i.try_into(),
_ => ast_expr!(Expression::Statement(
i.try_into().get_map(Box::new).map(Box::new)
)),
}
}
Rule::statement | Rule::basic_stmt | Rule::control_flow => ast_expr!(
Expression::Statement(pair.try_into().get_map(Box::new).map(Box::new))
),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(match pair.as_rule() {
Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?,
Rule::deref_px => Self::Deref,
Rule::mut_ref_px => Self::RefMut,
Rule::ref_px => Self::Ref,
Rule::new_px => Self::New(
pair.into_inner()
.next()
.map(|v| v.try_into().get())
.transpose()?,
),
Rule::not_px => Self::Not,
Rule::neg_px => Self::Neg,
Rule::closure => {
let mut inner = pair.into_inner();
return ast_expr!(Self::Closure(
consume_rule(&mut inner, Rule::type_expr)
.map(TypeExpr::try_from)
.transpose(),
collect_recovered(inner.next().unwrap().into_inner())
));
}
_ => return AstError::bug_unimplemented(pair),
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::postfix => Postfix::try_from(inner.next().unwrap()),
Rule::field_px => {
ast_expr!(Postfix::FieldAccess(
inner.next().unwrap().try_into(),
inner.next().map(Generics::try_from).transpose()
))
}
Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))),
Rule::struct_px => ast_expr!(Postfix::StructCall(collect_recovered_map(inner, |p| {
let mut pi = p.into_inner();
Ok((
Identifier::try_from(pi.next().unwrap())?,
Expression::try_from(pi.next().unwrap()).get()?,
))
}))),
Rule::index_px => {
ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
}
Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())),
Rule::as_px => {
ast_expr!(Postfix::As(inner.next().unwrap().try_into()))
}
Rule::try_px => Ok(Postfix::Try),
Rule::increment => Ok(Postfix::Increment),
Rule::decrement => Ok(Postfix::Decrement),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPath {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
ast_ensure!(pair, Rule::expr_path => {
ast_expr!(ExprPath(collect_recovered(pair.into_inner())))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPathSegment {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::expr_path_segment => {
ast_expr!(ExprPathSegment {
ident: Identifier::try_from(inner.next().unwrap()),
generics: inner.next().map(Generics::try_from).transpose(),
})
})
}
}
@@ -7,8 +7,8 @@ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_ensure, ast_expr, ast_ensure, ast_expr,
error::{AstError, IntoErr, collect_recovered}, error::{AstError, AstResult, IntoErr, collect_recovered, collect_recovered_map},
parser::consume_rule, parser::{consume_rule, listen_rule},
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
@@ -60,23 +60,26 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
match rule { match rule {
Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered(pair.into_inner()))), Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered_map(inner, |v| {
Self::try_from(v).map(Box::new)
}))),
Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple( Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple(
Path::try_from(inner.next().unwrap()), Path::try_from(inner.next().unwrap()),
collect_recovered(inner), collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new)),
)), )),
Rule::struct_pattern => ast_expr!(Pattern::Struct( Rule::struct_pattern => ast_expr!(Pattern::Struct(
Path::try_from(inner.next().unwrap()), Path::try_from(inner.next().unwrap()),
collect_recovered(inner), collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new)),
)), )),
Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())), Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())),
Rule::identifier => ast_expr!(Pattern::Id(pair.try_into())), Rule::path_pattern => ast_expr!(Pattern::Path(
Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
Rule::static_path => ast_expr!(Pattern::Path(pair.try_into())), inner.next().unwrap().try_into()
)),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
} }
@@ -2,16 +2,35 @@ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_ensure, ast_expr, ast_ensure, ast_expr,
error::{AstError, AstResult, ErrorCode, IntoErr, collect_recovered}, error::{AstError, IntoErr, collect_recovered},
parser::listen_rule,
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
type Error = AstError<'a, Self>; type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::block => { ast_ensure!(pair, Rule::block => {
ast_expr!(Block(collect_recovered(pair.into_inner()))) ast_expr!(Block(collect_recovered(inner.next().unwrap().into_inner()), inner.next().map(Spanned::try_from).transpose()))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBody {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::statement_body => {
let i = inner.next().unwrap();
match i.as_rule() {
Rule::expr => ast_expr!(StatementBody::Expression(i.try_into())),
Rule::statement_wrapper => ast_expr!(StatementBody::Statement(i.try_into())),
_ => AstError::bug_unimplemented(i),
}
}) })
} }
} }
@@ -39,10 +58,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
match rule { match rule {
Rule::statement => Statement::try_from(inner.next().unwrap()), Rule::statement | Rule::basic_stmt | Rule::control_flow => {
Statement::try_from(inner.next().unwrap())
Rule::expr_stmt => {
ast_expr!(Statement::Expression(inner.next().unwrap().try_into()))
} }
Rule::block => ast_expr!(Statement::Block(pair.try_into())), Rule::block => ast_expr!(Statement::Block(pair.try_into())),
@@ -63,61 +80,46 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
ast_expr!(Statement::If { ast_expr!(Statement::If {
initial: inner.next().unwrap().try_into(), initial: inner.next().unwrap().try_into(),
else_if: collect_recovered(inner.next().unwrap().into_inner()), else_if: collect_recovered(inner.next().unwrap().into_inner()),
else_branch: inner else_branch: inner.next().map(StatementBody::try_from).transpose(),
.next()
.map(Statement::try_from)
.transpose()
.map(|v| v.map(Box::new))
.get_map(|v| { Some(Box::new(v)) }),
}) })
} }
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())), Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())),
Rule::loop_stmt => ast_expr!(Statement::Loop(inner.next().unwrap().try_into())),
Rule::c_for_stmt => ast_expr!(Statement::CStyleFor { Rule::c_for_stmt => ast_expr!(Statement::CStyleFor {
init: inner.next().unwrap().try_into().map(Box::new), init: inner.next().unwrap().try_into(),
condition: inner.next().unwrap().try_into(), condition: inner.next().unwrap().try_into(),
update: inner.next().unwrap().try_into().map(Box::new), update: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new), body: inner.next().unwrap().try_into(),
}), }),
Rule::for_stmt => ast_expr!(Statement::For { Rule::for_stmt => ast_expr!(Statement::For {
mutable: Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
pattern: inner.next().unwrap().try_into(), pattern: inner.next().unwrap().try_into(),
iterator: inner.next().unwrap().try_into(), iterator: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new), body: inner.next().unwrap().try_into(),
}), }),
Rule::assign_statement => ast_expr!(VarAssignStmt {
target: inner.next().unwrap().try_into(),
value: inner.next().unwrap().try_into(),
})
.map(Statement::VarAssign)
.get_map(Statement::VarAssign),
Rule::match_stmt => ast_expr!(Statement::Match( Rule::match_stmt => ast_expr!(Statement::Match(
inner.next().unwrap().try_into(), inner.next().unwrap().try_into(),
inner collect_recovered(inner),
.map(|match_itms| {
let mut match_inner = match_itms.into_inner();
Ok((
Pattern::try_from(match_inner.next().unwrap()).get()?,
Block::try_from(match_inner.next().unwrap()).get()?,
))
})
.collect::<AstResult<'a, Vec<_>>>(),
)), )),
Rule::unexpected_statement => {
return Err(AstError {
span: pair.as_span(),
error_code: ErrorCode::InvalidStatement,
error_message: "Invalid Statement".to_string(),
recovered: None,
});
}
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
} }
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for MatchItem {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut match_inner = pair.into_inner();
Ok(MatchItem(
collect_recovered(match_inner.next().unwrap().into_inner()).get()?,
Expression::try_from(match_inner.next().unwrap()).get()?,
))
}
}
@@ -1,7 +1,7 @@
use crate::{ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_expr, ast_ensure, ast_expr,
error::{AstError, GetLength, IntoErr, collect_recovered}, error::{AstError, GetLength, IntoErr, collect_recovered},
parser::{consume_rule, listen_rule}, parser::{consume_rule, listen_rule},
}; };
@@ -36,6 +36,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
}) })
} }
Rule::dyn_type => Ok(TypePostfix::Dyn),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
} }
} }
@@ -87,17 +89,48 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for GenericsDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::generics_decl => {
ast_expr!(GenericsDecl(collect_recovered(inner)))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for GenericDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::generic_decl => {
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
ast_expr!(GenericDecl::Lifetime(
pair.into_inner().next().unwrap().try_into(),
))
} else {
ast_expr!(GenericDecl::Type(
inner.next().unwrap().try_into(),
collect_recovered(inner),
))
}
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
type Error = AstError<'a, Self>; type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let inner = pair.clone().into_inner(); let inner = pair.clone().into_inner();
match rule { ast_ensure!(pair, Rule::generics => {
Rule::generics => ast_expr!(Generics(collect_recovered(inner))), ast_expr!(Generics(collect_recovered(inner)))
_ => AstError::bug_unimplemented(pair), })
}
} }
} }
@@ -107,15 +140,16 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generic {
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { ast_ensure!(pair, Rule::generic => {
ast_expr!(Generic::Lifetime( if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
pair.into_inner().next().unwrap().try_into(), ast_expr!(Generic::Lifetime(
)) pair.into_inner().next().unwrap().try_into(),
} else { ))
ast_expr!(Generic::Type( } else {
inner.next().unwrap().try_into(), ast_expr!(Generic::Type(
collect_recovered(inner), inner.next().unwrap().try_into()
)) ))
} }
})
} }
} }
@@ -28,11 +28,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
} }
Some(next) => match next.as_rule() { Some(next) => match next.as_rule() {
Rule::primary => { Rule::literal => {
// #[path = literal] // #[path = literal]
Ok(Attribute::NameValue { Ok(Attribute::NameValue {
path, path,
value: inner.next().unwrap().try_into().get()?, value: next.try_into().get()?,
}) })
} }
@@ -14,8 +14,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
Ok(Self { Ok(Self {
visibility: Visibility::try_from(&mut inner).get()?, visibility: Visibility::try_from(&mut inner).get()?,
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.get()? .get()?
.unwrap_or_default(), .unwrap_or_default(),
@@ -0,0 +1,80 @@
use crate::{
Rule,
ast::*,
ast_ensure, ast_expr,
error::{AstError, AstResult, IntoErr, collect_recovered},
parser::{consume_rule, listen_rule},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
ast_ensure!(pair, Rule::function_decl, Rule::method, Rule::method_no_body => {
let mut inner = pair.into_inner();
let visibility = Visibility::try_from(&mut inner);
let return_type = TypeExpr::try_from(inner.next().unwrap());
let name = Identifier::try_from(inner.next().unwrap());
let generics = consume_rule(&mut inner, Rule::generics_decl)
.map(GenericsDecl::try_from)
.transpose()
.map(|v| v.unwrap_or_default());
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
let mut param_inner = param.into_inner();
let mutable = listen_rule(&mut param_inner, Rule::mutable);
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
let name = Pattern::Path(mutable && !is_ref, Path(vec![Identifier(String::from("self"))]));
VarDecl {
name: name.clone(),
type_: Some(TypeExpr(
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
if is_ref {
vec![if mutable {
TypePostfix::RefMut
} else {
TypePostfix::Ref
}]
} else {
Vec::new()
},
)),
}
});
let params = consume_rule(&mut inner, Rule::param_list)
.map({
let self_param = self_param.clone();
|params_pair| -> AstResult<'a, ParamList> {
let mut params = ParamList::try_from(params_pair)?;
if let Some(x) = self_param {
params.0.insert(0, x);
}
Ok(params)
}
})
.unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect())));
let body = inner.next().map(Block::try_from).transpose();
ast_expr!(Self {
visibility: visibility,
return_type: return_type,
name: name,
generics: generics,
params: params,
body: body,
})
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(ParamList(collect_recovered(pair.into_inner()).get()?))
}
}
@@ -14,8 +14,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
match rule { match rule {
Rule::impl_for_decl => Ok(ImplDecl { Rule::impl_for_decl => Ok(ImplDecl {
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.get()? .get()?
.unwrap_or_default(), .unwrap_or_default(),
@@ -25,8 +25,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
}), }),
Rule::impl_decl => Ok(ImplDecl { Rule::impl_decl => Ok(ImplDecl {
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.get()? .get()?
.unwrap_or_default(), .unwrap_or_default(),
@@ -21,10 +21,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
let attributes = collect_recovered(inner.next().unwrap().into_inner()); let attributes = collect_recovered(inner.next().unwrap().into_inner());
ast_expr!(TopLevel( ast_expr!(TopLevel(
inner inner.next().map(Spanned::try_from).unwrap(),
.next()
.map(TopLevelKind::try_from)
.unwrap_or(Ok(TopLevelKind::ModAttribute)),
attributes, attributes,
)) ))
} }
@@ -50,14 +47,14 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
name: inner.next().unwrap().try_into(), name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
fields: inner fields: inner
.next() .next()
.map(|pair| collect_recovered::<FieldDecl, FieldDecl>(pair.into_inner())) .map(|pair| collect_recovered(pair.into_inner()))
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
}), }),
@@ -67,11 +64,15 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
name: inner.next().unwrap().try_into(), name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
inherits: consume_rule(&mut inner, Rule::type_expr)
.map(TypeExpr::try_from)
.transpose(),
fields: collect_recovered(inner.next().unwrap().into_inner()), fields: collect_recovered(inner.next().unwrap().into_inner()),
constructor: inner.next().unwrap().try_into(), constructor: inner.next().unwrap().try_into(),
@@ -84,8 +85,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
name: inner.next().unwrap().try_into(), name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
@@ -106,17 +107,17 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
name: inner.next().unwrap().try_into(), name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics) generics: consume_rule(&mut inner, Rule::generics_decl)
.map(Generics::try_from) .map(GenericsDecl::try_from)
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
requirements: consume_rule(&mut inner, Rule::trait_requirements) requirements: consume_rule(&mut inner, Rule::trait_requirements)
.map(|pair| collect_recovered::<TypeExpr, TypeExpr>(pair.into_inner())) .map(|pair| collect_recovered(pair.into_inner()))
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
items: collect_recovered(inner), items: collect_recovered(&mut inner),
}), }),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
+54
View File
@@ -0,0 +1,54 @@
pub mod common;
pub mod items;
use crate::{Rule, ast::Spanned, error::AstError};
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed {
pairs.next();
}
consumed
}
pub fn consume_rule<'a>(
pairs: &mut pest::iterators::Pairs<'a, Rule>,
rule: Rule,
) -> Option<pest::iterators::Pair<'a, Rule>> {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed { pairs.next() } else { None }
}
impl<'a, T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, T>>>
TryFrom<pest::iterators::Pair<'a, Rule>> for Spanned<T>
{
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let span = pair.as_span().start_pos().line_col();
Ok(Self {
line: span.0,
column: span.1,
item: pair.try_into().map_err(|err: AstError<'_, T>| AstError {
span: err.span,
error_code: err.error_code,
error_message: err.error_message,
recovered: err.recovered.map(|v| Spanned {
line: span.0,
column: span.1,
item: v,
}),
})?,
})
}
}
@@ -0,0 +1,9 @@
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
integer = @{ ASCII_DIGIT+ }
map = { "/*" ~ integer ~ ":" ~ integer ~ "*/" }
non_map = { (!map ~ ANY)+ }
mapping = { SOI ~ (map | non_map)* ~ EOI }
+51
View File
@@ -0,0 +1,51 @@
use std::collections::HashSet;
use pest::Parser;
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "./src/rev_mapper/grammar.pest"]
pub struct MistMapperParser;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MistMap(pub usize, pub usize);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct RustMap(pub usize, pub usize);
pub fn get_mapping(input: &str) -> HashSet<(RustMap, MistMap)> {
let mut mapping = HashSet::new();
let pairs = MistMapperParser::parse(Rule::mapping, input)
.unwrap()
.next()
.unwrap()
.into_inner();
for pair in pairs {
if pair.as_rule() == Rule::map {
let rs = pair.as_span().start_pos().line_col();
let mut inner = pair.into_inner();
let (line, col) = (
inner.next().unwrap().as_str().parse().unwrap(),
inner.next().unwrap().as_str().parse().unwrap(),
);
mapping.insert((RustMap(rs.0, rs.1), MistMap(line, col)));
}
}
mapping
}
pub fn find_mapping(
mapping: &HashSet<(RustMap, MistMap)>,
target: &RustMap,
) -> Option<(RustMap, MistMap)> {
mapping
.iter()
.copied()
.filter(|(rust, _)| rust <= target)
.max_by_key(|(rust, _)| *rust)
}
+1 -1
View File
@@ -5,6 +5,6 @@ edition = "2024"
[[bin]] [[bin]]
name = "main" name = "main"
path = "build/main.rs" path = ".mist/src/main.rs"
[dependencies] [dependencies]
+1
View File
@@ -0,0 +1 @@
package = "main.mist"
-4
View File
@@ -1,4 +0,0 @@
{
"src": "src",
"output": "build"
}
+33 -5
View File
@@ -15,7 +15,6 @@ pub class Application {
pub constructor(str* name) { pub constructor(str* name) {
self.name = name.to_string(); self.name = name.to_string();
self.tasks = new Vec(); self.tasks = new Vec();
self.plugins = new Vec(); self.plugins = new Vec();
@@ -46,7 +45,7 @@ pub class Application {
void tick(self mut*) { void tick(self mut*) {
self.logger.info("tick"); self.logger.info("tick");
self.ticks = self.ticks + 1; self.ticks++;
var task = task::create_task("background-job"); var task = task::create_task("background-job");
@@ -79,17 +78,46 @@ pub class Application {
self.logger.info("shutdown event"); self.logger.info("shutdown event");
} }
event::Event::PluginLoaded(name) => { event::Event::PluginLoaded[name] => {
println!("plugin loaded: {}", name); println!("plugin loaded: {}", name);
} }
event::Event::TaskExecuted(name) => { event::Event::TaskExecuted[name] => {
println!("task executed: {}", name); println!("task executed: {}", name);
} }
event::Event::Error(message) => { event::Event::Error[message] => {
self.logger.error(&message); self.logger.error(&message);
} }
} }
} }
} }
i32 test_stmt() {
if (0 == 0) {
0
}
else {
1
}
}
void loops_test() {
for (x : 0..10) {
println!("{x}");
}
for (var mut i = 0; i < 10; i++) {
println!("{i}");
}
var i = 0;
while (i == 1) {
println!("hi");
}
loop {
println!("loop!");
}
}
+3 -3
View File
@@ -1,7 +1,7 @@
pub enum Event { pub enum Event {
Startup, Startup,
Shutdown, Shutdown,
TaskExecuted(String), TaskExecuted[String],
PluginLoaded(String), PluginLoaded[String],
Error(String), Error[String],
} }
+12 -12
View File
@@ -2,7 +2,7 @@ use <std::fmt::Formatter>;
use <std::fmt>; use <std::fmt>;
pub trait TestLogging<T: fmt::Display>: fmt::Display { pub trait TestLogging<T: fmt::Display>: fmt::Display {
String get(); String get(self*);
} }
pub enum LogLevel { pub enum LogLevel {
@@ -14,21 +14,21 @@ pub enum LogLevel {
impl fmt::Display for LogLevel { impl fmt::Display for LogLevel {
fmt::Result fmt(self*, Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
match (self) { match (self) {
LogLevel::Info => { LogLevel::Info => write!(f, "[INFO]");
return write!(f, "[INFO]");
}
LogLevel::Warning => { LogLevel::Warning => write!(f, "[WARN]");
return write!(f, "[WARN]");
}
LogLevel::Error => { LogLevel::Error => write!(f, "[ERROR]");
return write!(f, "[ERROR]");
}
} }
} }
} }
impl TestLogging<LogLevel> for LogLevel {
String get(self*) {
return format!("{self}");
}
}
pub class Logger { pub class Logger {
String prefix; String prefix;
@@ -55,7 +55,7 @@ pub class Logger {
} }
LogLevel::Warning => { LogLevel::Warning => {
println!("{level} {} {}", self.prefix, message); println!("{} {} {}", level.get(), self.prefix, message);
} }
LogLevel::Error => { LogLevel::Error => {
@@ -66,7 +66,7 @@ pub class Logger {
impl fmt::Display { impl fmt::Display {
fmt::Result fmt(self*, Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
return write!(f, "logger ({})", self.prefix); write!(f, "logger ({})", self.prefix)
} }
} }
} }
+16 -9
View File
@@ -1,15 +1,22 @@
pub mod app;
pub mod task;
pub mod plugin;
pub mod logger;
pub mod event;
void main() { void main() {
var mut app_instance = new app::Application("mist-app"); var mut app_instance = new app::Application("mist-app");
// greeting::register(&mut app_instance);
// statistics::register(&mut app_instance);
app_instance.boot(); app_instance.boot();
app_instance.run(); app_instance.run();
} }
void do_stuff() {
vec!(1, 2, 3).into_iter().map(Option<i32> |var v| {Some(v)}).collect::<Vec<_>>();
if (43==69) testing1();
}
i32 testing1() {
i32 v = if (0 == 0) {
0
} else {
1
};
v
}
+2 -2
View File
@@ -12,9 +12,9 @@ pub struct Task {
} }
pub Task create_task(str* name) { pub Task create_task(str* name) {
return Task { Task {
name: name.to_string(), name: name.to_string(),
state: TaskState::Pending, state: TaskState::Pending,
executions: 0, executions: 0,
}; }
} }
-280
View File
@@ -1,280 +0,0 @@
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct Identifier(pub String);
#[derive(Debug, Clone, Serialize, Default)]
pub struct ParamList(pub Vec<VarDecl>);
#[derive(Debug, Clone, Serialize, Default)]
pub struct Block(pub Vec<Statement>);
#[derive(Debug, Clone, Serialize)]
pub enum TypePostfix {
Ref,
RefMut,
RefLifetime(Identifier),
RefMutLifetime(Identifier),
}
#[derive(Debug, Clone, Serialize)]
pub enum Visibility {
Public,
PublicTarget(Path),
Private,
}
#[derive(Debug, Clone, Serialize)]
pub enum Attribute {
/// #[test]
Path(Path),
/// #[name = "value"]
NameValue { path: Path, value: Literal },
/// #[derive(Clone, Copy)]
List { path: Path, items: Vec<Attribute> },
}
#[derive(Debug, Clone, Serialize)]
pub enum TypeExprKind {
Path(Path),
PathParams(Path, Vec<TypeExpr>),
Tuple(Vec<TypeExpr>),
Lifetime(Identifier),
}
#[derive(Debug, Clone, Serialize)]
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>);
#[derive(Debug, Clone, Serialize)]
pub struct Path(pub Vec<Identifier>);
#[derive(Debug, Clone, Serialize)]
pub enum BinaryOp {
Plus,
Minus,
Multiply,
Divide,
Modulo,
Equal,
NotEqual,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
And,
Or,
}
#[derive(Debug, Clone, Serialize)]
pub struct TopLevel(pub TopLevelKind, pub Vec<Attribute>);
#[derive(Debug, Clone, Serialize)]
pub enum TopLevelKind {
ModAttribute,
Import(Visibility, Path),
Mod(Visibility, Identifier),
ImplDecl(ImplDecl),
TraitDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
requirements: Vec<TypeExpr>,
items: Vec<FunctionDecl>,
},
EnumDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
fields: Vec<EnumItem>,
},
StructDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
fields: Vec<FieldDecl>,
},
FunctionDecl(FunctionDecl),
ClassDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
fields: Vec<FieldDeclStmt>,
constructor: ClassConstructor,
items: Vec<ClassItem>,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum ClassItem {
Method(FunctionDecl),
ImplDecl(ImplDecl),
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct Generics(pub Vec<Generic>);
#[derive(Debug, Clone, Serialize)]
pub enum Generic {
Lifetime(Identifier),
Type(Identifier, Vec<TypeExpr>),
}
#[derive(Debug, Clone, Serialize)]
pub enum Pattern {
NamedTuple(Path, Vec<Identifier>),
Struct(Path, Vec<Identifier>),
Tuple(Vec<Identifier>),
Literal(Literal),
Path(Path),
Id(Identifier),
}
#[derive(Debug, Clone, Serialize)]
pub enum EnumItem {
Named(Identifier),
Tuple(Identifier, Vec<TypeExpr>),
Struct(Identifier, Vec<FieldDecl>),
}
#[derive(Debug, Clone, Serialize)]
pub struct ClassConstructor {
pub visibility: Visibility,
pub generics: Generics,
pub params: ParamList,
pub body: Block,
}
#[derive(Debug, Clone, Serialize)]
pub struct FunctionDecl {
pub visibility: Visibility,
pub name: Identifier,
pub generics: Generics,
pub params: ParamList,
pub return_type: TypeExpr,
pub body: Option<Block>,
}
#[derive(Debug, Clone, Serialize)]
pub enum Postfix {
FieldAccess(Identifier),
Call(Vec<Expression>),
MacroCall(String),
StructCall(Vec<(Identifier, Expression)>),
Index(Expression),
Binary(BinaryOp, Expression),
}
#[derive(Debug, Clone, Serialize)]
pub enum Prefix {
Ref,
RefMut,
Deref,
New,
Not,
}
#[derive(Debug, Clone, Serialize)]
pub enum Statement {
Expression(Expression),
Block(Block),
VarDecl(VarDeclStmt),
VarAssign(VarAssignStmt),
If {
initial: StatementBranch,
else_if: Vec<StatementBranch>,
else_branch: Option<Box<Statement>>,
},
While(StatementBranch),
CStyleFor {
init: Box<Statement>,
condition: Expression,
update: Box<Statement>,
body: Box<Statement>,
},
For {
mutable: bool,
pattern: Pattern,
iterator: Expression,
body: Box<Statement>,
},
Match(Expression, Vec<(Pattern, Block)>),
Return(Option<Expression>),
Break,
Continue,
}
#[derive(Debug, Clone, Serialize)]
pub struct ImplDecl {
pub generics: Generics,
pub target: TypeExpr,
pub trait_: Option<TypeExpr>,
pub methods: Vec<FunctionDecl>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VarDecl {
pub mutable: bool,
pub name: Pattern,
pub type_: Option<TypeExpr>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VarDeclStmt {
pub decl: VarDecl,
pub init: Option<Expression>,
}
#[derive(Debug, Clone, Serialize)]
pub struct FieldDecl {
pub visibility: Visibility,
pub type_: TypeExpr,
pub name: Identifier,
}
#[derive(Debug, Clone, Serialize)]
pub struct FieldDeclStmt {
pub decl: FieldDecl,
pub init: Option<Expression>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VarAssignStmt {
pub target: Expression,
pub value: Expression,
}
#[derive(Debug, Clone, Serialize)]
pub struct StatementBranch {
pub condition: Expression,
pub body: Box<Statement>,
}
#[derive(Debug, Clone, Serialize)]
pub enum Expression {
Literal(Literal),
Path(Path),
Fix {
initial: Box<Expression>,
prefixes: Vec<Prefix>,
postfixes: Vec<Postfix>,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum Literal {
String(String),
Int(i64),
Float(f64),
Bool(bool),
Tuple(Vec<Expression>),
}
impl TypeExpr {
pub fn no_px(kind: TypeExprKind) -> Self {
Self(kind, Vec::new())
}
}
-117
View File
@@ -1,117 +0,0 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, GetLength, IntoErr, collect_recovered, collect_recovered_map},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::expr => {
let prefixes = inner
.next()
.map(|p| collect_recovered::<Prefix, Prefix>(p.into_inner()))
.unwrap_or_else(|| Ok(Vec::new()));
let exp = Expression::try_from(inner.next().unwrap());
if inner.len() > 0 || prefixes.len() > 0 {
ast_expr!(Expression::Fix {
initial: exp.map(Box::new),
prefixes: prefixes,
postfixes: collect_recovered(inner),
})
} else {
exp
}
}
Rule::primary => inner.next().unwrap().try_into(),
Rule::static_path => ast_expr!(Expression::Path(pair.try_into())),
Rule::literal => ast_expr!(Expression::Literal(pair.try_into())),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(match pair.as_rule() {
Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?,
Rule::deref_px => Self::Deref,
Rule::mut_ref_px => Self::RefMut,
Rule::ref_px => Self::Ref,
Rule::new_px => Self::New,
Rule::not_px => Self::Not,
_ => return AstError::bug_unimplemented(pair),
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::postfix => Postfix::try_from(inner.next().unwrap()),
Rule::field_px => {
ast_expr!(Postfix::FieldAccess(inner.next().unwrap().try_into()))
}
Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))),
Rule::struct_px => ast_expr!(Postfix::StructCall(collect_recovered_map(inner, |p| {
let mut pi = p.into_inner();
Ok((
Identifier::try_from(pi.next().unwrap())?,
Expression::try_from(pi.next().unwrap()).get()?,
))
}))),
Rule::index_px => {
ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
}
Rule::binary_px => {
let op_pair = inner.next().unwrap();
let op = match op_pair.as_str() {
"+" => BinaryOp::Plus,
"-" => BinaryOp::Minus,
"*" => BinaryOp::Multiply,
"/" => BinaryOp::Divide,
"%" => BinaryOp::Modulo,
"==" => BinaryOp::Equal,
"!=" => BinaryOp::NotEqual,
"<" => BinaryOp::LessThan,
">" => BinaryOp::GreaterThan,
"<=" => BinaryOp::LessThanOrEqual,
">=" => BinaryOp::GreaterThanOrEqual,
"&&" => BinaryOp::And,
"||" => BinaryOp::Or,
_ => return AstError::bug_unimplemented(op_pair),
};
Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?))
}
Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())),
_ => AstError::bug_unimplemented(pair),
}
}
}
-81
View File
@@ -1,81 +0,0 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, AstResult, IntoErr, collect_recovered},
parser::{consume_rule, listen_rule},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
let visibility = Visibility::try_from(&mut inner);
let return_type = TypeExpr::try_from(inner.next().unwrap());
let name = Identifier::try_from(inner.next().unwrap());
let generics = consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.map(|v| v.unwrap_or_default());
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
let mut param_inner = param.into_inner();
let name = Pattern::Id(Identifier(String::from("self")));
let mutable = listen_rule(&mut param_inner, Rule::mutable);
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
VarDecl {
mutable: mutable && !is_ref,
name: name.clone(),
type_: Some(TypeExpr(
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
if is_ref {
vec![if mutable {
TypePostfix::RefMut
} else {
TypePostfix::Ref
}]
} else {
Vec::new()
},
)),
}
});
let params = consume_rule(&mut inner, Rule::param_list)
.map({
let self_param = self_param.clone();
|params_pair| -> AstResult<'a, ParamList> {
let mut params = ParamList::try_from(params_pair)?;
if let Some(x) = self_param {
params.0.insert(0, x);
}
Ok(params)
}
})
.unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect())));
let body = inner.next().map(Block::try_from).transpose();
ast_expr!(Self {
visibility: visibility,
return_type: return_type,
name: name,
generics: generics,
params: params,
body: body,
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(ParamList(collect_recovered(pair.into_inner()).get()?))
}
}
-29
View File
@@ -1,29 +0,0 @@
pub mod common;
pub mod items;
use crate::Rule;
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed {
pairs.next();
}
consumed
}
pub fn consume_rule<'a>(
pairs: &mut pest::iterators::Pairs<'a, Rule>,
rule: Rule,
) -> Option<pest::iterators::Pair<'a, Rule>> {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed { pairs.next() } else { None }
}
+5
View File
@@ -0,0 +1,5 @@
use <mist_analyzer>;
void main() {
mist_analyzer::start();
}
-883
View File
@@ -1,883 +0,0 @@
use mist_parser::ast::{
Attribute, BinaryOp, Block, ClassItem, EnumItem, Expression, FieldDecl, FunctionDecl, Generic,
Generics, Identifier, ImplDecl, Literal, Path, Pattern, Postfix, Prefix, Statement,
StatementBranch, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt,
VarDecl, VarDeclStmt, Visibility,
};
// ---------------------------------------------------------------------------
// Traits
// ---------------------------------------------------------------------------
/// Implemented by nodes that *write* into the codegen output buffer.
/// Requires `&mut RustCodegen` because it calls `add` / `addln` / indentation helpers.
pub trait ToRust {
fn to_rust(&self, cg: &mut RustCodegen);
}
/// Implemented by nodes that *produce* a `String` without mutating the codegen.
/// Only needs `&RustCodegen` (e.g. for indent level or helper access).
pub trait GetRust {
fn get_rust(&self) -> String;
}
// ---------------------------------------------------------------------------
// Codegen struct
// ---------------------------------------------------------------------------
pub struct RustCodegen {
output: String,
indent: usize,
}
impl RustCodegen {
pub fn new() -> Self {
Self {
output: String::new(),
indent: 0,
}
}
fn indent_str(&self) -> String {
" ".repeat(self.indent)
}
fn add(&mut self, s: &str) {
self.output.push_str(s);
}
fn addln(&mut self, s: &str) {
self.add(s);
self.add("\n");
}
fn add_indentedln(&mut self, s: &str) {
let line = format!("{}{}\n", self.indent_str(), s);
self.add(&line);
}
pub fn generate(&mut self, toplevels: &[TopLevel]) -> String {
for tl in toplevels {
tl.to_rust(self);
}
self.output.clone()
}
pub fn ensure_brackets(&mut self, stmt: &Statement) {
match stmt {
Statement::Block(_) => stmt.to_rust(self),
_ => {
self.add_indentedln("{");
self.indent += 1;
stmt.to_rust(self);
self.indent -= 1;
self.add_indentedln("}");
}
}
}
}
impl Default for RustCodegen {
fn default() -> Self {
Self::new()
}
}
// ---------------------------------------------------------------------------
// GetRust — pure string production (expressions, types)
// ---------------------------------------------------------------------------
impl GetRust for TypeExpr {
fn get_rust(&self) -> String {
get_type_postfixes(&self.1) + &self.0.get_rust()
}
}
impl GetRust for TypeExprKind {
fn get_rust(&self) -> String {
match self {
TypeExprKind::Path(path) => get_static_type_path(path),
TypeExprKind::Lifetime(name) => format!("'{}", name.get_rust()),
TypeExprKind::PathParams(path, params) => {
format!(
"{}<{}>",
get_static_type_path(path),
params
.iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", ")
)
}
TypeExprKind::Tuple(types) => format!(
"({})",
types
.iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
impl GetRust for Literal {
fn get_rust(&self) -> String {
match self {
Self::Int(n) => n.to_string(),
Self::Float(n) => format!("{n:?}"),
Self::Bool(b) => b.to_string(),
Self::String(s) => format!("\"{s}\""),
Self::Tuple(t) => {
format!(
"({})",
t.iter()
.map(Expression::get_rust)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
}
impl GetRust for Expression {
fn get_rust(&self) -> String {
match self {
Expression::Path(path) => path.get_rust(),
Expression::Literal(literal) => literal.get_rust(),
Expression::Fix {
initial,
prefixes,
postfixes,
} => {
prefixes.get_rust()
+ &initial.get_rust()
+ &Some(prefixes).get_rust()
+ &postfixes.get_rust()
}
}
}
}
impl GetRust for Prefix {
fn get_rust(&self) -> String {
match self {
Self::Deref => "*",
Self::Ref => "&",
Self::RefMut => "&mut ",
Self::Not => "!",
Self::New => "",
}
.to_string()
}
}
impl GetRust for [Prefix] {
fn get_rust(&self) -> String {
self.iter().map(Prefix::get_rust).collect()
}
}
impl GetRust for Option<&Vec<Prefix>> {
fn get_rust(&self) -> String {
self.map(|prefixes| {
prefixes
.iter()
.last()
.map(|p| match p {
Prefix::New => "::new",
_ => "",
})
.unwrap_or_default()
.to_string()
})
.unwrap_or_default()
}
}
impl GetRust for Postfix {
fn get_rust(&self) -> String {
match self {
Postfix::FieldAccess(field) => format!(".{}", field.get_rust()),
Postfix::Call(args) => {
let args = args
.iter()
.map(|a| a.get_rust())
.collect::<Vec<_>>()
.join(", ");
format!("({})", args)
}
Postfix::MacroCall(inner) => {
format!("!({})", inner)
}
Postfix::StructCall(fields) => {
let fields = fields
.iter()
.map(|(k, v)| format!("{}: {}", k.get_rust(), v.get_rust()))
.collect::<Vec<_>>()
.join(", ");
format!("{{ {} }}", fields)
}
Postfix::Index(idx) => {
format!("[{}]", idx.get_rust())
}
Postfix::Binary(op, rhs) => {
let op_str = match op {
BinaryOp::Plus => "+",
BinaryOp::Minus => "-",
BinaryOp::Multiply => "*",
BinaryOp::Divide => "/",
BinaryOp::Modulo => "%",
BinaryOp::Equal => "==",
BinaryOp::NotEqual => "!=",
BinaryOp::LessThan => "<",
BinaryOp::GreaterThan => ">",
BinaryOp::LessThanOrEqual => "<=",
BinaryOp::GreaterThanOrEqual => ">=",
BinaryOp::And => "&&",
BinaryOp::Or => "||",
};
format!(" {} {}", op_str, rhs.get_rust())
}
}
}
}
impl GetRust for [Postfix] {
fn get_rust(&self) -> String {
self.iter().map(Postfix::get_rust).collect()
}
}
// ---------------------------------------------------------------------------
// ToRust — output-writing (top-level, statements, blocks)
// ---------------------------------------------------------------------------
impl ToRust for Block {
fn to_rust(&self, cg: &mut RustCodegen) {
for stmt in &self.0 {
stmt.to_rust(cg);
}
}
}
impl ToRust for TopLevel {
fn to_rust(&self, cg: &mut RustCodegen) {
match &self.0 {
TopLevelKind::ModAttribute => {
for attr in &self.1 {
cg.addln(&format!("#![{}]", attr.get_rust()));
}
}
_ => {
for attr in &self.1 {
cg.addln(&format!("#[{}]", attr.get_rust()));
}
}
}
self.0.to_rust(cg);
}
}
impl GetRust for Attribute {
fn get_rust(&self) -> String {
match self {
Self::Path(path) => path.get_rust(),
Self::NameValue { path, value } => {
format!("{} = {}", path.get_rust(), value.get_rust())
}
Self::List { path, items } => {
format!(
"{}({})",
path.get_rust(),
items
.iter()
.map(Attribute::get_rust)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
}
impl ToRust for TopLevelKind {
fn to_rust(&self, cg: &mut RustCodegen) {
match self {
Self::ModAttribute => {}
Self::Import(vis, path) => {
cg.addln(&format!("{} use {};", vis.get_rust(), path.get_rust()))
}
Self::Mod(vis, id) => cg.addln(&format!("{} mod {};", vis.get_rust(), id.get_rust())),
Self::FunctionDecl(decl) => decl.to_rust(cg),
Self::ImplDecl(impl_) => impl_.to_rust(cg),
Self::StructDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}struct {}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
for field in fields {
cg.add_indentedln(&field.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::EnumDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}enum {}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
for field in fields {
cg.add_indentedln(&(format!("{}", field.get_rust()) + ","));
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::TraitDecl {
visibility,
name,
generics,
requirements,
items,
} => {
cg.addln(&format!(
"{}trait {}{}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust(),
if requirements.len() != 0 {
String::from(": ")
+ &requirements
.iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join("+")
} else {
String::new()
},
));
cg.indent += 1;
for item in items {
item.to_rust(cg);
}
cg.indent -= 1;
cg.addln("}\n");
}
Self::ClassDecl {
visibility,
name,
generics,
fields,
constructor,
items,
} => {
// Struct decl
cg.addln(&format!(
"{}struct {}{} {{",
visibility.get_rust(),
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
for field in fields {
cg.add_indentedln(&field.decl.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
// Constructor
cg.addln(&format!(
"impl{} {}{} {{",
generics.get_rust(),
name.get_rust(),
format!(
"<{}>",
generics
.0
.iter()
.map(|v| (false, v).get_rust())
.collect::<Vec<_>>()
.join(", ")
)
));
cg.indent += 1;
let params_str = constructor
.params
.0
.iter()
.map(VarDecl::get_rust)
.collect::<Vec<_>>()
.join(", ");
cg.add_indentedln("#[allow(invalid_value)]");
cg.add_indentedln(&format!(
"{}fn new{}({}) -> Self {{",
constructor.visibility.get_rust(),
constructor.generics.get_rust(),
params_str
));
cg.indent += 1;
cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };");
for field in fields {
if let Some(init) = &field.init {
cg.add_indentedln(&format!(
"this.{} = {};",
field.decl.name.get_rust(),
init.get_rust()
));
}
}
cg.add_indentedln(&format!(
"this.construct_class({});",
constructor
.params
.0
.iter()
.map(|e| e.name.get_rust())
.collect::<Vec<_>>()
.join(", ")
));
cg.add_indentedln("this");
cg.indent -= 1;
cg.add_indentedln("}\n");
// Constructor function
cg.add_indentedln(&format!(
"{}fn construct_class{}(&mut self, {}) {{",
constructor.visibility.get_rust(),
constructor.generics.get_rust(),
params_str
));
cg.indent += 1;
constructor.body.to_rust(cg);
cg.indent -= 1;
cg.add_indentedln("}\n");
for item in items {
match item {
ClassItem::ImplDecl(_) => {}
ClassItem::Method(method) => method.to_rust(cg),
}
}
cg.indent -= 1;
cg.addln("}\n");
for item in items {
match item {
ClassItem::ImplDecl(impl_) => {
let mut impl_ = impl_.clone();
impl_.trait_ = Some(impl_.target);
impl_.target =
TypeExpr(TypeExprKind::Path(Path(vec![name.clone()])), Vec::new());
impl_.to_rust(cg);
}
ClassItem::Method(_) => {}
}
}
}
}
}
}
impl ToRust for Statement {
fn to_rust(&self, cg: &mut RustCodegen) {
match self {
Statement::Expression(expr) => {
cg.add_indentedln(&format!("{};", expr.get_rust()));
}
Statement::Block(block) => {
cg.add_indentedln("{");
cg.indent += 1;
block.to_rust(cg);
cg.indent -= 1;
cg.add_indentedln("}");
}
Statement::VarDecl(VarDeclStmt { decl, init }) => {
let init = init
.as_ref()
.map(|e| format!(" = {}", e.get_rust()))
.unwrap_or_default();
cg.add_indentedln(&format!("let {}{};", decl.get_rust(), init));
}
Statement::VarAssign(VarAssignStmt { target, value }) => {
cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),));
}
Statement::Match(expr, match_items) => {
cg.add_indentedln(&format!("match {} {{", expr.get_rust()));
cg.indent += 1;
for itm in match_items {
cg.add_indentedln(&format!("{} =>", itm.0.get_rust()));
cg.add_indentedln("{");
cg.indent += 1;
itm.1.to_rust(cg);
cg.indent -= 1;
cg.add_indentedln("}");
}
cg.indent -= 1;
cg.add_indentedln("}");
}
Statement::If {
initial,
else_if,
else_branch,
} => {
cg.add_indentedln(&format!("if {}", initial.condition.get_rust()));
cg.ensure_brackets(&initial.body);
for else_if_branch in else_if {
cg.add_indentedln(&format!("else if {}", else_if_branch.condition.get_rust()));
cg.ensure_brackets(&else_if_branch.body);
}
if let Some(else_br) = else_branch {
cg.add_indentedln("else");
cg.ensure_brackets(else_br);
}
}
Statement::While(StatementBranch { condition, body }) => {
cg.add_indentedln(&format!("while {}", condition.get_rust()));
cg.ensure_brackets(body);
}
Statement::CStyleFor {
init,
condition,
update,
body,
} => {
cg.add_indentedln("{");
cg.indent += 1;
init.to_rust(cg);
cg.add_indentedln(&format!("while {}", condition.get_rust()));
cg.add_indentedln("{");
cg.indent += 1;
cg.ensure_brackets(body);
update.to_rust(cg);
cg.indent -= 1;
cg.add_indentedln("}");
cg.indent -= 1;
cg.add_indentedln("}");
}
Statement::For {
mutable,
pattern,
iterator,
body,
} => {
cg.add_indentedln(&format!(
"for {}{} in {}",
get_mutable(*mutable),
pattern.get_rust(),
iterator.get_rust()
));
cg.ensure_brackets(body);
}
Statement::Return(expr) => {
let val = expr.as_ref().map(|e| e.get_rust()).unwrap_or_default();
cg.add_indentedln(&format!("return {};", val));
}
Statement::Break => cg.add_indentedln("break;"),
Statement::Continue => cg.add_indentedln("continue;"),
}
}
}
impl ToRust for FunctionDecl {
fn to_rust(&self, cg: &mut RustCodegen) {
let params_str = self
.params
.0
.iter()
.map(VarDecl::get_rust)
.collect::<Vec<_>>()
.join(", ");
cg.add_indentedln(&format!(
"{}fn {}{}({}) -> {}",
self.visibility.get_rust(),
self.name.get_rust(),
self.generics.get_rust(),
params_str,
self.return_type.get_rust()
));
if let Some(body) = &self.body {
cg.add_indentedln("{\n");
cg.indent += 1;
body.to_rust(cg);
cg.indent -= 1;
cg.add_indentedln("}\n");
} else {
cg.add(";");
}
}
}
impl ToRust for ImplDecl {
fn to_rust(&self, cg: &mut RustCodegen) {
if let Some(trait_) = &self.trait_ {
cg.add_indentedln(&format!(
"impl{} {} for {} {{",
self.generics.get_rust(),
trait_.get_rust(),
self.target.get_rust()
));
} else {
cg.add_indentedln(&format!(
"impl{} {} {{",
self.generics.get_rust(),
self.target.get_rust()
));
}
cg.indent += 1;
for method in &self.methods {
method.to_rust(cg);
}
cg.indent -= 1;
cg.add_indentedln("}");
}
}
impl GetRust for VarDecl {
fn get_rust(&self) -> String {
let ty = self
.type_
.as_ref()
.map(|t| format!(": {}", t.get_rust()))
.unwrap_or_default();
format!(
"{}{}{}",
get_mutable(self.mutable),
self.name.get_rust(),
ty
)
}
}
impl GetRust for Path {
fn get_rust(&self) -> String {
self.0
.iter()
.map(Identifier::get_rust)
.collect::<Vec<String>>()
.join("::")
}
}
impl GetRust for TypePostfix {
fn get_rust(&self) -> String {
match self {
TypePostfix::Ref => format!("&"),
TypePostfix::RefMut => format!("&mut "),
TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
}
}
}
impl GetRust for Visibility {
fn get_rust(&self) -> String {
match self {
Visibility::Public => "pub ".to_string(),
Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
Visibility::Private => "".to_string(),
}
}
}
impl GetRust for Identifier {
fn get_rust(&self) -> String {
self.0.clone()
}
}
impl GetRust for EnumItem {
fn get_rust(&self) -> String {
match self {
Self::Named(id) => id.get_rust(),
Self::Struct(id, s) => format!(
"{} {{{}}}",
id.get_rust(),
s.iter()
.map(|field| format!("{}: {}", field.name.get_rust(), field.type_.get_rust()))
.collect::<Vec<_>>()
.join(", ")
),
Self::Tuple(id, t) => format!(
"{} ({})",
id.get_rust(),
t.iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
impl GetRust for Pattern {
fn get_rust(&self) -> String {
match self {
Self::Id(id) => id.get_rust(),
Self::Path(path) => path.get_rust(),
Self::Literal(lit) => lit.get_rust(),
Self::Struct(path, ids) => format!(
"{} {{{}}}",
path.get_rust(),
ids.iter()
.map(Identifier::get_rust)
.collect::<Vec<_>>()
.join(", ")
),
Self::Tuple(ids) => format!(
"({})",
ids.iter()
.map(Identifier::get_rust)
.collect::<Vec<_>>()
.join(", ")
),
Self::NamedTuple(path, ids) => {
format!(
"{} ({})",
path.get_rust(),
ids.iter()
.map(Identifier::get_rust)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
}
impl GetRust for Generics {
fn get_rust(&self) -> String {
if self.0.len() == 0 {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(|v| (true, v).get_rust())
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetRust for (bool, &Generic) {
fn get_rust(&self) -> String {
match &self.1 {
Generic::Lifetime(name) => format!("'{}", name.get_rust()),
Generic::Type(name, requirements) => {
name.get_rust()
+ &(if !self.0 && requirements.len() == 0 {
String::new()
} else {
format!(
": {}",
requirements
.iter()
.map(TypeExpr::get_rust)
.collect::<Vec<_>>()
.join("+")
)
})
}
}
}
}
impl GetRust for FieldDecl {
fn get_rust(&self) -> String {
format!(
"{}{}: {},",
self.visibility.get_rust(),
self.name.get_rust(),
self.type_.get_rust()
)
}
}
pub fn get_static_type_path(path: &Path) -> String {
let rust_path = path.get_rust();
if rust_path == "void" {
format!("()")
} else {
rust_path
}
}
pub fn get_type_postfixes(postfixes: &[TypePostfix]) -> String {
postfixes.iter().map(TypePostfix::get_rust).collect()
}
pub fn get_mutable(mutable: bool) -> String {
if mutable { "mut " } else { "" }.to_string()
}
-168
View File
@@ -1,168 +0,0 @@
use std::{
fs,
path::{Path, PathBuf},
process,
time::Instant,
};
use mist_parser::error::ParseError;
use serde::Deserialize;
#[derive(Deserialize)]
struct Config {
src: String,
output: String,
}
pub fn build() {
let start = Instant::now();
// 1. find project root
let root = find_project_root().unwrap_or_else(|| {
panic!("error: could not find project root (mist.json)");
});
println!("mistc build ({})", root.display());
// 2. load config
let config = load_config(&root);
let src_dir = root.join(&config.src);
let out_dir = root.join(&config.output);
build_dir(&root, &src_dir, &src_dir, &out_dir);
let elapsed = start.elapsed();
println!("build finished in {:.2?}", elapsed);
}
fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
let entries = match fs::read_dir(current_dir) {
Ok(entries) => entries,
Err(e) => {
eprintln!(
"error: failed to read directory {}\n {}",
current_dir.display(),
e
);
process::exit(1);
}
};
for entry in entries {
let entry = match entry {
Ok(entry) => entry,
Err(e) => {
eprintln!("error: failed to read directory entry\n {}", e);
process::exit(1);
}
};
let path = entry.path();
// recurse into nested directories
if path.is_dir() {
build_dir(root, base_src, &path, out_dir);
continue;
}
// skip non-mist files
if path.extension().and_then(|e| e.to_str()) != Some("mist") {
continue;
}
let relative = path.strip_prefix(base_src).unwrap();
let output_path = out_dir.join(relative).with_extension("rs");
// create parent directories
if let Some(parent) = output_path.parent() {
if let Err(e) = fs::create_dir_all(parent) {
eprintln!(
"error: failed to create output directory {}\n {}",
parent.display(),
e
);
process::exit(1);
}
}
// read source
let source = match fs::read_to_string(&path) {
Ok(s) => s,
Err(e) => {
eprintln!("error: failed to read file {}\n {}", path.display(), e);
process::exit(1);
}
};
let parser_result = mist_parser::parse(&source).map_err(|e| match e {
ParseError::Ast(e) => {
let start_pos = e.span.start_pos().line_col();
let span = e.span.as_str();
format!(
"\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}",
path.as_os_str().display(),
start_pos.0,
start_pos.1,
e.error_message,
span,
if span.ends_with("\n") { "" } else { "\n" },
"^".repeat(span.trim().len()),
)
}
ParseError::PreAst(e) => format!("{e}"),
});
let ast = match parser_result {
Ok(ast) => ast,
Err(e) => {
eprintln!("error: parse failed in {}\n{}", path.display(), e);
process::exit(1);
}
};
// semantic::walk_ast(semantic::scope::Scope::from_top(root, &ast), &mut ast);
let mut gc = crate::codegen::RustCodegen::new();
let output = gc.generate(&ast);
if let Err(e) = fs::write(&output_path, output) {
eprintln!(
"error: failed to write output {}\n {}",
output_path.display(),
e
);
process::exit(1);
}
}
}
pub fn find_project_root() -> Option<PathBuf> {
let mut dir = std::env::current_dir().ok()?;
loop {
if dir.join("mist.json").exists() {
return Some(dir);
}
if !dir.pop() {
return None;
}
}
}
fn load_config(root: &Path) -> Config {
let content = fs::read_to_string(root.join("mist.json")).expect("failed to read mist.json");
serde_json::from_str(&content).expect("invalid mist.json format")
}
+105
View File
@@ -0,0 +1,105 @@
use <std::process>;
use <std::env>;
use <std::fs>;
use <mist_api::builder>;
use <mist_api::transpiler>;
void main() {
Vec<String> args = env::args().collect();
if (args.len() < 2) {
print_usage();
process::exit(1);
}
match (args[1].as_str()) {
"run" | "build" | "check" | "r" | "b" | "c" => {
var root = transpiler::build(false);
println!("");
if (builder::build(args, root)) {
println!("\x1b[32m\nBuild successful\x1b[0m");
} else {
println!("\x1b[31m\nBuild failed\x1b[0m");
}
}
"transpile" | "t" => {
transpiler::build(args.get(2).is_some());
}
"init" => {
init_project(args);
}
"version" | "--version" | "-v" => {
println!("mist {}", env!("CARGO_PKG_VERSION"));
}
"help" | "--help" | "-h" => {
print_usage();
}
unknown => {
eprintln!("error: unknown command '{}'\n", unknown);
print_usage();
process::exit(1);
}
}
}
void print_usage() {
println!("Mist - the mist compiler\n");
println!("󰖟 View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m");
println!(" Follow us on github! \x1b[35mhttps://github.com/mist-go\x1b[0m\n");
println!("usage:");
println!(" \x1b[36m mist run\x1b[0m,\x1b[36m r\x1b[0m run the project in the current directory\n");
println!(
" \x1b[36m mist build\x1b[0m,\x1b[36m b\x1b[0m build the project in the current directory\n"
);
println!(
" \x1b[36m mist transpile\x1b[0m,\x1b[36m t\x1b[0m transpile the project in the current directory\n"
);
println!(
" \x1b[36m mist check\x1b[0m,\x1b[36m c\x1b[0m check the project in the current directory\n"
);
println!(
" \x1b[36m mist init\x1b[0m initialize a project in the current folder\n"
);
println!(" \x1b[36m mist version \x1b[0m print the compiler version\n");
println!(" \x1b[36m mist help\x1b[0m print this message\n");
}
void init_project(Vec<String> mut args) {
args.remove(0);
new process::Command("cargo")
.args(args)
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit())
.stdin(process::Stdio::inherit())
.spawn()
.expect("Failed to run cargo").wait().expect("Unable to wait");
bool is_lib = fs::metadata("src/lib.rs").is_ok();
if (is_lib) {
fs::remove_file("src/lib.rs").expect("Failed to remove src/lib.rs");
fs::write("src/lib.mist", "void test() {\n}").expect("Failed to create src/lib.mist");
} else {
fs::remove_file("src/main.rs").expect("Failed to remove src/main.rs");
fs::write("src/main.mist", "void main() {\n println!(\"Hello, World!\");\n}\n").expect("Failed to create src/main.mist");
}
inject_mist_target(is_lib);
println!("\n\x1b[34minfo\x1b[0m: Please open Cargo.toml and adjust `\x1b[35mname\x1b[0m = ` as needed, Thank you for using Mist!\n");
}
void inject_mist_target(bool is_lib) {
String toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml");
str* inject = if (is_lib) {
"\n[lib]\nname = \"my_lib\"\npath = \".mist/src/lib.rs\"\n"
} else {
"\n[[bin]]\nname = \"my_bin\"\npath = \".mist/src/main.rs\"\n"
};
fs::write("Cargo.toml", toml_content+inject).expect("Failed to inject to Cargo.toml");
}
-48
View File
@@ -1,48 +0,0 @@
use std::process::{self, Command};
pub mod codegen;
pub mod compiler;
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
print_usage();
process::exit(1);
}
match args[1].as_str() {
"run" | "build" | "r" | "b" => {
compiler::build();
Command::new("cargo").args(&args[1..]).status().unwrap();
}
"transpile" | "t" => compiler::build(),
"version" | "--version" | "-v" => {
println!("mist {}", env!("CARGO_PKG_VERSION"));
}
"help" | "--help" | "-h" => {
print_usage();
}
unknown => {
eprintln!("error: unknown command '{}'\n", unknown);
print_usage();
process::exit(1);
}
}
}
fn print_usage() {
println!("Mist - the mist compiler\n");
println!("󰖟 View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m");
println!(" Follow us on github! \x1b[35mhttps://github.com/mist-go\x1b[0m\n");
println!("usage:");
println!(" \x1b[36m mist run\x1b[0m run the project in the current directory\n");
println!(
" \x1b[36m mist build\x1b[0m build the project in the current directory\n"
);
println!(
" \x1b[36m mist transpile\x1b[0m transpile the project in the current directory\n"
);
println!(" \x1b[36m mist version \x1b[0m print the compiler version\n");
println!(" \x1b[36m mist help\x1b[0m print this message\n");
}