├── .gitattributes ├── .github ├── version └── workflows │ ├── generator.yml │ ├── github_pages.yml │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── doc ├── .gitignore ├── book.toml └── src │ ├── SUMMARY.md │ ├── function_decl.md │ ├── function_signature.md │ ├── intro.md │ ├── language_reference.md │ ├── primitives.md │ ├── quick_start.md │ ├── self.md │ ├── struct.md │ └── trait.md ├── src ├── bin │ ├── logger │ │ └── mod.rs │ └── main.rs └── lib │ ├── ast │ ├── ast_print.rs │ ├── mod.rs │ ├── tree.rs │ ├── visit.rs │ └── visit_mut.rs │ ├── ast_lowering │ ├── ast_lowering_context.rs │ ├── hir_map.rs │ ├── infix_desugar.rs │ ├── loop_desugar.rs │ └── mod.rs │ ├── codegen │ ├── codegen_context.rs │ └── mod.rs │ ├── diagnostics │ ├── diagnostic.rs │ ├── diagnostics_list.rs │ └── mod.rs │ ├── helpers │ ├── class_name.rs │ ├── config.rs │ ├── mod.rs │ ├── scopes.rs │ ├── test_utils.rs │ └── walk_helpers.rs │ ├── hir │ ├── arena.rs │ ├── has_hir_id.rs │ ├── hir_id.rs │ ├── hir_node.rs │ ├── hir_printer.rs │ ├── mod.rs │ ├── tree.rs │ ├── visit.rs │ └── visit_mut.rs │ ├── infer │ ├── constraint.rs │ ├── mangle.rs │ ├── mod.rs │ ├── monomorphize │ │ ├── mod.rs │ │ └── monomorphizer.rs │ ├── state.rs │ └── trait_solver.rs │ ├── parser │ ├── default_impl_populator.rs │ ├── mod.rs │ ├── parsing_context.rs │ ├── source_file.rs │ ├── span.rs │ └── tests.rs │ ├── resolver │ ├── mod.rs │ ├── resolution_map.rs │ ├── resolve_ctx.rs │ └── unused_collector.rs │ ├── rock.rs │ ├── testcases │ ├── basic │ │ ├── 0_arg_fn │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── 1_arg_fn │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── 2_arg_fn │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── array │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── bool_false │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── bool_true │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── deep_monomorph │ │ │ └── main.rk.stdout │ │ ├── dot_assign │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── early_return │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── escaped_string │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── extern │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── fn_arg │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── fn_arg_array │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── fn_generic_sig │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── fn_sig │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── if_else │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── impl_self │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── indice_assign │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── let │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── main │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── monomorph │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── monomorph_in_trait │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── multi_style_struct_ctor │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── multiline_struct_const │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── negative_floats │ │ │ ├── 0_arg_fn │ │ │ │ ├── main.rk │ │ │ │ ├── main.rk.out │ │ │ │ └── main.rk.stdout │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── negative_numbers │ │ │ ├── 0_arg_fn │ │ │ │ ├── main.rk │ │ │ │ ├── main.rk.out │ │ │ │ └── main.rk.stdout │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── nested_array │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── nested_struct │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── nested_struct_dect_multiline │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── no_newline_end │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── op_func │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── operator_precedence │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── reassign │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── reassign_return │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── reassign_self │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── recur │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── self_returning_fn │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── simple_char │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── simple_struct │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── spaced_dot │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── string_index │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── struct_array_field │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── struct_impl │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── struct_index │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── trait_monomorph │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── trait_use_before_decl │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ └── while │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ ├── fails │ │ └── basic │ │ │ ├── fn_bad_arg │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ │ ├── fn_bad_arg_nb │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ │ ├── fn_bad_arg_nb2 │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ │ ├── fn_orpheline_sig │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ │ ├── fn_sig │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ │ └── struct_bad_field_type │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ ├── mods │ │ ├── basic_mod │ │ │ ├── _std.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── build │ │ │ └── main.rk.stdout │ │ ├── full_fact │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── func_arg_resolution │ │ │ ├── _std.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── nested_trait_resolution │ │ │ ├── _std.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── struct_new │ │ │ ├── lib.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ ├── unused_fn │ │ │ ├── _std.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ │ └── unused_impl_fn │ │ │ ├── _std.rk │ │ │ ├── main.rk │ │ │ ├── main.rk.out │ │ │ └── main.rk.stdout │ ├── test_template │ ├── tests_loader.rs │ └── trait │ │ ├── build │ │ └── main.rk.stdout │ │ ├── default_method │ │ ├── main.rk │ │ ├── main.rk.out │ │ └── main.rk.stdout │ │ ├── default_method_override │ │ ├── main.rk │ │ ├── main.rk.out │ │ └── main.rk.stdout │ │ ├── late_resolution │ │ ├── main.rk │ │ ├── main.rk.out │ │ └── main.rk.stdout │ │ ├── multi_resolution │ │ ├── main.rk │ │ ├── main.rk.out │ │ └── main.rk.stdout │ │ └── nested_fn_sig │ │ ├── main.rk │ │ ├── main.rk.out │ │ └── main.rk.stdout │ ├── tests.rs │ └── ty │ ├── func_type.rs │ ├── mod.rs │ ├── primitive_type.rs │ ├── struct_type.rs │ └── type.rs └── std ├── Rock.toml └── src ├── clone.rk ├── eq.rk ├── externs.rk ├── fs.rk ├── functor.rk ├── helpers.rk ├── lib.rk ├── num.rk ├── prelude.rk ├── print.rk ├── show.rk └── vec.rk /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rk linguist-language=haskell 2 | -------------------------------------------------------------------------------- /.github/version: -------------------------------------------------------------------------------- 1 | v0.2.4 2 | -------------------------------------------------------------------------------- /.github/workflows/generator.yml: -------------------------------------------------------------------------------- 1 | name: Generator 2 | 3 | on: 4 | [create, push] 5 | 6 | jobs: 7 | replace: 8 | runs-on: ubuntu-latest 9 | name: Generate files. 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Generate replacements 15 | run: | 16 | ./.github/templates/replacer.sh 17 | 18 | - name: Add & Commit 19 | uses: EndBug/add-and-commit@v7.3.0 20 | with: 21 | message: Generated files for new version 22 | -------------------------------------------------------------------------------- /.github/workflows/github_pages.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-20.04 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - run: cd ./doc 18 | 19 | - name: Setup mdBook 20 | uses: peaceiris/actions-mdbook@v1 21 | with: 22 | mdbook-version: '0.4.18' 23 | # mdbook-version: 'latest' 24 | 25 | - run: cd ./doc && mdbook build 26 | 27 | - name: Deploy 28 | uses: peaceiris/actions-gh-pages@v3 29 | if: ${{ github.ref == 'refs/heads/master' }} 30 | with: 31 | github_token: ${{ secrets.GITHUB_TOKEN }} 32 | publish_dir: ./doc/book 33 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master, develop ] 6 | pull_request: 7 | branches: [ master, develop ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-22.04 15 | 16 | steps: 17 | - name: Apt Update 18 | run: | 19 | sudo apt update 20 | sudo apt install llvm-13 clang 21 | 22 | - name: Rust Cache 23 | uses: Swatinem/rust-cache@v1.3.0 24 | 25 | - name: rust-toolchain 26 | uses: actions-rs/toolchain@v1.0.6 27 | with: 28 | toolchain: nightly 29 | override: true 30 | 31 | - uses: actions/checkout@v2 32 | 33 | - name: Build 34 | run: cargo +nightly build 35 | 36 | - name: Run tests 37 | run: cargo +nightly test 38 | 39 | # NOT WORKING 40 | # - name: rustfmt-check 41 | # uses: LoliGothick/rustfmt-check@v0.2.0 42 | # with: 43 | # token: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | # NOT WORKING 46 | # - name: rust-clippy-check 47 | # uses: actions-rs/clippy-check@v1.0.7 48 | # with: 49 | # token: ${{ secrets.GITHUB_TOKEN }} 50 | # toolchain: nightly 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | *.o 4 | a.out 5 | project 6 | *.ir 7 | *.s 8 | /project*/ 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rock" 3 | version = "0.4.3" 4 | authors = ["champii "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | clap = "2.32.0" 9 | lazy_static = "1.2.0" 10 | regex = "1.5.6" 11 | env_logger = "0.5.12" 12 | log = "0.4" 13 | inkwell = { version = "0.1.0-beta.4", features = ["llvm13-0"] } 14 | either = "1.5" 15 | serde = "*" 16 | serde_derive = '*' 17 | bincode = "*" 18 | colored = "2.0.0" 19 | paste = "1.0.5" 20 | rustyline = "9.0.0" 21 | nom = "7.1.1" 22 | nom_locate = "4.0.0" 23 | itertools = "0.10.3" 24 | snailquote = "0.3.1" 25 | ariadne = "0.1.5" 26 | 27 | [build-dependencies] 28 | walkdir = "2" 29 | 30 | [lib] 31 | name = "rock" 32 | path = "src/lib/rock.rs" 33 | 34 | [[bin]] 35 | name = "rock" 36 | path = "src/bin/main.rs" 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rock v0.4.3 2 | 3 | [![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/Champii/Rock/actions/workflows/rust.yml) 4 | [![Discord](https://img.shields.io/discord/990627124236939314.svg)](https://discord.gg/f6skPNB96J) 5 | 6 | [Documentation](https://champii.github.io/Rock) 7 | 8 | Native language made with Rust and LLVM. 9 | 10 | Aim to follow the enforced safeness of the Rust model with a borrow checker (Soon™) and to achieve high native performances thanks to LLVM. 11 | Rock is highly inspired from [Livescript](https://livescript.net/), [Haskell](https://www.haskell.org/) and [Rust](https://www.rust-lang.org/). 12 | 13 | No to be taken seriously (yet). 14 | Rock is still in its early conception phase, and everything can change and/or break at any time. 15 | Feel free to discuss any new feature or change you may like in an issue! We welcome and value every contribution. 16 | 17 | ## Index 18 | 19 | - [Rock v0.4.3](#rock-v0.4.3) 20 | - [Index](#index) 21 | - [Features](#features) 22 | - [Install](#install) 23 | - [From source](#from-source) 24 | - [With Cargo from Git (Recommanded)](#with-cargo-from-git-recommanded) 25 | - [Manual Clone and Build from Git](#manual-clone-and-build-from-git) 26 | - [Using Released Binary](#using-released-binary) 27 | - [Quickstart](#quickstart) 28 | - [Showcases](#showcases) 29 | - [Polymorphic function](#polymorphic-function) 30 | - [Custom infix operator](#custom-infix-operator) 31 | - [Trait Definition](#trait-definition) 32 | - [Trait default method](#trait-default-method) 33 | - [Struct instance and methods]( #struct-instance-and-methods ) 34 | - [Show and Print implementation]( #show-and-print-implementation ) 35 | - [Modules and Code Separation](#modules-and-code-separation) 36 | - [Development notes](#development-notes) 37 | 38 | --- 39 | 40 | ## Features 41 | 42 | - Strongly typed 43 | - Type inference 44 | - Custom operators 45 | - Typeclass (Traits) 46 | - Polymorphism by default 47 | - Compile to LLVM IR 48 | 49 | --- 50 | 51 | ## Install 52 | 53 | ### From source 54 | 55 | You will need `llvm-13` and `clang-13` somewhere in your $PATH 56 | 57 | #### With Cargo from Git (Recommanded) 58 | 59 | ```sh 60 | cargo install --locked --git https://github.com/Champii/Rock --tag v0.4.3 61 | rock -V 62 | ``` 63 | 64 | #### Manual Clone and Build from Git 65 | 66 | ```sh 67 | git clone https://github.com/Champii/Rock.git 68 | cd Rock 69 | cargo run --release -- -V 70 | ``` 71 | 72 | Note: If you clone and build manually, make sure to add `Rock/target/release/` to you `$PATH` so you can run it anywhere on your system. 73 | This method uses the `master` branch of Rock, that is not stable. You can checkout the latest version tag. 74 | 75 | Rock has been tested against Rust stable v1.60.0 and nightly 76 | 77 | [Adding Rust Nightly](https://github.com/Champii/Rock/wiki/Adding-Rust-Nightly) 78 | 79 | ### Using Released Binary 80 | 81 | [Rock v0.4.3](https://github.com/Champii/Rock/releases/download/v0.4.3/rock) 82 | 83 | ``` sh 84 | wget https://github.com/Champii/Rock/releases/download/v0.4.3/rock 85 | chmod +x rock 86 | ./rock -V 87 | ``` 88 | 89 | This install method is not well tested yet, and might not work for your environment. 90 | It requires a x86_64 architecture and GLIBC 2.34. (Don't try to upgrade your GLIBC if you don't know what you are doing) 91 | 92 | --- 93 | 94 | ## Quickstart 95 | 96 | - Lets create a new project folder to compute some factorials 97 | 98 | ``` sh 99 | rock new factorial && cd factorial 100 | ``` 101 | 102 | - Edit the `factorial/src/main.rk` file: 103 | 104 | ```haskell 105 | fact: x -> 106 | if x <= 1 107 | then 1 108 | else x * fact (x - 1) 109 | 110 | main: -> fact 4 .print! 111 | ``` 112 | 113 | Assuming that you built Rock and put its binary in your PATH: 114 | 115 | ``` sh 116 | $ rock run 117 | 24 118 | ``` 119 | 120 | Rock should have produced a `./build/` folder, that contains your `a.out` executable. 121 | You can execute it directly: 122 | 123 | ```sh 124 | $ ./build/a.out 125 | 24 126 | ``` 127 | 128 | Take a look at `rock --help` for a quick tour of its flags and arguments 129 | 130 | Note that you currently MUST be at the project root to run the compiler. (i.e. inside the `./factorial/` folder) 131 | 132 | --- 133 | 134 | ## Showcases 135 | 136 | ### Polymorphic function 137 | 138 | ``` haskell 139 | id: x -> x 140 | 141 | main: -> 142 | id 1 .print! 143 | id 2.2 .print! 144 | id "Test" .print! 145 | ``` 146 | 147 | Prints 148 | 149 | ``` sh 150 | $ rock run 151 | 1 152 | 2.2 153 | Test 154 | ``` 155 | 156 | The `id` function here is polymorphic by default, as we don't make any constraint on the type that we should take or return. 157 | If we did something like this 158 | `id: x -> x + x` 159 | We would have constrained `x` to types that implement [`Num`](https://github.com/Champii/Rock/blob/master/std/src/num.rk) 160 | 161 | Note that this example would still be valid, as `Int64`, `Float64` and `String` are all implementors of `Num`. 162 | `String` is nowhere at its place here, and only implements `+` for string concatenation. This should change in the future with more traits like `Add` in rust 163 | 164 | The output would be: 165 | 166 | ``` sh 167 | 2 168 | 4.4 169 | TestTest 170 | ``` 171 | 172 | ### Custom infix operator 173 | 174 | ``` haskell 175 | infix |> 1 176 | |>: x, f -> f x 177 | 178 | f: x -> x + 2 179 | 180 | main: -> (4 |> f).print! 181 | ``` 182 | 183 | ``` sh 184 | $ rock run 185 | 6 186 | ``` 187 | 188 | You can create any operator that is made of any combination of one or more of `'+', '-', '/', '*', '|', '<', '>', '=', '!', '$', '@', '&'` 189 | 190 | Most of the commonly defined operators like `+`, `<=`, etc are already implemented by the [stdlib](https://github.com/Champii/Rock/tree/master/std) that is automaticaly compiled with every package. 191 | There is a `--nostd` option to allow you to use your own custom implementation. 192 | 193 | ### Trait definition 194 | 195 | This `trait ToString` is redondant with the `trait Show` implemented in the stdlib, and serves as a demonstration only 196 | 197 | ``` haskell 198 | trait ToString 199 | @tostring: String 200 | 201 | impl ToString Int64 202 | @tostring: -> @show! 203 | 204 | impl ToString Float64 205 | @tostring: -> @show! 206 | 207 | main: -> 208 | (33).tostring!.print! 209 | (42.42).tostring!.print! 210 | ``` 211 | 212 | ``` sh 213 | $ rock run 214 | 33 215 | 42.42 216 | ``` 217 | 218 | ### Trait default method 219 | 220 | ``` haskell 221 | trait ToString 222 | @tostring: -> @show! 223 | 224 | impl ToString Int64 225 | impl ToString Float64 226 | 227 | main: -> 228 | (33).tostring!.print! 229 | (42.42).tostring!.print! 230 | ``` 231 | 232 | ``` sh 233 | $ rock run 234 | 33 235 | 42.42 236 | ``` 237 | 238 | ### Struct instance and methods 239 | 240 | ``` haskell 241 | struct Player 242 | level: Int64 243 | name: String 244 | 245 | impl Player 246 | new: level -> 247 | Player 248 | level: level 249 | name: "Default" 250 | @getlevel: -> @level 251 | 252 | main: -> 253 | Player::new 1 254 | .getlevel! 255 | .print! 256 | ``` 257 | 258 | ``` sh 259 | $ rock run 260 | 1 261 | ``` 262 | 263 | ### Show and Print implementation 264 | 265 | ``` haskell 266 | struct Player 267 | level: Int64 268 | name: String 269 | 270 | impl Show Player 271 | @show: -> @name + "(" + @level.show! + ")" 272 | 273 | # This will be automatic in the future 274 | impl Print Player 275 | 276 | main: -> 277 | let player = Player 278 | level: 42 279 | name: "MyName" 280 | 281 | player.print! 282 | ``` 283 | 284 | ``` sh 285 | $ rock run 286 | MyName(42) 287 | ``` 288 | 289 | ### Modules and code separation 290 | 291 | - `./myproj/src/foo.rk` 292 | 293 | ```haskell 294 | bar: x -> x + 1 295 | ``` 296 | 297 | - `./myproj/src/main.rk` 298 | 299 | ```haskell 300 | mod foo 301 | 302 | use foo::bar 303 | 304 | main: -> bar 1 .print! 305 | ``` 306 | 307 | ```sh 308 | $ rock run 309 | 2 310 | ``` 311 | 312 | Note that we could have skiped the 313 | `use foo::bar` 314 | if we wrote 315 | `main: -> foo::bar 1 .print!` 316 | 317 | --- 318 | 319 | ## Development notes 320 | 321 | This project, its syntax and its APIs are subject to change at any moment. 322 | This is a personal project, so please bear with me 323 | 324 | Differently put: this is a big red hot pile of experimental garbage right now 325 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_dir; 2 | use std::fs::File; 3 | use std::io; 4 | use std::io::Write; 5 | use std::path::Path; 6 | use std::path::PathBuf; 7 | 8 | use walkdir::WalkDir; 9 | 10 | fn visit_dirs(dir: &Path) -> io::Result> { 11 | let mut res = vec![]; 12 | 13 | if dir.is_dir() { 14 | for entry in read_dir(dir)? { 15 | let entry = entry?; 16 | let path = entry.path(); 17 | 18 | if path.is_dir() { 19 | res.extend(visit_dirs(&path)?); 20 | } else if let Some(ext) = path.extension() { 21 | if ext == "rk" && path.file_name().unwrap() == "main.rk" { 22 | res.push(entry.path().to_str().unwrap().to_string()); 23 | } 24 | } 25 | } 26 | } 27 | 28 | Ok(res) 29 | } 30 | 31 | fn schedule_rerun_if_folder_changed(path: &Path) { 32 | for entry in WalkDir::new(path) { 33 | let entry = entry.unwrap(); 34 | 35 | if entry.path() == path { 36 | continue; 37 | } 38 | 39 | if entry.path().is_dir() { 40 | schedule_rerun_if_folder_changed(&entry.path()); 41 | } else { 42 | println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); 43 | } 44 | } 45 | } 46 | 47 | // build script's entry point 48 | fn main() { 49 | schedule_rerun_if_folder_changed(&PathBuf::from("src/lib/testcases/")); 50 | 51 | let out_dir = "src/lib"; 52 | let destination = Path::new(&out_dir).join("tests.rs"); 53 | let mut output_file = File::create(&destination).unwrap(); 54 | 55 | // write test file header, put `use`, `const` etc there 56 | write_header(&mut output_file); 57 | 58 | for file in visit_dirs(Path::new(&"src/lib/testcases".to_string())).unwrap() { 59 | write_test(&mut output_file, &file); 60 | } 61 | } 62 | 63 | fn write_test(output_file: &mut File, path: &str) { 64 | let path = path.replace("src/lib/", ""); 65 | 66 | let name = path.replace("./", "").replace("/", "_").replace(".rk", ""); 67 | 68 | write!( 69 | output_file, 70 | include_str!("src/lib/testcases/test_template"), 71 | name = name, 72 | path = path 73 | ) 74 | .unwrap(); 75 | } 76 | 77 | fn write_header(output_file: &mut File) { 78 | write!( 79 | output_file, 80 | r##"use std::path::PathBuf; 81 | 82 | #[allow(dead_code)] 83 | fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) {{ 84 | let mut config = super::Config::default(); 85 | 86 | config.project_config.entry_point = PathBuf::from(path); 87 | config.quiet = true; 88 | 89 | let expected_ret = expected_ret.parse::().unwrap(); 90 | 91 | let (ret_code, stdout) = super::helpers::test_utils::run(path, input.to_string(), config); 92 | 93 | assert_eq!(expected_ret, ret_code); 94 | assert_eq!(expected_output, stdout); 95 | }} 96 | "## 97 | ) 98 | .unwrap(); 99 | } 100 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /doc/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Champii"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Rock v0.4.3 language documentation" 7 | -------------------------------------------------------------------------------- /doc/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](./intro.md) 4 | - [Quick start](./quick_start.md) 5 | - [Language reference](./language_reference.md) 6 | - [Primitives](./primitives.md) 7 | - [Function](./function_decl.md) 8 | - [Function signature](./function_signature.md) 9 | - [Struct](./struct.md) 10 | - [Trait](./trait.md) 11 | - [Self](./self.md) 12 | -------------------------------------------------------------------------------- /doc/src/function_decl.md: -------------------------------------------------------------------------------- 1 | # Function 2 | 3 | ## Syntax 4 | 5 | The function declaration format is: 6 | 7 | ```haskell 8 | function_name: arg1, arg2, arg3 -> return_value 9 | ``` 10 | 11 | The function call format is: 12 | 13 | ```haskell 14 | function_name arg1, arg2, arg3 15 | ``` 16 | 17 | But you can add parenthesis 18 | 19 | ```haskell 20 | function_name(arg1, arg2, arg3) 21 | ``` 22 | 23 | Every Rock package must have a `./src/main.rk` file containing a `main` function 24 | 25 | ```haskell 26 | main: -> "Hello World!".print! 27 | ``` 28 | 29 | You can call functions with no args with a bang `!` like the `.print!` above or with 30 | explicit parenthesis like `.print()` 31 | But the idiomatic way is to avoid parenthesis as much as possible 32 | 33 | ```haskell 34 | add: x, y -> x + y 35 | main: -> add 2, 3 36 | ``` 37 | 38 | Rock does not allow for uppercase identifiers, so you should embrace the snake case. 39 | Uppercase names are reserved for custom types like [Struct](./struct.md) or [Trait](./trait.md) 40 | 41 | ## Polymorphism 42 | 43 | Every function in Rock is polymorphic by default, and only infer the types based on the caller and the return value of its body. 44 | Multiple calls with different types will generate each corresponding function, just like the templates in C++ or in Rust, except the generic parameter is always implicit if no constraints have been made. 45 | 46 | For example, lets declare the most polymorphic function of all, `id`: 47 | 48 | ```haskell 49 | id: x -> x 50 | ``` 51 | 52 | This function takes a `x` argument and returns it. Here `x` can be of any type 53 | 54 | ```haskell 55 | main: -> 56 | id 42 57 | id 6.66 58 | id "Hello" 59 | id my_custom_struct 60 | ``` 61 | 62 | The infered signature of the function is `id: a => a`, with `a` being any type 63 | 64 | If we had changed the body of `id` to be: 65 | 66 | ```haskell 67 | id: x -> x + x 68 | ``` 69 | 70 | the previous main would still work if all of the types implemented the `Num` trait from the stdlib, that provide implementation of `+` for the basic types 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /doc/src/function_signature.md: -------------------------------------------------------------------------------- 1 | # Function signature 2 | 3 | ## Syntax 4 | 5 | ```haskell 6 | foo: a => Int64 => String 7 | foo: x, y -> "bar" 8 | ``` 9 | 10 | Here, the `foo` function takes 2 arguments, of type `a` (generic) and `Int64`, and returns a `String` 11 | The implementation ignore the two arguments and returns "bar" 12 | 13 | A signature is always formed of at least one type. 14 | The last (or only) type is the return type 15 | 16 | Functions can take functions as parameter, and must be representable in a signature: 17 | 18 | ```haskell 19 | my_func: a => (a => b) => b 20 | my_func: x, f -> f x 21 | 22 | # A function of type (a => b) that resolves to (Int64 => String) 23 | handler: x -> x.show! 24 | 25 | main: -> my_func 42, handler .print! 26 | ``` 27 | 28 | Here the second argument of the function `my_func` is a function that take a generic type `a` and returns a type `b`, and the whole method returns a type `b` 29 | 30 | This outputs: 31 | 32 | ``` 33 | 42 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /doc/src/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Rock is an experimental native language. 4 | 5 | Its main goal is to mix some parts of popular functionnal languages like haskell or livescript with 6 | the rigor of Rust while staying elegant and fast with minimal runtime 7 | 8 | Rock is at an early development stage. Don't expect everything to work smoothly. (you have been warned) 9 | 10 | ```haskell 11 | struct Player 12 | level: Int64 13 | name: String 14 | 15 | impl Player 16 | new: x -> 17 | Player 18 | level: x 19 | name: "MyName" 20 | 21 | impl Show Player 22 | @show: -> @name + "(" + @level.show! + ")" 23 | 24 | use std::print::printl 25 | 26 | impl Print Player 27 | @print: -> printl @ 28 | 29 | main: -> 30 | let player = Player::new 42 31 | player.print! 32 | ``` 33 | 34 | Rock syntax is entierly based on indentation, like Livescript. 35 | Each whitespace count, and tabulations `\t` are prohibited. 36 | 37 | The number of whitespace to make one level of indentation is taken from the first indent level. 38 | If your first indentation has two whitespaces, the rest of the file must have the same number of whitespace per level (here two) 39 | 40 | We generally use two as a default, but you can use any number you want. Here is the same example with four whitespaces: 41 | 42 | ```haskell 43 | struct Player 44 | level: Int64 45 | name: String 46 | 47 | impl Player 48 | new: x -> 49 | Player 50 | level: x 51 | name: "MyName" 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /doc/src/language_reference.md: -------------------------------------------------------------------------------- 1 | # Language reference 2 | 3 | -------------------------------------------------------------------------------- /doc/src/primitives.md: -------------------------------------------------------------------------------- 1 | # Primitives 2 | 3 | Rock actually support some essential primitives. 4 | 5 | ## Boolean 6 | 7 | The `Bool` type 8 | 9 | ```haskell 10 | main: -> 11 | true.print! 12 | false.print! 13 | ``` 14 | 15 | ## Integer 16 | 17 | The most stable integer is `Int64` and should be used until the rest follows. 18 | 19 | ```haskell 20 | main: -> 0 21 | ``` 22 | 23 | Rock has an inference mechanism that automatically assign types to variables and primitives 24 | 25 | Here the `main` function is special and has a fixed signature `(Int64)` so `0` is a `Int64` 26 | You can learn more about [Function signature](./function_signature.md) 27 | 28 | ## Float 29 | 30 | ```haskell 31 | main: -> 32 | let x = 2.2 33 | x.print! 34 | ``` 35 | 36 | ## Char 37 | 38 | ```haskell 39 | main: -> '*'.print! 40 | ``` 41 | 42 | ## String 43 | 44 | Strings are immutable (like in most language) 45 | 46 | ```haskell 47 | main: -> ("Hello" + " World!").print! 48 | ``` 49 | 50 | You can index them to get a `Char` 51 | 52 | ```haskell 53 | second_char: -> "Hello"[1] 54 | ``` 55 | 56 | Strings are 0-indexed 57 | 58 | Both Strings and Chars accept some escaped characters: 59 | `\\ \' \" \n \r \0` 60 | 61 | In the future there will be a distinction between native `Str` and on-the-heap `String` like in Rust 62 | 63 | ## Array 64 | 65 | There is very limited support for arrays, they are still in development. 66 | 67 | ```haskell 68 | main: -> 69 | let a = [1, 2, 3] 70 | a[2] = 4 71 | a[2] 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /doc/src/quick_start.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | The actual best way to start is to build and install Rock via cargo: 4 | 5 | ```sh 6 | cargo install --git https://github.com/Champii/Rock --locked 7 | rock -V 8 | ``` 9 | Then to create a new empty project folder 10 | 11 | ```sh 12 | rock new my_project 13 | cd my_project 14 | ``` 15 | 16 | The project folder should contain a `src` folder with a `src/main.rk` file that should look like this: 17 | 18 | ```haskell 19 | main: -> "Hello World !".print! 20 | ``` 21 | 22 | You can immediately build and run this default snippet with 23 | 24 | ```sh 25 | rock run 26 | ``` 27 | 28 | This should output 29 | 30 | ```sh 31 | Hello World ! 32 | ``` 33 | 34 | The compiler has created a `build` folder containing your compiled executable `build/a.out` 35 | 36 | -------------------------------------------------------------------------------- /doc/src/self.md: -------------------------------------------------------------------------------- 1 | # Self 2 | 3 | ## The `self` parameter 4 | 5 | The `self` parameter is represented by the `@` symbol. 6 | 7 | ```haskell 8 | impl CanDouble Int64 9 | @double_me: -> @ + @ 10 | ``` 11 | 12 | This method desugars to: 13 | 14 | ```haskell 15 | impl CanDouble Int64 16 | double_me: self -> self + self 17 | ``` 18 | 19 | Those are strictly equivalent, as `@` desugar to `self` 20 | We can see that we also have a `@` at the start of the name of the method. This allows for auto-injection of the self-parameter: 21 | 22 | ## Auto-inject self parameter 23 | 24 | The standard way of defining a self-method is to auto-inject the self parameter: 25 | 26 | ```haskell 27 | impl CanDouble Int64 28 | @double_me: -> @ + @ 29 | ``` 30 | 31 | ## Auto-return self 32 | 33 | And if you also wanted to return `self` for chainable capababilities: 34 | 35 | ```haskell 36 | impl CanDouble Int64 37 | @double_me: @-> 38 | @ = @ + @ 39 | 40 | main: -> 41 | let x = 2 42 | x.double_me!.double_me!.double_me! 43 | x.print! 44 | ``` 45 | Outputs 46 | ``` 47 | 16 48 | ``` 49 | 50 | The `@->` automatically inject the `@` as last returned statement of the function's body. 51 | This operator is only available when using the `@method_name:` notation 52 | 53 | -------------------------------------------------------------------------------- /doc/src/struct.md: -------------------------------------------------------------------------------- 1 | # Structure 2 | 3 | ## Declaration: 4 | 5 | Here is the idiomatic way to declare a structure 6 | 7 | ```haskell 8 | struct Counter 9 | value: Int64 10 | name: String 11 | ``` 12 | 13 | This structure has two fields `value` and `name` with their types respectively `Int64` and `String` 14 | 15 | ## Implementation 16 | 17 | You can attach some methods to the structure, for example here a class-method `new` 18 | that takes a `x` and is used as a constructor 19 | 20 | The `increment` method is an instance-method that takes nothing, increments the `value` field by `1` and returns `@` 21 | 22 | ```haskell 23 | impl Counter 24 | new: x -> 25 | Counter 26 | value: x 27 | name: "Counter" 28 | 29 | @increment: @-> 30 | @value = @value + 1 31 | ``` 32 | 33 | You can learn more about the `@` parameter here: [Self](./self.md) 34 | 35 | ```haskell 36 | main: -> 37 | Counter::new(41) 38 | .increment! 39 | .value 40 | .print! 41 | ``` 42 | 43 | This prints `42` 44 | 45 | --- 46 | 47 | *Note: We could have written something more compact, but less readable 48 | 49 | ```haskell 50 | impl Counter 51 | new: x -> Counter value: x, name: "Counter" 52 | @increment: @-> @value = @value + 1 53 | 54 | main: -> Counter::new 41 .increment!.value.print! 55 | ``` 56 | 57 | 58 | -------------------------------------------------------------------------------- /doc/src/trait.md: -------------------------------------------------------------------------------- 1 | # Trait 2 | 3 | ## Declaration 4 | 5 | The trait feature is very similar to what Rust have 6 | You can define some 'interfaces' that has some methods, you can then implement them for your types. 7 | 8 | For example, we will implement a trait that double itself with the `+` operator 9 | 10 | ```haskell 11 | trait CanDouble 12 | @double_me: @ 13 | ``` 14 | 15 | We define a trait `CanDouble` and declare a method `double_me` that returns the generic self type `@`. 16 | 17 | ## Implementation 18 | 19 | We can now implement the trait for any type we want, like `Int64` 20 | 21 | ```haskell 22 | impl CanDouble Int64 23 | @double_me: -> @ + @ 24 | ``` 25 | 26 | We can then call this method: 27 | 28 | ```haskell 29 | main: -> (2).double_me!.print! 30 | ``` 31 | 32 | This output 33 | ``` 34 | 4 35 | ``` 36 | 37 | ## Default method 38 | 39 | You can define trait methods that have a default implementation. 40 | That means you don't have to reimplement it for each type, but you can override the default implementation with your own if you need it. 41 | 42 | ```haskell 43 | trait CanDouble 44 | @double_me: -> @ + @ 45 | 46 | impl CanDouble Int64 47 | 48 | main: -> (2).double_me!.print! 49 | ``` 50 | 51 | ### Overriding 52 | 53 | You can override a default implementation 54 | 55 | ```haskell 56 | trait CanDouble 57 | @double_me: -> @ + @ 58 | 59 | impl CanDouble Int64 60 | @double_me: -> @ * 2 61 | 62 | main: -> (2).double_me!.print! 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /src/bin/logger/mod.rs: -------------------------------------------------------------------------------- 1 | use env_logger::{Builder, Color, Env}; 2 | use log::Level; 3 | use std::io::Write; 4 | 5 | pub fn init_logger() { 6 | let env = Env::default(); 7 | 8 | let mut builder = Builder::from_env(env); 9 | 10 | builder.format(|buf, record| { 11 | let level = record.level(); 12 | let mut style = buf.style(); 13 | 14 | let color = match level { 15 | Level::Trace => Color::White, 16 | Level::Debug => Color::Cyan, 17 | Level::Info => Color::Green, 18 | Level::Warn => Color::Yellow, 19 | Level::Error => Color::Red, 20 | }; 21 | 22 | style.set_color(color); 23 | 24 | if level == Level::Error { 25 | style.set_bold(true); 26 | } 27 | 28 | write!(buf, "[{:>5}] ", style.value(level)).unwrap(); 29 | 30 | let ts = buf.timestamp(); 31 | write!(buf, "[{}] ", style.value(ts)).unwrap(); 32 | 33 | let module_path = record.module_path().unwrap().to_string(); 34 | 35 | write!(buf, "[{:^20}] ", style.value(module_path)).unwrap(); 36 | 37 | writeln!(buf, "{}", style.value(record.args())).unwrap(); 38 | 39 | Ok(()) 40 | }); 41 | 42 | // builder.filter_level(LevelFilter::Warn); 43 | 44 | builder.init(); 45 | } 46 | -------------------------------------------------------------------------------- /src/bin/main.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | extern crate rock; 3 | 4 | #[macro_use] 5 | extern crate log; 6 | 7 | use clap::{App, Arg, SubCommand}; 8 | use std::{ 9 | fs::{self, File}, 10 | io::Write, 11 | path::{Path, PathBuf}, 12 | process::Command, 13 | }; 14 | 15 | pub mod logger; 16 | 17 | use rock::diagnostics::DiagnosticKind; 18 | pub(crate) use rock::*; 19 | 20 | fn build(config: &Config) -> bool { 21 | debug!(" -> Building"); 22 | 23 | let entry_file = "./src/main.rk"; 24 | 25 | fs::create_dir_all(config.build_folder.clone()).unwrap(); 26 | 27 | if let Err(diagnostic) = rock::compile_file(entry_file.to_string(), config) { 28 | if let DiagnosticKind::NoError = diagnostic.get_kind() { 29 | } else { 30 | println!("Error: {}", diagnostic.get_kind()); 31 | } 32 | 33 | return false; 34 | } 35 | 36 | let clang_cmd = Command::new("clang") 37 | .args(&[ 38 | config.build_folder.join("out.bc").to_str().unwrap(), 39 | "-o", 40 | config.build_folder.join("a.out").to_str().unwrap(), 41 | ]) 42 | .output() 43 | .expect("failed to compile to ir"); 44 | 45 | match clang_cmd.status.code() { 46 | Some(code) => { 47 | if code != 0 { 48 | println!( 49 | "BUG: Cannot compile: \n{}", 50 | String::from_utf8(clang_cmd.stderr).unwrap() 51 | ); 52 | 53 | return false; 54 | } 55 | } 56 | None => println!( 57 | "\nError running: \n{}", 58 | String::from_utf8(clang_cmd.stderr).unwrap() 59 | ), 60 | } 61 | 62 | true 63 | } 64 | 65 | fn run(config: Config) { 66 | if !build(&config) { 67 | return; 68 | } 69 | 70 | let cmd = Command::new(config.build_folder.join("a.out").to_str().unwrap()) 71 | .output() 72 | .expect("failed to execute binary"); 73 | 74 | print!("{}", unsafe { String::from_utf8_unchecked(cmd.stdout) }); 75 | 76 | match cmd.status.code() { 77 | Some(code) => { 78 | std::process::exit(code); 79 | } 80 | None => println!( 81 | "\nError running: \n{}", 82 | String::from_utf8(cmd.stderr).unwrap() 83 | ), 84 | } 85 | 86 | std::process::exit(-1); 87 | } 88 | 89 | fn main() { 90 | let matches = App::new("Rock") 91 | .version(env!("CARGO_PKG_VERSION")) 92 | .about("A compiler for the Rock programming language") 93 | .arg( 94 | Arg::with_name("verbose") 95 | .takes_value(false) 96 | .short("v") 97 | .long("verbose") 98 | .help("Verbose level"), 99 | ) 100 | .arg( 101 | Arg::with_name("quiet") 102 | .takes_value(false) 103 | .short("q") 104 | .long("quiet") 105 | .help("Silence all outputs"), 106 | ) 107 | .arg( 108 | Arg::with_name("ast") 109 | .short("a") 110 | .long("ast") 111 | .takes_value(false) 112 | .help("Show ast"), 113 | ) 114 | .arg( 115 | Arg::with_name("hir") 116 | .short("h") 117 | .long("hir") 118 | .takes_value(false) 119 | .help("Show hir"), 120 | ) 121 | .arg( 122 | Arg::with_name("thir") 123 | .short("t") 124 | .long("thir") 125 | .takes_value(false) 126 | .help("Show typed hir after monomorphization"), 127 | ) 128 | .arg( 129 | Arg::with_name("no-optimize") 130 | .short("N") 131 | .long("no-optimize") 132 | .takes_value(false) 133 | .help("Disable LLVM optimization passes"), 134 | ) 135 | .arg( 136 | Arg::with_name("ir") 137 | .short("i") 138 | .long("ir") 139 | .takes_value(false) 140 | .help("Show the generated IR"), 141 | ) 142 | .arg( 143 | Arg::with_name("nostd") 144 | .long("nostd") 145 | .takes_value(false) 146 | .help("Does not include stdlib"), 147 | ) 148 | .arg( 149 | Arg::with_name("output-folder") 150 | .short("o") 151 | .long("output-folder") 152 | .takes_value(true) 153 | .default_value("./build") 154 | .help("Choose a different output folder"), 155 | ) 156 | .subcommand(SubCommand::with_name("build").about("Build the current project directory")) 157 | .subcommand(SubCommand::with_name("run").about("Run the current project directory")) 158 | .subcommand( 159 | SubCommand::with_name("new") 160 | .about("Create a new empty project folder") 161 | .arg( 162 | Arg::with_name("name") 163 | .required(true) 164 | .help("The name of the new project"), 165 | ), 166 | ) 167 | .get_matches(); 168 | 169 | let config = rock::Config { 170 | verbose: matches.is_present("verbose"), 171 | quiet: matches.is_present("quiet"), 172 | show_ast: matches.is_present("ast"), 173 | show_hir: matches.is_present("hir"), 174 | show_thir: matches.is_present("thir"), 175 | show_ir: matches.is_present("ir"), 176 | no_optimize: matches.is_present("no-optimize"), 177 | build_folder: PathBuf::from(matches.value_of("output-folder").unwrap()), 178 | std: !matches.is_present("nostd"), 179 | ..Default::default() 180 | }; 181 | 182 | logger::init_logger(); 183 | 184 | if let Some(_matches) = matches.subcommand_matches("build") { 185 | build(&config); 186 | } else if let Some(_matches) = matches.subcommand_matches("run") { 187 | run(config); 188 | } else if let Some(matches) = matches.subcommand_matches("new") { 189 | create_project_folder(matches.value_of("name").unwrap()); 190 | } else { 191 | println!("{}", matches.usage()); 192 | } 193 | } 194 | 195 | fn create_project_folder(name: &str) { 196 | let path = Path::new(name); 197 | 198 | if path.exists() { 199 | println!("Error: {} already exists", name); 200 | return; 201 | } 202 | 203 | fs::create_dir(path).expect("Failed to create project folder"); 204 | fs::create_dir(path.join("src")).expect("Failed to create project src folder"); 205 | 206 | let mut file = File::create(path.join("src/main.rk")).expect("Failed to create main.rk"); 207 | 208 | file.write(b"main: -> \"Hello World !\".print!").unwrap(); 209 | } 210 | -------------------------------------------------------------------------------- /src/lib/ast/ast_print.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use paste::paste; 4 | 5 | use crate::{ 6 | ast::{tree::*, visit::*}, 7 | helpers::*, 8 | ty::*, 9 | }; 10 | 11 | pub struct AstPrintContext { 12 | indent: usize, 13 | } 14 | 15 | impl AstPrintContext { 16 | pub fn new() -> Self { 17 | Self { indent: 0 } 18 | } 19 | 20 | pub fn increment(&mut self) { 21 | self.indent += 1; 22 | } 23 | 24 | pub fn decrement(&mut self) { 25 | self.indent -= 1; 26 | } 27 | 28 | pub fn indent(&self) -> usize { 29 | self.indent 30 | } 31 | 32 | pub fn print(&self, t: T) { 33 | let indent_str = String::from(" ").repeat(self.indent()); 34 | 35 | println!("{}{:30}", indent_str, t.class_name_self()); 36 | } 37 | 38 | pub fn print_primitive(&self, t: T) 39 | where 40 | T: Debug, 41 | { 42 | let indent_str = String::from(" ").repeat(self.indent()); 43 | 44 | println!("{}{:?}", indent_str, t); 45 | } 46 | } 47 | 48 | macro_rules! impl_visitor_trait { 49 | ($( 50 | $name:ty 51 | )+) => { 52 | impl<'ast> Visitor<'ast> for AstPrintContext { 53 | fn visit_name(&mut self, name: &str) { 54 | self.print_primitive(name); 55 | } 56 | 57 | fn visit_type(&mut self, t: &Type) { 58 | self.print_primitive(t); 59 | } 60 | 61 | fn visit_primitive(&mut self, val: T) 62 | where 63 | T: Debug, 64 | { 65 | self.print_primitive(val); 66 | } 67 | 68 | paste! { 69 | $( 70 | fn [](&mut self, node: &'ast $name) { 71 | 72 | self.print(node); 73 | 74 | self.increment(); 75 | 76 | [](self, node); 77 | 78 | self.decrement(); 79 | } 80 | )+ 81 | } 82 | } 83 | }; 84 | } 85 | 86 | impl_visitor_trait!( 87 | Root 88 | TopLevel 89 | StructDecl 90 | Use 91 | Trait 92 | // Assign 93 | Impl 94 | FunctionDecl 95 | Identifier 96 | Body 97 | Statement 98 | For 99 | While 100 | ForIn 101 | // Expression 102 | /* If 103 | Else */ 104 | // UnaryExpr 105 | StructCtor 106 | Operator 107 | // PrimaryExpr 108 | SecondaryExpr 109 | Operand 110 | Argument 111 | // Literal 112 | Array 113 | NativeOperator 114 | FuncType 115 | ); 116 | -------------------------------------------------------------------------------- /src/lib/ast/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod ast_print; 3 | 4 | pub mod tree; 5 | pub mod visit; 6 | pub mod visit_mut; 7 | 8 | pub use tree::*; 9 | 10 | // TODO: Make it the same way as HirId and FnBodyId ? 11 | pub type NodeId = u64; 12 | -------------------------------------------------------------------------------- /src/lib/ast/visit.rs: -------------------------------------------------------------------------------- 1 | use paste::paste; 2 | 3 | use crate::ast::tree::*; 4 | use crate::ty::*; 5 | 6 | macro_rules! generate_visitor_trait { 7 | ($( 8 | $name:ty 9 | )+) => { 10 | pub trait Visitor<'ast>: Sized { 11 | fn visit_name(&mut self, _name: &str) {} 12 | 13 | fn visit_primitive(&mut self, _val: T) 14 | where 15 | T: std::fmt::Debug, 16 | {} 17 | 18 | paste! { 19 | $( 20 | fn [](&mut self, node: &'ast $name) { 21 | [](self, node); 22 | } 23 | )+ 24 | } 25 | } 26 | }; 27 | } 28 | 29 | generate_visitor_trait!( 30 | Root 31 | Mod 32 | TopLevel 33 | Assign 34 | AssignLeftSide 35 | Prototype 36 | Use 37 | Trait 38 | Impl 39 | FunctionDecl 40 | StructDecl 41 | Identifier 42 | IdentifierPath 43 | Body 44 | Statement 45 | For 46 | ForIn 47 | While 48 | Expression 49 | If 50 | Else 51 | UnaryExpr 52 | Operator 53 | PrimaryExpr 54 | SecondaryExpr 55 | Operand 56 | Argument 57 | Literal 58 | StructCtor 59 | Array 60 | NativeOperator 61 | FuncType 62 | Type 63 | ); 64 | 65 | pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { 66 | visitor.visit_mod(&root.r#mod); 67 | } 68 | 69 | pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, _mod: &'a Mod) { 70 | walk_list!(visitor, visit_top_level, &_mod.top_levels); 71 | } 72 | 73 | pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { 74 | match &top_level { 75 | TopLevel::Extern(p) => visitor.visit_prototype(p), 76 | TopLevel::FnSignature(p) => visitor.visit_prototype(p), 77 | TopLevel::Use(u) => visitor.visit_use(u), 78 | TopLevel::Trait(t) => visitor.visit_trait(t), 79 | TopLevel::Impl(i) => visitor.visit_impl(i), 80 | TopLevel::Struct(i) => visitor.visit_struct_decl(i), 81 | TopLevel::Mod(name, m) => { 82 | visitor.visit_identifier(name); 83 | visitor.visit_mod(m); 84 | } 85 | TopLevel::Function(f) => visitor.visit_function_decl(f), 86 | TopLevel::Infix(ident, _) => visitor.visit_operator(ident), 87 | }; 88 | } 89 | 90 | pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { 91 | visitor.visit_identifier(&s.name); 92 | 93 | walk_list!(visitor, visit_prototype, &s.defs); 94 | } 95 | 96 | pub fn walk_trait<'a, V: Visitor<'a>>(visitor: &mut V, t: &'a Trait) { 97 | visitor.visit_type(&t.name); 98 | 99 | walk_list!(visitor, visit_type, &t.types); 100 | 101 | walk_list!(visitor, visit_prototype, &t.defs); 102 | } 103 | 104 | pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { 105 | visitor.visit_type(&i.name); 106 | 107 | walk_list!(visitor, visit_type, &i.types); 108 | 109 | walk_list!(visitor, visit_function_decl, &i.defs); 110 | } 111 | 112 | pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { 113 | visitor.visit_identifier(&prototype.name); 114 | 115 | visitor.visit_func_type(&prototype.signature); 116 | } 117 | 118 | pub fn walk_use<'a, V: Visitor<'a>>(visitor: &mut V, r#use: &'a Use) { 119 | visitor.visit_identifier_path(&r#use.path); 120 | } 121 | 122 | pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { 123 | visitor.visit_identifier(&function_decl.name); 124 | 125 | walk_list!(visitor, visit_identifier, &function_decl.arguments); 126 | 127 | visitor.visit_body(&function_decl.body); 128 | } 129 | 130 | pub fn walk_identifier_path<'a, V: Visitor<'a>>( 131 | visitor: &mut V, 132 | identifier_path: &'a IdentifierPath, 133 | ) { 134 | walk_list!(visitor, visit_identifier, &identifier_path.path); 135 | } 136 | 137 | pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { 138 | visitor.visit_name(&identifier.name); 139 | } 140 | 141 | pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { 142 | walk_list!(visitor, visit_statement, &body.stmts); 143 | } 144 | 145 | pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { 146 | match &statement { 147 | Statement::Expression(expr) => visitor.visit_expression(expr), 148 | Statement::Assign(assign) => visitor.visit_assign(assign), 149 | Statement::If(expr) => visitor.visit_if(expr), 150 | Statement::For(for_loop) => visitor.visit_for(for_loop), 151 | } 152 | } 153 | 154 | pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { 155 | match for_loop { 156 | For::In(for_in) => visitor.visit_for_in(for_in), 157 | For::While(while_loop) => visitor.visit_while(while_loop), 158 | } 159 | } 160 | 161 | pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { 162 | visitor.visit_identifier(&for_in.value); 163 | visitor.visit_expression(&for_in.expr); 164 | visitor.visit_body(&for_in.body); 165 | } 166 | 167 | pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { 168 | visitor.visit_expression(&while_loop.predicat); 169 | visitor.visit_body(&while_loop.body); 170 | } 171 | 172 | pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { 173 | match assign_left { 174 | AssignLeftSide::Identifier(id) => visitor.visit_expression(id), 175 | AssignLeftSide::Indice(expr) => visitor.visit_expression(expr), 176 | AssignLeftSide::Dot(expr) => visitor.visit_expression(expr), 177 | } 178 | } 179 | 180 | pub fn walk_assign<'a, V: Visitor<'a>>(visitor: &mut V, assign: &'a Assign) { 181 | visitor.visit_assign_left_side(&assign.name); 182 | visitor.visit_expression(&assign.value); 183 | } 184 | 185 | pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { 186 | visitor.visit_expression(&r#if.predicat); 187 | visitor.visit_body(&r#if.body); 188 | if let Some(r#else) = &r#if.else_ { 189 | visitor.visit_else(r#else); 190 | } 191 | } 192 | 193 | pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { 194 | match r#else { 195 | Else::If(expr) => visitor.visit_if(expr), 196 | Else::Body(expr) => visitor.visit_body(expr), 197 | } 198 | } 199 | 200 | pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { 201 | match &expr { 202 | Expression::BinopExpr(unary, operator, expr) => { 203 | visitor.visit_unary_expr(unary); 204 | visitor.visit_operator(operator); 205 | visitor.visit_expression(&*expr); 206 | } 207 | Expression::UnaryExpr(unary) => visitor.visit_unary_expr(unary), 208 | Expression::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), 209 | Expression::NativeOperation(op, left, right) => { 210 | visitor.visit_identifier(left); 211 | visitor.visit_identifier(right); 212 | visitor.visit_native_operator(op); 213 | } 214 | Expression::Return(expr) => { 215 | visitor.visit_expression(expr); 216 | } 217 | } 218 | } 219 | 220 | pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { 221 | visitor.visit_identifier(&s.name); 222 | 223 | walk_map!(visitor, visit_expression, &s.defs); 224 | } 225 | 226 | pub fn walk_unary_expr<'a, V: Visitor<'a>>(visitor: &mut V, unary: &'a UnaryExpr) { 227 | match unary { 228 | UnaryExpr::PrimaryExpr(primary) => visitor.visit_primary_expr(primary), 229 | UnaryExpr::UnaryExpr(op, unary) => { 230 | visitor.visit_operator(op); 231 | visitor.visit_unary_expr(&*unary); 232 | } 233 | } 234 | } 235 | 236 | pub fn walk_primary_expr<'a, V: Visitor<'a>>(visitor: &mut V, primary: &'a PrimaryExpr) { 237 | visitor.visit_operand(&primary.op); 238 | 239 | if let Some(secondaries) = &primary.secondaries { 240 | walk_list!(visitor, visit_secondary_expr, secondaries); 241 | } 242 | } 243 | 244 | pub fn walk_secondary_expr<'a, V: Visitor<'a>>(visitor: &mut V, secondary: &'a SecondaryExpr) { 245 | match secondary { 246 | SecondaryExpr::Arguments(args) => { 247 | walk_list!(visitor, visit_argument, args); 248 | } 249 | SecondaryExpr::Indice(expr) => { 250 | visitor.visit_expression(expr); 251 | } 252 | SecondaryExpr::Dot(expr) => { 253 | visitor.visit_identifier(expr); 254 | } 255 | } 256 | } 257 | 258 | pub fn walk_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a Operator) { 259 | visitor.visit_identifier(&operator.0) 260 | } 261 | 262 | pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { 263 | match &operand { 264 | Operand::Literal(l) => visitor.visit_literal(l), 265 | Operand::Identifier(i) => visitor.visit_identifier_path(i), 266 | Operand::Expression(e) => visitor.visit_expression(&*e), 267 | } 268 | } 269 | 270 | pub fn walk_argument<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a Argument) { 271 | visitor.visit_unary_expr(&argument.arg); 272 | } 273 | 274 | pub fn walk_literal<'a, V: Visitor<'a>>(visitor: &mut V, literal: &'a Literal) { 275 | match &literal.kind { 276 | LiteralKind::Number(n) => visitor.visit_primitive(n), 277 | LiteralKind::Float(f) => visitor.visit_primitive(f), 278 | LiteralKind::String(s) => visitor.visit_primitive(s), 279 | LiteralKind::Bool(b) => visitor.visit_primitive(b), 280 | LiteralKind::Array(arr) => visitor.visit_array(arr), 281 | LiteralKind::Char(c) => visitor.visit_primitive(c), 282 | } 283 | } 284 | 285 | pub fn walk_array<'a, V: Visitor<'a>>(visitor: &mut V, arr: &'a Array) { 286 | walk_list!(visitor, visit_expression, &arr.values); 287 | } 288 | 289 | pub fn walk_native_operator<'a, V: Visitor<'a>>(_visitor: &mut V, _operator: &'a NativeOperator) { 290 | // Nothing to do 291 | } 292 | 293 | pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { 294 | walk_list!(visitor, visit_type, &signature.arguments); 295 | 296 | visitor.visit_type(&signature.ret); 297 | } 298 | 299 | pub fn walk_type<'a, V: Visitor<'a>>(_visitor: &mut V, _t: &'a Type) { 300 | // Nothing to do 301 | } 302 | -------------------------------------------------------------------------------- /src/lib/ast/visit_mut.rs: -------------------------------------------------------------------------------- 1 | use paste::paste; 2 | 3 | use crate::ast::tree::*; 4 | use crate::ty::*; 5 | 6 | macro_rules! generate_visitor_mut_trait { 7 | ($( 8 | $name:ty 9 | )+) => { 10 | pub trait VisitorMut<'a>: Sized { 11 | fn visit_name(&mut self, _name: &mut String) {} 12 | 13 | fn visit_primitive(&mut self, _val: T) 14 | where 15 | T: std::fmt::Debug, 16 | {} 17 | 18 | paste! { 19 | $( 20 | fn [](&mut self, node: &'a mut $name) { 21 | [](self, node); 22 | } 23 | )+ 24 | } 25 | } 26 | }; 27 | } 28 | 29 | generate_visitor_mut_trait!( 30 | Root 31 | Mod 32 | TopLevel 33 | Assign 34 | AssignLeftSide 35 | Prototype 36 | Use 37 | Trait 38 | Impl 39 | FunctionDecl 40 | StructDecl 41 | Identifier 42 | IdentifierPath 43 | Body 44 | Statement 45 | For 46 | ForIn 47 | While 48 | Expression 49 | If 50 | Else 51 | UnaryExpr 52 | Operator 53 | PrimaryExpr 54 | SecondaryExpr 55 | Operand 56 | Argument 57 | Literal 58 | StructCtor 59 | Array 60 | NativeOperator 61 | FuncType 62 | Type 63 | ); 64 | 65 | pub fn walk_root<'a, V: VisitorMut<'a>>(visitor: &mut V, root: &'a mut Root) { 66 | visitor.visit_mod(&mut root.r#mod); 67 | } 68 | 69 | pub fn walk_mod<'a, V: VisitorMut<'a>>(visitor: &mut V, _mod: &'a mut Mod) { 70 | walk_list!(visitor, visit_top_level, &mut _mod.top_levels); 71 | } 72 | 73 | pub fn walk_top_level<'a, V: VisitorMut<'a>>(visitor: &mut V, top_level: &'a mut TopLevel) { 74 | match top_level { 75 | TopLevel::Extern(p) => visitor.visit_prototype(p), 76 | TopLevel::FnSignature(p) => visitor.visit_prototype(p), 77 | TopLevel::Use(u) => visitor.visit_use(u), 78 | TopLevel::Trait(t) => visitor.visit_trait(t), 79 | TopLevel::Impl(i) => visitor.visit_impl(i), 80 | TopLevel::Struct(i) => visitor.visit_struct_decl(i), 81 | TopLevel::Mod(name, m) => { 82 | visitor.visit_identifier(name); 83 | visitor.visit_mod(m); 84 | } 85 | TopLevel::Function(f) => visitor.visit_function_decl(f), 86 | TopLevel::Infix(ident, _) => visitor.visit_operator(ident), 87 | }; 88 | } 89 | 90 | pub fn walk_struct_decl<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructDecl) { 91 | visitor.visit_identifier(&mut s.name); 92 | 93 | walk_list!(visitor, visit_prototype, &mut s.defs); 94 | } 95 | 96 | pub fn walk_trait<'a, V: VisitorMut<'a>>(visitor: &mut V, t: &'a mut Trait) { 97 | visitor.visit_type(&mut t.name); 98 | 99 | walk_list!(visitor, visit_type, &mut t.types); 100 | 101 | walk_list!(visitor, visit_prototype, &mut t.defs); 102 | } 103 | 104 | pub fn walk_impl<'a, V: VisitorMut<'a>>(visitor: &mut V, i: &'a mut Impl) { 105 | visitor.visit_type(&mut i.name); 106 | 107 | walk_list!(visitor, visit_type, &mut i.types); 108 | 109 | walk_list!(visitor, visit_function_decl, &mut i.defs); 110 | } 111 | 112 | pub fn walk_prototype<'a, V: VisitorMut<'a>>(visitor: &mut V, prototype: &'a mut Prototype) { 113 | visitor.visit_identifier(&mut prototype.name); 114 | 115 | visitor.visit_func_type(&mut prototype.signature); 116 | } 117 | 118 | pub fn walk_use<'a, V: VisitorMut<'a>>(visitor: &mut V, r#use: &'a mut Use) { 119 | visitor.visit_identifier_path(&mut r#use.path); 120 | } 121 | 122 | pub fn walk_function_decl<'a, V: VisitorMut<'a>>( 123 | visitor: &mut V, 124 | function_decl: &'a mut FunctionDecl, 125 | ) { 126 | visitor.visit_identifier(&mut function_decl.name); 127 | 128 | walk_list!(visitor, visit_identifier, &mut function_decl.arguments); 129 | 130 | visitor.visit_body(&mut function_decl.body); 131 | } 132 | 133 | pub fn walk_identifier_path<'a, V: VisitorMut<'a>>( 134 | visitor: &mut V, 135 | identifier_path: &'a mut IdentifierPath, 136 | ) { 137 | walk_list!(visitor, visit_identifier, &mut identifier_path.path); 138 | } 139 | 140 | pub fn walk_identifier<'a, V: VisitorMut<'a>>(visitor: &mut V, identifier: &'a mut Identifier) { 141 | visitor.visit_name(&mut identifier.name); 142 | } 143 | 144 | pub fn walk_body<'a, V: VisitorMut<'a>>(visitor: &mut V, body: &'a mut Body) { 145 | walk_list!(visitor, visit_statement, &mut body.stmts); 146 | } 147 | 148 | pub fn walk_statement<'a, V: VisitorMut<'a>>(visitor: &mut V, statement: &'a mut Statement) { 149 | match statement { 150 | Statement::Expression(expr) => visitor.visit_expression(expr), 151 | Statement::Assign(assign) => visitor.visit_assign(assign), 152 | Statement::If(expr) => visitor.visit_if(expr), 153 | Statement::For(for_loop) => visitor.visit_for(for_loop), 154 | } 155 | } 156 | 157 | pub fn walk_for<'a, V: VisitorMut<'a>>(visitor: &mut V, for_loop: &'a mut For) { 158 | match for_loop { 159 | For::In(for_in) => visitor.visit_for_in(for_in), 160 | For::While(while_loop) => visitor.visit_while(while_loop), 161 | } 162 | } 163 | 164 | pub fn walk_for_in<'a, V: VisitorMut<'a>>(visitor: &mut V, for_in: &'a mut ForIn) { 165 | visitor.visit_identifier(&mut for_in.value); 166 | visitor.visit_expression(&mut for_in.expr); 167 | visitor.visit_body(&mut for_in.body); 168 | } 169 | 170 | pub fn walk_while<'a, V: VisitorMut<'a>>(visitor: &mut V, while_loop: &'a mut While) { 171 | visitor.visit_expression(&mut while_loop.predicat); 172 | visitor.visit_body(&mut while_loop.body); 173 | } 174 | 175 | pub fn walk_assign_left_side<'a, V: VisitorMut<'a>>( 176 | visitor: &mut V, 177 | assign_left: &'a mut AssignLeftSide, 178 | ) { 179 | match assign_left { 180 | AssignLeftSide::Identifier(id) => visitor.visit_expression(id), 181 | AssignLeftSide::Indice(expr) => visitor.visit_expression(expr), 182 | AssignLeftSide::Dot(expr) => visitor.visit_expression(expr), 183 | } 184 | } 185 | 186 | pub fn walk_assign<'a, V: VisitorMut<'a>>(visitor: &mut V, assign: &'a mut Assign) { 187 | visitor.visit_assign_left_side(&mut assign.name); 188 | visitor.visit_expression(&mut assign.value); 189 | } 190 | 191 | pub fn walk_if<'a, V: VisitorMut<'a>>(visitor: &mut V, r#if: &'a mut If) { 192 | visitor.visit_expression(&mut r#if.predicat); 193 | visitor.visit_body(&mut r#if.body); 194 | if let Some(r#else) = &mut r#if.else_ { 195 | visitor.visit_else(r#else); 196 | } 197 | } 198 | 199 | pub fn walk_else<'a, V: VisitorMut<'a>>(visitor: &mut V, r#else: &'a mut Else) { 200 | match r#else { 201 | Else::If(expr) => visitor.visit_if(expr), 202 | Else::Body(expr) => visitor.visit_body(expr), 203 | } 204 | } 205 | 206 | pub fn walk_expression<'a, V: VisitorMut<'a>>(visitor: &mut V, expr: &'a mut Expression) { 207 | match expr { 208 | Expression::BinopExpr(unary, operator, expr) => { 209 | visitor.visit_unary_expr(unary); 210 | visitor.visit_operator(operator); 211 | visitor.visit_expression(&mut *expr); 212 | } 213 | Expression::UnaryExpr(unary) => visitor.visit_unary_expr(unary), 214 | Expression::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), 215 | Expression::NativeOperation(op, left, right) => { 216 | visitor.visit_identifier(left); 217 | visitor.visit_identifier(right); 218 | visitor.visit_native_operator(op); 219 | } 220 | Expression::Return(expr) => { 221 | visitor.visit_expression(expr); 222 | } 223 | } 224 | } 225 | 226 | pub fn walk_struct_ctor<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructCtor) { 227 | visitor.visit_identifier(&mut s.name); 228 | 229 | walk_map!(visitor, visit_expression, &mut s.defs); 230 | } 231 | 232 | pub fn walk_unary_expr<'a, V: VisitorMut<'a>>(visitor: &mut V, unary: &'a mut UnaryExpr) { 233 | match unary { 234 | UnaryExpr::PrimaryExpr(primary) => visitor.visit_primary_expr(primary), 235 | UnaryExpr::UnaryExpr(op, unary) => { 236 | visitor.visit_operator(op); 237 | visitor.visit_unary_expr(&mut *unary); 238 | } 239 | } 240 | } 241 | 242 | pub fn walk_primary_expr<'a, V: VisitorMut<'a>>(visitor: &mut V, primary: &'a mut PrimaryExpr) { 243 | visitor.visit_operand(&mut primary.op); 244 | 245 | if let Some(secondaries) = &mut primary.secondaries { 246 | walk_list!(visitor, visit_secondary_expr, secondaries); 247 | } 248 | } 249 | 250 | pub fn walk_secondary_expr<'a, V: VisitorMut<'a>>( 251 | visitor: &mut V, 252 | secondary: &'a mut SecondaryExpr, 253 | ) { 254 | match secondary { 255 | SecondaryExpr::Arguments(args) => { 256 | walk_list!(visitor, visit_argument, args); 257 | } 258 | SecondaryExpr::Indice(expr) => { 259 | visitor.visit_expression(expr); 260 | } 261 | SecondaryExpr::Dot(expr) => { 262 | visitor.visit_identifier(expr); 263 | } 264 | } 265 | } 266 | 267 | pub fn walk_operator<'a, V: VisitorMut<'a>>(visitor: &mut V, operator: &'a mut Operator) { 268 | visitor.visit_identifier(&mut operator.0) 269 | } 270 | 271 | pub fn walk_operand<'a, V: VisitorMut<'a>>(visitor: &mut V, operand: &'a mut Operand) { 272 | match operand { 273 | Operand::Literal(l) => visitor.visit_literal(l), 274 | Operand::Identifier(i) => visitor.visit_identifier_path(i), 275 | Operand::Expression(e) => visitor.visit_expression(&mut *e), 276 | } 277 | } 278 | 279 | pub fn walk_argument<'a, V: VisitorMut<'a>>(visitor: &mut V, argument: &'a mut Argument) { 280 | visitor.visit_unary_expr(&mut argument.arg); 281 | } 282 | 283 | pub fn walk_literal<'a, V: VisitorMut<'a>>(visitor: &mut V, literal: &'a mut Literal) { 284 | match &mut literal.kind { 285 | LiteralKind::Number(n) => visitor.visit_primitive(n), 286 | LiteralKind::Float(f) => visitor.visit_primitive(f), 287 | LiteralKind::String(s) => visitor.visit_primitive(s), 288 | LiteralKind::Bool(b) => visitor.visit_primitive(b), 289 | LiteralKind::Array(arr) => visitor.visit_array(arr), 290 | LiteralKind::Char(c) => visitor.visit_primitive(c), 291 | } 292 | } 293 | 294 | pub fn walk_array<'a, V: VisitorMut<'a>>(visitor: &mut V, arr: &'a mut Array) { 295 | walk_list!(visitor, visit_expression, &mut arr.values); 296 | } 297 | 298 | pub fn walk_native_operator<'a, V: VisitorMut<'a>>( 299 | _visitor: &mut V, 300 | _operator: &'a mut NativeOperator, 301 | ) { 302 | // Nothing to do 303 | } 304 | 305 | pub fn walk_func_type<'a, V: VisitorMut<'a>>(visitor: &mut V, signature: &'a mut FuncType) { 306 | walk_list!(visitor, visit_type, &mut signature.arguments); 307 | 308 | visitor.visit_type(&mut signature.ret); 309 | } 310 | 311 | pub fn walk_type<'a, V: VisitorMut<'a>>(_visitor: &mut V, _t: &'a mut Type) { 312 | // Nothing to do 313 | } 314 | -------------------------------------------------------------------------------- /src/lib/ast_lowering/hir_map.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::{ 4 | ast::NodeId, 5 | hir::{FnBodyId, HirId}, 6 | }; 7 | 8 | #[derive(Clone, Debug, Serialize, Deserialize)] 9 | pub struct HirMap { 10 | map: HashMap, 11 | rev_map: HashMap, 12 | pub hir_id_next: u64, 13 | pub body_id_next: u64, 14 | } 15 | 16 | impl Default for HirMap { 17 | fn default() -> Self { 18 | Self { 19 | hir_id_next: 1, 20 | body_id_next: 1, 21 | map: HashMap::new(), 22 | rev_map: HashMap::new(), 23 | } 24 | } 25 | } 26 | 27 | impl HirMap { 28 | pub fn new() -> Self { 29 | Self::default() 30 | } 31 | 32 | pub fn next_hir_id(&mut self, node_id: NodeId) -> HirId { 33 | let hir_id = HirId(self.hir_id_next); 34 | 35 | self.hir_id_next += 1; 36 | 37 | self.add_hir_mapping(hir_id.clone(), node_id); 38 | 39 | hir_id 40 | } 41 | 42 | pub fn next_body_id(&mut self) -> FnBodyId { 43 | let body_id = FnBodyId(self.body_id_next); 44 | 45 | self.body_id_next += 1; 46 | 47 | body_id 48 | } 49 | 50 | pub fn get_hir_id(&self, node_id: NodeId) -> Option { 51 | self.rev_map.get(&node_id).cloned() 52 | } 53 | 54 | pub fn get_node_id(&self, hir_id: &HirId) -> Option { 55 | self.map.get(hir_id).cloned() 56 | } 57 | 58 | pub fn add_hir_mapping(&mut self, hir_id: HirId, node_id: NodeId) { 59 | self.map.insert(hir_id.clone(), node_id); 60 | 61 | self.rev_map.insert(node_id, hir_id); 62 | } 63 | 64 | pub fn duplicate_hir_mapping(&mut self, hir_id: HirId) -> Option { 65 | let node_id = self.get_node_id(&hir_id)?; 66 | 67 | let new_id = self.next_hir_id(node_id); 68 | 69 | self.add_hir_mapping(new_id.clone(), node_id); 70 | 71 | Some(new_id) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/lib/ast_lowering/infix_desugar.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::ast::tree::{Expression, Identifier, Operand, UnaryExpr}; 4 | 5 | #[derive(Debug)] 6 | pub enum ExprOrIdentifier { 7 | Expr(UnaryExpr), 8 | Identifier(Identifier), 9 | } 10 | 11 | #[derive(Debug)] 12 | pub struct InfixDesugar { 13 | pub opstack: Vec, 14 | pub output: Vec, 15 | pub operators_list: HashMap, 16 | } 17 | 18 | impl InfixDesugar { 19 | pub fn new(operators_list: HashMap) -> Self { 20 | InfixDesugar { 21 | opstack: vec![], 22 | output: vec![], 23 | operators_list, 24 | } 25 | } 26 | 27 | pub fn desugar(&mut self, expr: &Expression) -> Expression { 28 | self.populate_rec(expr); 29 | 30 | self.pop_higher_operators(0); 31 | 32 | self.generate_calls() 33 | } 34 | 35 | pub fn generate_calls(&self) -> Expression { 36 | let mut stack = vec![]; 37 | for item in &self.output { 38 | match item { 39 | ExprOrIdentifier::Expr(expr) => stack.push(expr.clone()), 40 | ExprOrIdentifier::Identifier(id) => { 41 | let right = stack.pop().unwrap(); 42 | let left = stack.pop().unwrap(); 43 | 44 | stack.push(UnaryExpr::create_2_args_func_call( 45 | Operand::from_identifier(id.clone()), 46 | left.clone(), 47 | right.clone(), 48 | )); 49 | } 50 | } 51 | } 52 | 53 | Expression::new_unary(stack.pop().unwrap()) 54 | } 55 | 56 | pub fn populate_rec(&mut self, expr: &Expression) { 57 | match &expr { 58 | Expression::BinopExpr(unary, op, expr2) => { 59 | self.output.push(ExprOrIdentifier::Expr(unary.clone())); 60 | 61 | self.pop_higher_operators( 62 | *self.operators_list.get(&op.0.name.to_string()).unwrap(), 63 | ); 64 | 65 | self.opstack.push(op.0.clone()); 66 | 67 | self.desugar(expr2); 68 | } 69 | Expression::UnaryExpr(unary) => self.output.push(ExprOrIdentifier::Expr(unary.clone())), 70 | _ => unimplemented!(), 71 | } 72 | } 73 | 74 | pub fn pop_higher_operators(&mut self, precedence: u8) { 75 | for op in self.opstack.clone().iter().rev() { 76 | let item_precedence = self.operators_list.get(&op.name.to_string()).unwrap(); 77 | 78 | if precedence <= *item_precedence { 79 | self.opstack.pop(); 80 | 81 | self.output.push(ExprOrIdentifier::Identifier(op.clone())); 82 | } else { 83 | break; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/lib/ast_lowering/loop_desugar.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::ast::{Expression, ExpressionKind, Identifier, Operand, Statement, UnaryExpr}; 4 | 5 | pub struct Loop { 6 | pre_loop: Vec, 7 | predicat: Expression, 8 | pre_body: Vec, 9 | body: Body, 10 | post_body: Vec, 11 | } 12 | 13 | #[derive(Debug)] 14 | pub struct LoopDesugar {} 15 | 16 | impl LoopDesugar { 17 | pub fn new() -> Self { 18 | LoopDesugar {} 19 | } 20 | 21 | pub fn desugar(&mut self, for_loop: &For) -> Loop { 22 | match for_loop { 23 | For::In(for_in) => self.desugar_for_in(&for_in), 24 | For::While(while_loop) => self.desugar_while(&while_loop), 25 | } 26 | } 27 | 28 | // for item in arr 29 | // do item 30 | // 31 | // --- becomes 32 | // 33 | // let i = 0 34 | // let arr_len = ~Len arr 35 | // for i < arr_len 36 | // let item = arr[i] // pre_body 37 | // do item 38 | // i = i + 1 // post_body 39 | 40 | 41 | 42 | fn desugar_for_in(&mut self, for_in: &ForIn) -> Loop { 43 | let i_var = Statement::new_assign() 44 | 45 | Loop { 46 | pre_loop: vec![], 47 | predicat: (), 48 | pre_body: vec![], 49 | body: for_in.body.clone(), 50 | post_body: vec![], 51 | } 52 | } 53 | 54 | fn desugar_while(&mut self, while_loop: &While) -> Loop { 55 | Loop { 56 | pre_loop: vec![], 57 | predicat: while_loop.predicat.clone(), 58 | pre_body: vec![], 59 | body: while_loop.body.clone(), 60 | post_body: vec![], 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/lib/ast_lowering/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{ast::tree::Root, hir}; 2 | 3 | mod ast_lowering_context; 4 | mod hir_map; 5 | mod infix_desugar; 6 | 7 | use ast_lowering_context::AstLoweringContext; 8 | pub use hir_map::*; 9 | pub use infix_desugar::*; 10 | 11 | pub fn lower_crate(root: &Root) -> hir::Root { 12 | AstLoweringContext::new(root.operators_list.clone()).lower_root(root) 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/codegen/mod.rs: -------------------------------------------------------------------------------- 1 | mod codegen_context; 2 | 3 | use codegen_context::*; 4 | use inkwell::context::Context; 5 | 6 | use crate::{diagnostics::Diagnostic, hir::Root, Config}; 7 | 8 | pub fn generate(config: &Config, hir: Root) -> Result<(), Diagnostic> { 9 | let context = Context::create(); 10 | let builder = context.create_builder(); 11 | 12 | let mut codegen_ctx = CodegenContext::new(&context, &hir); 13 | 14 | if codegen_ctx.lower_hir(&hir, &builder).is_err() { 15 | // FIXME: have a movable `Diagnostics` 16 | // codegen_ctx.parsing_ctx.return_if_error()?; 17 | panic!("GEN ERROR"); 18 | } 19 | 20 | match codegen_ctx.module.verify() { 21 | Ok(_) => (), 22 | Err(e) => { 23 | codegen_ctx.module.print_to_stderr(); 24 | 25 | println!("Error: Bug in the generated IR:\n\n{}", e.to_string()); 26 | 27 | return Err(Diagnostic::new_empty()); 28 | } 29 | } 30 | 31 | if !config.no_optimize { 32 | codegen_ctx.optimize(); 33 | } 34 | 35 | if config.show_ir { 36 | codegen_ctx.module.print_to_stderr(); 37 | } 38 | 39 | if !codegen_ctx 40 | .module 41 | .write_bitcode_to_path(&config.build_folder.join("out.bc")) 42 | { 43 | panic!("CANNOT IR WRITE TO PATH"); 44 | } 45 | 46 | Ok(()) 47 | } 48 | -------------------------------------------------------------------------------- /src/lib/diagnostics/diagnostics_list.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, path::PathBuf}; 2 | 3 | use nom::error::VerboseError; 4 | 5 | use crate::parser::{Parser, SourceFile}; 6 | 7 | use super::Diagnostic; 8 | 9 | #[derive(Debug, Clone)] 10 | pub enum DiagnosticType { 11 | Warning, 12 | Error, 13 | } 14 | 15 | impl Default for DiagnosticType { 16 | fn default() -> Self { 17 | DiagnosticType::Error 18 | } 19 | } 20 | 21 | #[derive(Debug, Default, Clone)] 22 | pub struct Diagnostics { 23 | pub list: Vec, 24 | pub list_types: Vec, 25 | pub must_stop: bool, 26 | } 27 | 28 | impl Diagnostics { 29 | pub fn push_error(&mut self, diag: Diagnostic) { 30 | self.must_stop = true; 31 | 32 | trace!("Push error diagnostic: {:#?}", diag); 33 | 34 | self.list.push(diag); 35 | self.list_types.push(DiagnosticType::Error); 36 | } 37 | 38 | pub fn push_warning(&mut self, diag: Diagnostic) { 39 | trace!("Push warning: {:#?}", diag); 40 | 41 | self.list.push(diag); 42 | self.list_types.push(DiagnosticType::Warning); 43 | } 44 | 45 | pub fn print(&self, files: &HashMap) { 46 | for (i, diag) in self.list.iter().enumerate() { 47 | let input = match files.get(&diag.span.file_path) { 48 | Some(input) => input, 49 | None => { 50 | println!("DIAG FILE {:#?}", diag.span.file_path); 51 | warn!("Diagnostic has been silenced because the file is not found"); 52 | 53 | continue; 54 | } 55 | }; 56 | 57 | diag.print(input, self.list_types.get(i).unwrap()); 58 | } 59 | } 60 | 61 | pub fn append(&mut self, other: Self) { 62 | self.list.extend(other.list); 63 | self.list_types.extend(other.list_types); 64 | self.must_stop = self.must_stop || other.must_stop; 65 | } 66 | } 67 | 68 | impl<'a> From>> for Diagnostics { 69 | fn from(err: VerboseError>) -> Self { 70 | let mut diags = err 71 | .errors 72 | .clone() 73 | .into_iter() 74 | .take(1) 75 | .map(Diagnostic::from) 76 | .collect::>(); 77 | 78 | let diags2 = err 79 | .errors 80 | .into_iter() 81 | .take(1) 82 | .map(|(input, _kind)| input.extra.diagnostics().list) 83 | .flatten() 84 | .collect::>(); 85 | 86 | diags.extend(diags2); 87 | 88 | let mut list = Diagnostics::default(); 89 | 90 | for diag in diags { 91 | list.push_error(diag); 92 | } 93 | 94 | list 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/lib/diagnostics/mod.rs: -------------------------------------------------------------------------------- 1 | mod diagnostic; 2 | mod diagnostics_list; 3 | 4 | pub use diagnostic::*; 5 | pub use diagnostics_list::*; 6 | -------------------------------------------------------------------------------- /src/lib/helpers/class_name.rs: -------------------------------------------------------------------------------- 1 | pub trait HasName { 2 | fn get_name(&self) -> String; 3 | } 4 | 5 | macro_rules! generate_has_name { 6 | ($class:tt) => { 7 | impl HasName for $class { 8 | fn get_name(&self) -> String { 9 | self.name.clone().to_string() 10 | } 11 | } 12 | }; 13 | } 14 | 15 | pub trait ClassName { 16 | fn class_name_self(&self) -> String; 17 | } 18 | 19 | impl ClassName for T 20 | where 21 | T: core::fmt::Debug, 22 | { 23 | fn class_name_self(&self) -> String { 24 | let name = format!("{:?}", self); 25 | 26 | name.chars().take_while(|c| c.is_alphanumeric()).collect() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/lib/helpers/config.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, path::PathBuf}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub enum PackageType { 5 | Lib, 6 | Bin, 7 | } 8 | 9 | impl Default for PackageType { 10 | fn default() -> Self { 11 | Self::Bin 12 | } 13 | } 14 | 15 | #[derive(Debug, Clone, Default)] 16 | pub struct ProjectConfig { 17 | pub name: String, 18 | pub base_path: PathBuf, 19 | pub package_type: PackageType, 20 | pub externs: HashMap, // Packages name and MetaData path 21 | pub entry_point: PathBuf, 22 | } 23 | 24 | #[derive(Debug, Clone, Default)] 25 | pub struct Config { 26 | pub project_config: ProjectConfig, 27 | pub show_ast: bool, 28 | pub show_hir: bool, 29 | pub show_thir: bool, 30 | pub show_ir: bool, 31 | pub verbose: bool, 32 | pub quiet: bool, 33 | pub build_folder: PathBuf, 34 | pub no_optimize: bool, 35 | pub std: bool, 36 | } 37 | -------------------------------------------------------------------------------- /src/lib/helpers/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod walk_helpers; 3 | #[macro_use] 4 | pub mod class_name; 5 | pub mod config; 6 | pub mod scopes; 7 | 8 | pub mod test_utils; 9 | 10 | pub use class_name::*; 11 | pub use walk_helpers::*; 12 | -------------------------------------------------------------------------------- /src/lib/helpers/scopes.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::hash::Hash; 3 | 4 | pub type Scope = HashMap; 5 | 6 | #[derive(Clone, Debug)] 7 | pub struct Scopes 8 | where 9 | K: Default + Hash + Eq + Clone, 10 | T: Clone, 11 | { 12 | pub scopes: Vec>, 13 | } 14 | 15 | impl Default for Scopes 16 | where 17 | K: Default + Hash + Eq + Clone, 18 | T: Clone, 19 | { 20 | fn default() -> Self { 21 | Self::new() 22 | } 23 | } 24 | 25 | impl Scopes 26 | where 27 | K: Default + Hash + Eq + Clone, 28 | T: Clone, 29 | { 30 | pub fn new() -> Scopes { 31 | Scopes { 32 | scopes: vec![Scope::new()], 33 | } 34 | } 35 | 36 | pub fn get(&self, s: K) -> Option { 37 | for scope in self.scopes.iter().rev() { 38 | if let Some(res) = scope.get(&s) { 39 | return Some(res.clone()); 40 | } 41 | } 42 | 43 | None 44 | } 45 | 46 | pub fn add(&mut self, s: K, val: T) { 47 | self.scopes.last_mut().unwrap().insert(s, val); 48 | } 49 | 50 | pub fn extend(&mut self, other: &Scope) { 51 | self.scopes.last_mut().unwrap().extend(other.clone()) 52 | } 53 | 54 | pub fn push(&mut self) { 55 | self.scopes.push(Scope::new()) 56 | } 57 | 58 | pub fn pop(&mut self) { 59 | self.scopes.pop(); 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod tests { 65 | use super::*; 66 | 67 | #[test] 68 | fn basic_scope() { 69 | let mut scopes = Scopes::default(); 70 | 71 | scopes.add("a", 1); 72 | scopes.add("b", 2); 73 | 74 | assert_eq!(scopes.get("a").unwrap(), 1); 75 | assert_eq!(scopes.get("b").unwrap(), 2); 76 | 77 | scopes.push(); 78 | 79 | scopes.add("b", 4); 80 | 81 | assert_eq!(scopes.get("a").unwrap(), 1); 82 | assert_eq!(scopes.get("b").unwrap(), 4); 83 | 84 | scopes.add("a", 3); 85 | 86 | assert_eq!(scopes.get("a").unwrap(), 3); 87 | assert_eq!(scopes.get("b").unwrap(), 4); 88 | 89 | scopes.pop(); 90 | 91 | assert_eq!(scopes.get("a").unwrap(), 1); 92 | assert_eq!(scopes.get("b").unwrap(), 2); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/lib/helpers/test_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{parser::SourceFile, Config}; 2 | use std::{ 3 | fs, 4 | path::{Path, PathBuf}, 5 | process::Command, 6 | }; 7 | 8 | fn build(input: String, config: Config) -> bool { 9 | let file = SourceFile { 10 | file_path: PathBuf::from("src/lib").join(&config.project_config.entry_point), 11 | mod_path: PathBuf::from("main"), 12 | content: input + "\n", 13 | }; 14 | 15 | if let Err(_e) = crate::compile_str(&file, &config) { 16 | return false; 17 | } 18 | 19 | let clang_cmd = Command::new("clang") 20 | .args(&[ 21 | config.build_folder.join("out.bc").to_str().unwrap(), 22 | "-o", 23 | config.build_folder.join("a.out").to_str().unwrap(), 24 | ]) 25 | .output() 26 | .expect("failed to compile to ir"); 27 | 28 | match clang_cmd.status.code() { 29 | Some(code) => { 30 | if code != 0 { 31 | println!( 32 | "BUG: Cannot compile: \n{}", 33 | String::from_utf8(clang_cmd.stderr).unwrap() 34 | ); 35 | 36 | return false; 37 | } 38 | } 39 | None => println!( 40 | "\nError running: \n{}", 41 | String::from_utf8(clang_cmd.stderr).unwrap() 42 | ), 43 | } 44 | 45 | true 46 | } 47 | 48 | pub fn run(path: &str, input: String, config: Config) -> (i64, String) { 49 | let path = Path::new("src/lib/").join(path); 50 | 51 | let build_path = path.parent().unwrap().join("build"); 52 | 53 | let mut config = config; 54 | config.build_folder = build_path; 55 | 56 | fs::create_dir_all(config.build_folder.clone()).unwrap(); 57 | 58 | if !build(input, config.clone()) { 59 | return (-1, String::new()); 60 | } 61 | 62 | let cmd = Command::new(config.build_folder.join("a.out").to_str().unwrap()) 63 | .output() 64 | .expect("failed to execute BINARY"); 65 | 66 | let stdout = String::from_utf8(cmd.stderr).unwrap(); 67 | 68 | fs::remove_dir_all(config.build_folder).unwrap(); 69 | 70 | match cmd.status.code() { 71 | Some(code) => (code.into(), stdout), 72 | None => (-1, stdout), 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/lib/helpers/walk_helpers.rs: -------------------------------------------------------------------------------- 1 | macro_rules! walk_list { 2 | ($visitor: expr, $method: ident, $list: expr) => { 3 | for elem in $list { 4 | $visitor.$method(elem) 5 | } 6 | }; 7 | 8 | ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => { 9 | for elem in $list { 10 | $visitor.$method(elem, $($extra_args,)*) 11 | } 12 | } 13 | } 14 | 15 | macro_rules! walk_map { 16 | ($visitor: expr, $method: ident, $list: expr) => { 17 | for (_, elem) in $list { 18 | $visitor.$method(elem) 19 | } 20 | }; 21 | 22 | ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => { 23 | for (_, elem) in $list { 24 | $visitor.$method(elem, $($extra_args,)*) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/hir/arena.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use paste::paste; 4 | 5 | use crate::hir::visit::*; 6 | use crate::hir::*; 7 | 8 | // This is not really an Arena, but more a HirNode Collector 9 | // The name is confusing on its properties and usage, 10 | // as one would expect the arena to own every hir nodes from their creation, 11 | // and give (mut) references when needed. 12 | // Instead, this "Arena" is constructed from a clone of every nodes in the HIR, 13 | // (as you can see bellow in the HirNodeCollector) and serves only as a global 14 | // accessor to the graph's structure and immutable properties. 15 | // Every effective mutable work is done on the hir::Root instead. 16 | #[derive(Debug, Default)] 17 | pub struct Arena(BTreeMap); 18 | 19 | impl Arena { 20 | pub fn new() -> Self { 21 | Self(BTreeMap::new()) 22 | } 23 | } 24 | 25 | // FIXME: Code smell 26 | impl std::ops::Deref for Arena { 27 | type Target = BTreeMap; 28 | 29 | fn deref(&self) -> &Self::Target { 30 | &self.0 31 | } 32 | } 33 | 34 | // FIXME: Code smell 35 | impl std::ops::DerefMut for Arena { 36 | fn deref_mut(&mut self) -> &mut Self::Target { 37 | &mut self.0 38 | } 39 | } 40 | 41 | #[derive(Debug, Default)] 42 | pub struct HirNodeCollector { 43 | arena: Arena, 44 | } 45 | 46 | impl HirNodeCollector { 47 | pub fn new() -> Self { 48 | Self { 49 | ..Default::default() 50 | } 51 | } 52 | 53 | pub fn take_arena(self) -> Arena { 54 | self.arena 55 | } 56 | 57 | pub fn insert(&mut self, node: &T) 58 | where 59 | T: HasHirId, 60 | T: Clone, 61 | hir_node::HirNode: From, 62 | { 63 | self.arena.insert(node.get_hir_id(), node.clone().into()); 64 | } 65 | } 66 | 67 | macro_rules! generate_hirnode_collector { 68 | ($($expr:ty,)+) => { 69 | impl<'a> Visitor<'a> for HirNodeCollector { 70 | paste! { 71 | $( 72 | fn [](&mut self, node: &'a $expr) { 73 | self.insert(node); 74 | 75 | [](self, node); 76 | } 77 | )+ 78 | } 79 | } 80 | }; 81 | } 82 | 83 | generate_hirnode_collector!( 84 | TopLevel, 85 | Assign, 86 | Prototype, 87 | FunctionDecl, 88 | ArgumentDecl, 89 | IdentifierPath, 90 | Identifier, 91 | FnBody, 92 | Body, 93 | Statement, 94 | Expression, 95 | If, 96 | IfChain, 97 | FunctionCall, 98 | Literal, 99 | NativeOperator, 100 | ); 101 | 102 | pub fn collect_arena(root: &Root) -> Arena { 103 | let mut hir_node_collector = HirNodeCollector::new(); 104 | 105 | hir_node_collector.visit_root(root); 106 | 107 | hir_node_collector.take_arena() 108 | } 109 | -------------------------------------------------------------------------------- /src/lib/hir/has_hir_id.rs: -------------------------------------------------------------------------------- 1 | use crate::hir::*; 2 | use paste::paste; 3 | 4 | pub trait HasHirId { 5 | fn get_hir_id(&self) -> HirId; 6 | } 7 | 8 | macro_rules! impl_direct_get_hir_id_trait { 9 | ($( 10 | $name:ident 11 | )*) => { 12 | $( 13 | impl HasHirId for $name { 14 | fn get_hir_id(&self) -> HirId { 15 | self.hir_id.clone() 16 | } 17 | } 18 | )* 19 | }; 20 | } 21 | 22 | impl_direct_get_hir_id_trait!( 23 | Prototype 24 | FunctionDecl 25 | Identifier 26 | If 27 | FunctionCall 28 | Indice 29 | Dot 30 | Literal 31 | NativeOperator 32 | ); 33 | 34 | macro_rules! impl_indirect_get_hir_id_trait { 35 | ($( 36 | $name:ident 37 | )*) => { 38 | paste! { 39 | $( 40 | impl HasHirId for $name { 41 | fn get_hir_id(&self) -> HirId { 42 | self.get_terminal_hir_id() 43 | } 44 | } 45 | )* 46 | } 47 | }; 48 | } 49 | 50 | impl_indirect_get_hir_id_trait!( 51 | TopLevel 52 | Statement 53 | StructCtor 54 | StructDecl 55 | Assign 56 | AssignLeftSide 57 | ArgumentDecl 58 | IdentifierPath 59 | FnBody 60 | For 61 | ForIn 62 | While 63 | Body 64 | Expression 65 | Array 66 | IfChain 67 | ); 68 | 69 | impl HasHirId for Vec { 70 | fn get_hir_id(&self) -> HirId { 71 | self.last().unwrap().get_hir_id() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/lib/hir/hir_id.rs: -------------------------------------------------------------------------------- 1 | use colored::*; 2 | use paste::paste; 3 | 4 | macro_rules! def_id { 5 | ($name:ident) => { 6 | paste! { 7 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)] 8 | pub struct $name(pub u64); 9 | 10 | impl std::fmt::Display for $name { 11 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 12 | write!( 13 | f, 14 | "{}{}{}{}", 15 | "HirId".yellow(), 16 | "(".green(), 17 | self.0.to_string().blue(), 18 | ")".green(), 19 | ) 20 | } 21 | } 22 | 23 | } 24 | }; 25 | } 26 | 27 | def_id!(HirId); 28 | def_id!(FnBodyId); 29 | -------------------------------------------------------------------------------- /src/lib/hir/hir_node.rs: -------------------------------------------------------------------------------- 1 | use crate::{hir::HasHirId, hir::*}; 2 | 3 | #[derive(Clone, Debug)] 4 | pub enum HirNode { 5 | Mod(Mod), 6 | TopLevel(TopLevel), 7 | Trait(Trait), 8 | Impl(Impl), 9 | Assign(Assign), 10 | Prototype(Prototype), 11 | FunctionDecl(FunctionDecl), 12 | ArgumentDecl(ArgumentDecl), 13 | IdentifierPath(IdentifierPath), 14 | Identifier(Identifier), 15 | FnBody(FnBody), 16 | Body(Body), 17 | Statement(Statement), 18 | Expression(Expression), 19 | If(If), 20 | IfChain(IfChain), 21 | FunctionCall(FunctionCall), 22 | Literal(Literal), 23 | NativeOperator(NativeOperator), 24 | } 25 | 26 | impl<'ar> HasHirId for HirNode { 27 | fn get_hir_id(&self) -> HirId { 28 | match self { 29 | HirNode::Mod(_x) => unimplemented!("Non-sense yet to get a hir_id from a mod"), 30 | HirNode::Assign(x) => x.get_hir_id(), 31 | HirNode::Prototype(x) => x.get_hir_id(), 32 | HirNode::FunctionDecl(x) => x.get_hir_id(), 33 | HirNode::ArgumentDecl(x) => x.get_hir_id(), 34 | HirNode::IdentifierPath(x) => x.get_hir_id(), 35 | HirNode::Identifier(x) => x.get_hir_id(), 36 | HirNode::FnBody(x) => x.get_hir_id(), 37 | HirNode::Body(x) => x.get_hir_id(), 38 | HirNode::Statement(x) => x.get_hir_id(), 39 | HirNode::Expression(x) => x.get_hir_id(), 40 | HirNode::If(x) => x.get_hir_id(), 41 | HirNode::FunctionCall(x) => x.get_hir_id(), 42 | HirNode::Literal(x) => x.get_hir_id(), 43 | HirNode::NativeOperator(x) => x.get_hir_id(), 44 | _ => unimplemented!(), 45 | } 46 | } 47 | } 48 | 49 | macro_rules! generate_hirnode_from { 50 | ($($expr:ident,)+) => { 51 | $( 52 | impl From<$expr> for HirNode { 53 | fn from(expr: $expr) -> HirNode { 54 | HirNode::$expr(expr) 55 | } 56 | } 57 | )+ 58 | }; 59 | } 60 | 61 | generate_hirnode_from!( 62 | Mod, 63 | TopLevel, 64 | Trait, 65 | Impl, 66 | Assign, 67 | Prototype, 68 | FunctionDecl, 69 | ArgumentDecl, 70 | IdentifierPath, 71 | Identifier, 72 | FnBody, 73 | Body, 74 | Statement, 75 | Expression, 76 | If, 77 | IfChain, 78 | FunctionCall, 79 | Literal, 80 | NativeOperator, 81 | ); 82 | -------------------------------------------------------------------------------- /src/lib/hir/hir_printer.rs: -------------------------------------------------------------------------------- 1 | use colored::*; 2 | use paste::paste; 3 | use std::fmt::Debug; 4 | 5 | use crate::helpers::*; 6 | use crate::hir::visit::*; 7 | use crate::hir::HasHirId; 8 | use crate::hir::*; 9 | use crate::ty::Type; 10 | 11 | pub struct HirPrinter<'a> { 12 | hir: &'a Root, 13 | indent: usize, 14 | } 15 | 16 | impl<'a> HirPrinter<'a> { 17 | pub fn new(hir: &'a Root) -> Self { 18 | Self { hir, indent: 0 } 19 | } 20 | 21 | pub fn make_indent_str(&self, t: ColoredString) -> String { 22 | format!( 23 | "{:<3}{}{}", 24 | "", 25 | String::from("| ").repeat(self.indent()).bright_black(), 26 | t 27 | ) 28 | } 29 | 30 | pub fn increment(&mut self) { 31 | self.indent += 1; 32 | } 33 | 34 | pub fn decrement(&mut self) { 35 | self.indent -= 1; 36 | } 37 | 38 | pub fn indent(&self) -> usize { 39 | self.indent 40 | } 41 | 42 | pub fn print(&self, t: T) { 43 | let ty = self 44 | .hir 45 | .node_types 46 | .get(&t.get_hir_id()) 47 | .map_or_else(|| String::from("None"), |t| format!("{:?}", t)); 48 | 49 | println!( 50 | "{:<10}{:-<60} {}", 51 | t.get_hir_id(), 52 | self.make_indent_str(t.class_name_self().magenta()), 53 | ty 54 | ); 55 | } 56 | 57 | pub fn print_primitive(&self, t: T) 58 | where 59 | T: Debug + std::fmt::Display, 60 | { 61 | println!("{:<9}{}", "", self.make_indent_str(t.to_string().yellow()),); 62 | } 63 | } 64 | 65 | macro_rules! impl_visitor_trait2 { 66 | ($( 67 | $name:ident 68 | )*) => { 69 | impl<'a> Visitor<'a> for HirPrinter<'a> { 70 | fn visit_name(&mut self, name: &str) { 71 | self.print_primitive(name); 72 | } 73 | 74 | fn visit_type(&mut self, t: &Type) { 75 | self.print_primitive(t); 76 | } 77 | 78 | fn visit_primitive(&mut self, val: T) 79 | where 80 | T: Debug + std::fmt::Display, 81 | { 82 | self.print_primitive(val); 83 | } 84 | 85 | paste! { 86 | 87 | $( 88 | fn [](&mut self, item: &'a $name) { 89 | self.print(item.clone()); 90 | 91 | self.increment(); 92 | 93 | [](self, item); 94 | 95 | self.decrement(); 96 | } 97 | )* 98 | } 99 | } 100 | }; 101 | } 102 | 103 | impl_visitor_trait2!( 104 | TopLevel 105 | Assign 106 | Prototype 107 | FunctionDecl 108 | StructDecl 109 | ArgumentDecl 110 | Identifier 111 | FnBody 112 | Body 113 | Statement 114 | If 115 | IfChain 116 | FunctionCall 117 | StructCtor 118 | Indice 119 | Literal 120 | Array 121 | NativeOperator 122 | ); 123 | 124 | pub fn print(root: &Root) { 125 | HirPrinter::new(root).visit_root(root) 126 | } 127 | -------------------------------------------------------------------------------- /src/lib/hir/mod.rs: -------------------------------------------------------------------------------- 1 | mod arena; 2 | pub mod has_hir_id; 3 | mod hir_id; 4 | mod hir_node; 5 | pub mod hir_printer; 6 | mod tree; 7 | pub mod visit; 8 | pub mod visit_mut; 9 | 10 | pub use hir_id::*; 11 | pub use tree::*; 12 | 13 | pub use arena::*; 14 | pub use has_hir_id::*; 15 | pub use hir_node::*; 16 | pub use hir_printer::*; 17 | -------------------------------------------------------------------------------- /src/lib/hir/visit.rs: -------------------------------------------------------------------------------- 1 | use paste::paste; 2 | 3 | use crate::{hir::*, ty::*}; 4 | 5 | macro_rules! generate_visitor_trait { 6 | ($( 7 | $name:ident 8 | )+) => { 9 | pub trait Visitor<'hir>: Sized { 10 | fn visit_name(&mut self, _name: &str) {} 11 | 12 | fn visit_primitive(&mut self, _val: T) 13 | {} 14 | 15 | paste! { 16 | $( 17 | fn [](&mut self, node: &'hir $name) { 18 | [](self, node); 19 | } 20 | )+ 21 | } 22 | } 23 | }; 24 | } 25 | 26 | generate_visitor_trait!( 27 | Root 28 | TopLevel 29 | Trait 30 | Impl 31 | Assign 32 | AssignLeftSide 33 | Prototype 34 | FunctionDecl 35 | StructDecl 36 | ArgumentDecl 37 | IdentifierPath 38 | Identifier 39 | FnBody 40 | Body 41 | Statement 42 | For 43 | ForIn 44 | While 45 | Expression 46 | IfChain 47 | If 48 | FunctionCall 49 | StructCtor 50 | Indice 51 | Dot 52 | Literal 53 | Array 54 | NativeOperator 55 | Type 56 | FuncType 57 | ); 58 | 59 | pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { 60 | walk_list!(visitor, visit_top_level, &root.top_levels); 61 | 62 | for r#struct in root.structs.values() { 63 | visitor.visit_struct_decl(r#struct); 64 | } 65 | 66 | for r#trait in root.traits.values() { 67 | visitor.visit_trait(r#trait); 68 | } 69 | 70 | for impls in root.trait_methods.values() { 71 | walk_map!(visitor, visit_function_decl, impls); 72 | } 73 | 74 | for impls in root.struct_methods.values() { 75 | walk_map!(visitor, visit_function_decl, impls); 76 | } 77 | 78 | walk_map!(visitor, visit_fn_body, &root.bodies); 79 | } 80 | 81 | pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { 82 | match &top_level.kind { 83 | TopLevelKind::Extern(p) => visitor.visit_prototype(p), 84 | TopLevelKind::Signature(p) => visitor.visit_prototype(p), 85 | TopLevelKind::Function(f) => visitor.visit_function_decl(f), 86 | }; 87 | } 88 | 89 | pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { 90 | visitor.visit_identifier(&s.name); 91 | 92 | walk_list!(visitor, visit_prototype, &s.defs); 93 | } 94 | 95 | pub fn walk_trait<'a, V: Visitor<'a>>(visitor: &mut V, t: &'a Trait) { 96 | visitor.visit_type(&t.name); 97 | 98 | walk_list!(visitor, visit_type, &t.types); 99 | 100 | walk_list!(visitor, visit_prototype, &t.defs); 101 | } 102 | 103 | #[allow(dead_code)] 104 | pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { 105 | visitor.visit_type(&i.name); 106 | 107 | walk_list!(visitor, visit_type, &i.types); 108 | 109 | walk_list!(visitor, visit_function_decl, &i.defs); 110 | } 111 | 112 | pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { 113 | visitor.visit_identifier(&prototype.name); 114 | 115 | visitor.visit_func_type(&prototype.signature); 116 | } 117 | 118 | pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { 119 | visitor.visit_identifier(&function_decl.name); 120 | 121 | walk_list!(visitor, visit_argument_decl, &function_decl.arguments); 122 | } 123 | 124 | pub fn walk_identifier_path<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a IdentifierPath) { 125 | walk_list!(visitor, visit_identifier, &identifier.path); 126 | } 127 | 128 | pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { 129 | visitor.visit_name(&identifier.name); 130 | } 131 | 132 | pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { 133 | visitor.visit_identifier(&argument.name); 134 | } 135 | 136 | pub fn walk_fn_body<'a, V: Visitor<'a>>(visitor: &mut V, fn_body: &'a FnBody) { 137 | visitor.visit_body(&fn_body.body); 138 | } 139 | 140 | pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { 141 | walk_list!(visitor, visit_statement, &body.stmts); 142 | } 143 | 144 | pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { 145 | match assign_left { 146 | AssignLeftSide::Identifier(id) => visitor.visit_identifier(id), 147 | AssignLeftSide::Indice(expr) => visitor.visit_indice(expr), 148 | AssignLeftSide::Dot(expr) => visitor.visit_dot(expr), 149 | } 150 | } 151 | 152 | pub fn walk_assign<'a, V: Visitor<'a>>(visitor: &mut V, assign: &'a Assign) { 153 | visitor.visit_assign_left_side(&assign.name); 154 | visitor.visit_expression(&assign.value); 155 | } 156 | 157 | pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { 158 | match statement.kind.as_ref() { 159 | StatementKind::Expression(expr) => visitor.visit_expression(expr), 160 | StatementKind::Assign(assign) => visitor.visit_assign(assign), 161 | StatementKind::If(expr) => visitor.visit_if_chain(expr), 162 | StatementKind::For(for_loop) => visitor.visit_for(for_loop), 163 | } 164 | } 165 | 166 | pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { 167 | match for_loop { 168 | For::In(for_in) => visitor.visit_for_in(for_in), 169 | For::While(while_loop) => visitor.visit_while(while_loop), 170 | } 171 | } 172 | 173 | pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { 174 | visitor.visit_identifier(&for_in.value); 175 | visitor.visit_expression(&for_in.expr); 176 | visitor.visit_body(&for_in.body); 177 | } 178 | 179 | pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { 180 | visitor.visit_expression(&while_loop.predicat); 181 | visitor.visit_body(&while_loop.body); 182 | } 183 | 184 | pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { 185 | match &*expr.kind { 186 | ExpressionKind::Lit(lit) => visitor.visit_literal(lit), 187 | ExpressionKind::Identifier(id) => visitor.visit_identifier_path(id), 188 | ExpressionKind::FunctionCall(fc) => visitor.visit_function_call(fc), 189 | ExpressionKind::StructCtor(s) => visitor.visit_struct_ctor(s), 190 | ExpressionKind::Indice(indice) => visitor.visit_indice(indice), 191 | ExpressionKind::Dot(dot) => visitor.visit_dot(dot), 192 | ExpressionKind::NativeOperation(op, left, right) => { 193 | visitor.visit_native_operator(op); 194 | visitor.visit_identifier(left); 195 | visitor.visit_identifier(right); 196 | } 197 | ExpressionKind::Return(expr) => visitor.visit_expression(expr), 198 | } 199 | } 200 | 201 | pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { 202 | visitor.visit_identifier(&s.name); 203 | 204 | walk_map!(visitor, visit_expression, &s.defs); 205 | } 206 | 207 | pub fn walk_function_call<'a, V: Visitor<'a>>(visitor: &mut V, fc: &'a FunctionCall) { 208 | visitor.visit_expression(&fc.op); 209 | 210 | walk_list!(visitor, visit_expression, &fc.args); 211 | } 212 | 213 | pub fn walk_dot<'a, V: Visitor<'a>>(visitor: &mut V, dot: &'a Dot) { 214 | visitor.visit_expression(&dot.op); 215 | visitor.visit_identifier(&dot.value); 216 | } 217 | 218 | pub fn walk_indice<'a, V: Visitor<'a>>(visitor: &mut V, indice: &'a Indice) { 219 | visitor.visit_expression(&indice.op); 220 | visitor.visit_expression(&indice.value); 221 | } 222 | 223 | pub fn walk_literal<'a, V: Visitor<'a>>(visitor: &mut V, literal: &'a Literal) { 224 | match &literal.kind { 225 | LiteralKind::Number(n) => visitor.visit_primitive(n), 226 | LiteralKind::Float(f) => visitor.visit_primitive(f), 227 | LiteralKind::String(s) => visitor.visit_primitive(s), 228 | LiteralKind::Bool(b) => visitor.visit_primitive(b), 229 | LiteralKind::Array(arr) => visitor.visit_array(arr), 230 | LiteralKind::Char(c) => visitor.visit_primitive(c), 231 | } 232 | } 233 | 234 | pub fn walk_array<'a, V: Visitor<'a>>(visitor: &mut V, arr: &'a Array) { 235 | walk_list!(visitor, visit_expression, &arr.values); 236 | } 237 | 238 | pub fn walk_native_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a NativeOperator) { 239 | visitor.visit_primitive(operator.kind.clone()); 240 | } 241 | 242 | pub fn walk_if_chain<'a, V: Visitor<'a>>(visitor: &mut V, if_chain: &'a IfChain) { 243 | walk_list!(visitor, visit_if, &if_chain.ifs); 244 | 245 | if let Some(body) = &if_chain.else_body { 246 | visitor.visit_body(body); 247 | } 248 | } 249 | 250 | pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { 251 | visitor.visit_expression(&r#if.predicat); 252 | visitor.visit_body(&r#if.body); 253 | } 254 | 255 | pub fn walk_type<'a, V: Visitor<'a>>(_visitor: &mut V, _t: &'a Type) { 256 | // Nothing to do 257 | } 258 | 259 | pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { 260 | walk_list!(visitor, visit_type, &signature.arguments); 261 | 262 | visitor.visit_type(&signature.ret); 263 | } 264 | -------------------------------------------------------------------------------- /src/lib/hir/visit_mut.rs: -------------------------------------------------------------------------------- 1 | use paste::paste; 2 | 3 | use crate::{hir::*, ty::*}; 4 | 5 | macro_rules! generate_visitor_mut_trait { 6 | ($( 7 | $name:ident 8 | )+) => { 9 | pub trait VisitorMut<'hir>: Sized { 10 | fn visit_name(&mut self, _name: &mut String) {} 11 | 12 | fn visit_primitive(&mut self, _val: T) 13 | {} 14 | 15 | paste! { 16 | $( 17 | fn [](&mut self, node: &'hir mut $name) { 18 | [](self, node); 19 | } 20 | )+ 21 | } 22 | } 23 | }; 24 | } 25 | 26 | generate_visitor_mut_trait!( 27 | Root 28 | TopLevel 29 | Trait 30 | Impl 31 | Prototype 32 | FunctionDecl 33 | StructDecl 34 | Assign 35 | AssignLeftSide 36 | ArgumentDecl 37 | IdentifierPath 38 | Identifier 39 | FnBody 40 | Body 41 | Statement 42 | For 43 | ForIn 44 | While 45 | Expression 46 | IfChain 47 | If 48 | FunctionCall 49 | StructCtor 50 | Indice 51 | Dot 52 | Literal 53 | Array 54 | NativeOperator 55 | Type 56 | FuncType 57 | ); 58 | 59 | pub fn walk_root<'a, V: VisitorMut<'a>>(visitor: &mut V, root: &'a mut Root) { 60 | walk_list!(visitor, visit_top_level, &mut root.top_levels); 61 | 62 | for r#struct in &mut root.structs.values_mut() { 63 | visitor.visit_struct_decl(r#struct); 64 | } 65 | 66 | for (_, r#trait) in &mut root.traits { 67 | visitor.visit_trait(r#trait); 68 | } 69 | 70 | for (_, impls) in &mut root.trait_methods { 71 | walk_map!(visitor, visit_function_decl, impls); 72 | } 73 | 74 | for (_, impls) in &mut root.struct_methods { 75 | walk_map!(visitor, visit_function_decl, impls); 76 | } 77 | 78 | walk_map!(visitor, visit_fn_body, &mut root.bodies); 79 | } 80 | 81 | pub fn walk_struct_decl<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructDecl) { 82 | visitor.visit_identifier(&mut s.name); 83 | 84 | walk_list!(visitor, visit_prototype, &mut s.defs); 85 | } 86 | 87 | pub fn walk_struct_ctor<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructCtor) { 88 | visitor.visit_identifier(&mut s.name); 89 | 90 | walk_map!(visitor, visit_expression, &mut s.defs); 91 | } 92 | 93 | pub fn walk_top_level<'a, V: VisitorMut<'a>>(visitor: &mut V, top_level: &'a mut TopLevel) { 94 | match &mut top_level.kind { 95 | TopLevelKind::Extern(p) => visitor.visit_prototype(p), 96 | TopLevelKind::Signature(p) => visitor.visit_prototype(p), 97 | TopLevelKind::Function(f) => visitor.visit_function_decl(f), 98 | }; 99 | } 100 | 101 | #[allow(dead_code)] 102 | pub fn walk_trait<'a, V: VisitorMut<'a>>(visitor: &mut V, t: &'a mut Trait) { 103 | visitor.visit_type(&mut t.name); 104 | 105 | walk_list!(visitor, visit_type, &mut t.types); 106 | 107 | walk_list!(visitor, visit_prototype, &mut t.defs); 108 | } 109 | 110 | #[allow(dead_code)] 111 | pub fn walk_impl<'a, V: VisitorMut<'a>>(visitor: &mut V, i: &'a mut Impl) { 112 | visitor.visit_type(&mut i.name); 113 | 114 | walk_list!(visitor, visit_type, &mut i.types); 115 | 116 | walk_list!(visitor, visit_function_decl, &mut i.defs); 117 | } 118 | 119 | pub fn walk_prototype<'a, V: VisitorMut<'a>>(visitor: &mut V, prototype: &'a mut Prototype) { 120 | visitor.visit_identifier(&mut prototype.name); 121 | 122 | visitor.visit_func_type(&mut prototype.signature); 123 | } 124 | 125 | pub fn walk_function_decl<'a, V: VisitorMut<'a>>( 126 | visitor: &mut V, 127 | function_decl: &'a mut FunctionDecl, 128 | ) { 129 | visitor.visit_identifier(&mut function_decl.name); 130 | 131 | walk_list!(visitor, visit_argument_decl, &mut function_decl.arguments); 132 | } 133 | 134 | pub fn walk_identifier_path<'a, V: VisitorMut<'a>>( 135 | visitor: &mut V, 136 | identifier: &'a mut IdentifierPath, 137 | ) { 138 | walk_list!(visitor, visit_identifier, &mut identifier.path); 139 | } 140 | 141 | pub fn walk_identifier<'a, V: VisitorMut<'a>>(visitor: &mut V, identifier: &'a mut Identifier) { 142 | visitor.visit_name(&mut identifier.name); 143 | } 144 | 145 | pub fn walk_argument_decl<'a, V: VisitorMut<'a>>(visitor: &mut V, argument: &'a mut ArgumentDecl) { 146 | visitor.visit_identifier(&mut argument.name); 147 | } 148 | 149 | pub fn walk_fn_body<'a, V: VisitorMut<'a>>(visitor: &mut V, fn_body: &'a mut FnBody) { 150 | visitor.visit_body(&mut fn_body.body); 151 | } 152 | 153 | pub fn walk_body<'a, V: VisitorMut<'a>>(visitor: &mut V, body: &'a mut Body) { 154 | walk_list!(visitor, visit_statement, &mut body.stmts); 155 | } 156 | 157 | pub fn walk_statement<'a, V: VisitorMut<'a>>(visitor: &mut V, statement: &'a mut Statement) { 158 | match &mut *statement.kind { 159 | StatementKind::Expression(expr) => visitor.visit_expression(expr), 160 | StatementKind::Assign(assign) => visitor.visit_assign(assign), 161 | StatementKind::If(expr) => visitor.visit_if_chain(expr), 162 | StatementKind::For(for_loop) => visitor.visit_for(for_loop), 163 | } 164 | } 165 | 166 | pub fn walk_for<'a, V: VisitorMut<'a>>(visitor: &mut V, for_loop: &'a mut For) { 167 | match for_loop { 168 | For::In(for_in) => visitor.visit_for_in(for_in), 169 | For::While(while_loop) => visitor.visit_while(while_loop), 170 | } 171 | } 172 | 173 | pub fn walk_for_in<'a, V: VisitorMut<'a>>(visitor: &mut V, for_in: &'a mut ForIn) { 174 | visitor.visit_identifier(&mut for_in.value); 175 | visitor.visit_expression(&mut for_in.expr); 176 | visitor.visit_body(&mut for_in.body); 177 | } 178 | 179 | pub fn walk_while<'a, V: VisitorMut<'a>>(visitor: &mut V, while_loop: &'a mut While) { 180 | visitor.visit_expression(&mut while_loop.predicat); 181 | visitor.visit_body(&mut while_loop.body); 182 | } 183 | 184 | pub fn walk_assign_left_side<'a, V: VisitorMut<'a>>( 185 | visitor: &mut V, 186 | assign_left: &'a mut AssignLeftSide, 187 | ) { 188 | match assign_left { 189 | AssignLeftSide::Identifier(id) => visitor.visit_identifier(id), 190 | AssignLeftSide::Indice(expr) => visitor.visit_indice(expr), 191 | AssignLeftSide::Dot(expr) => visitor.visit_dot(expr), 192 | } 193 | } 194 | 195 | pub fn walk_assign<'a, V: VisitorMut<'a>>(visitor: &mut V, assign: &'a mut Assign) { 196 | visitor.visit_assign_left_side(&mut assign.name); 197 | visitor.visit_expression(&mut assign.value); 198 | } 199 | 200 | pub fn walk_expression<'a, V: VisitorMut<'a>>(visitor: &mut V, expr: &'a mut Expression) { 201 | match &mut *expr.kind { 202 | ExpressionKind::Lit(lit) => visitor.visit_literal(lit), 203 | ExpressionKind::Identifier(id) => visitor.visit_identifier_path(id), 204 | ExpressionKind::FunctionCall(fc) => visitor.visit_function_call(fc), 205 | ExpressionKind::StructCtor(s) => visitor.visit_struct_ctor(s), 206 | ExpressionKind::Indice(indice) => visitor.visit_indice(indice), 207 | ExpressionKind::Dot(dot) => visitor.visit_dot(dot), 208 | ExpressionKind::NativeOperation(op, left, right) => { 209 | visitor.visit_identifier(left); 210 | visitor.visit_identifier(right); 211 | visitor.visit_native_operator(op); 212 | } 213 | ExpressionKind::Return(expr) => visitor.visit_expression(expr), 214 | } 215 | } 216 | 217 | pub fn walk_function_call<'a, V: VisitorMut<'a>>(visitor: &mut V, fc: &'a mut FunctionCall) { 218 | visitor.visit_expression(&mut fc.op); 219 | 220 | walk_list!(visitor, visit_expression, &mut fc.args); 221 | } 222 | 223 | pub fn walk_indice<'a, V: VisitorMut<'a>>(visitor: &mut V, indice: &'a mut Indice) { 224 | visitor.visit_expression(&mut indice.op); 225 | visitor.visit_expression(&mut indice.value); 226 | } 227 | 228 | pub fn walk_dot<'a, V: VisitorMut<'a>>(visitor: &mut V, dot: &'a mut Dot) { 229 | visitor.visit_expression(&mut dot.op); 230 | visitor.visit_identifier(&mut dot.value); 231 | } 232 | 233 | pub fn walk_literal<'a, V: VisitorMut<'a>>(visitor: &mut V, literal: &'a mut Literal) { 234 | match &mut literal.kind { 235 | LiteralKind::Number(n) => visitor.visit_primitive(n), 236 | LiteralKind::Float(f) => visitor.visit_primitive(f), 237 | LiteralKind::String(s) => visitor.visit_primitive(s), 238 | LiteralKind::Bool(b) => visitor.visit_primitive(b), 239 | LiteralKind::Array(arr) => visitor.visit_array(arr), 240 | LiteralKind::Char(c) => visitor.visit_primitive(c), 241 | } 242 | } 243 | 244 | pub fn walk_array<'a, V: VisitorMut<'a>>(visitor: &mut V, arr: &'a mut Array) { 245 | walk_list!(visitor, visit_expression, &mut arr.values); 246 | } 247 | 248 | pub fn walk_native_operator<'a, V: VisitorMut<'a>>( 249 | _visitor: &mut V, 250 | _operator: &'a mut NativeOperator, 251 | ) { 252 | // 253 | } 254 | 255 | pub fn walk_if_chain<'a, V: VisitorMut<'a>>(visitor: &mut V, if_chain: &'a mut IfChain) { 256 | walk_list!(visitor, visit_if, &mut if_chain.ifs); 257 | 258 | if let Some(body) = &mut if_chain.else_body { 259 | visitor.visit_body(body); 260 | } 261 | } 262 | 263 | pub fn walk_if<'a, V: VisitorMut<'a>>(visitor: &mut V, r#if: &'a mut If) { 264 | visitor.visit_expression(&mut r#if.predicat); 265 | visitor.visit_body(&mut r#if.body); 266 | } 267 | 268 | pub fn walk_type<'a, V: VisitorMut<'a>>(_visitor: &mut V, _t: &'a mut Type) { 269 | // Nothing to do 270 | } 271 | 272 | pub fn walk_func_type<'a, V: VisitorMut<'a>>(visitor: &mut V, signature: &'a mut FuncType) { 273 | walk_list!(visitor, visit_type, &mut signature.arguments); 274 | 275 | visitor.visit_type(&mut signature.ret); 276 | } 277 | -------------------------------------------------------------------------------- /src/lib/infer/mangle.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use crate::{hir::visit_mut::*, hir::*, ty::Type}; 4 | 5 | #[derive(Debug)] 6 | pub struct MangleContext { 7 | pub node_types: BTreeMap, 8 | } 9 | 10 | impl<'a> VisitorMut<'a> for MangleContext { 11 | fn visit_function_decl(&mut self, f: &'a mut FunctionDecl) { 12 | let t = self.node_types.get(&f.hir_id).unwrap(); 13 | 14 | if let Type::Func(f_t) = t { 15 | f.mangle(f_t.to_prefixes()); 16 | } else { 17 | panic!("Not a function {:?}", t); 18 | } 19 | } 20 | 21 | fn visit_function_call(&mut self, fc: &'a mut FunctionCall) { 22 | let t = self.node_types.get(&fc.op.get_hir_id()).unwrap(); 23 | 24 | if let Type::Func(f_t) = t { 25 | fc.mangle(f_t.to_prefixes()); 26 | 27 | self.visit_expression(&mut fc.op); 28 | 29 | walk_list!(self, visit_expression, &mut fc.args); 30 | } else { 31 | panic!("Not a function {:?}", t); 32 | } 33 | } 34 | } 35 | 36 | pub fn mangle(root: &mut Root) { 37 | MangleContext { 38 | node_types: root.node_types.clone(), 39 | } 40 | .visit_root(root); 41 | } 42 | -------------------------------------------------------------------------------- /src/lib/infer/mod.rs: -------------------------------------------------------------------------------- 1 | mod constraint; 2 | mod mangle; 3 | mod monomorphize; 4 | mod state; 5 | pub mod trait_solver; 6 | 7 | pub use self::state::*; 8 | 9 | use crate::{diagnostics::Diagnostic, parser::ParsingCtx, Config}; 10 | 11 | pub fn infer( 12 | root: &mut crate::hir::Root, 13 | parsing_ctx: &mut ParsingCtx, 14 | config: &Config, 15 | ) -> Result { 16 | if config.show_hir { 17 | super::hir::hir_printer::print(root); 18 | } 19 | 20 | let (tmp_resolutions, diags) = constraint::solve(root); 21 | 22 | parsing_ctx.diagnostics.append(diags); 23 | 24 | parsing_ctx.return_if_error()?; 25 | 26 | let mut new_root = monomorphize::monomophize(root, tmp_resolutions); 27 | 28 | mangle::mangle(&mut new_root); 29 | 30 | if config.show_thir { 31 | super::hir::hir_printer::print(&new_root); 32 | } 33 | 34 | parsing_ctx.return_if_error()?; 35 | 36 | Ok(new_root) 37 | } 38 | -------------------------------------------------------------------------------- /src/lib/infer/monomorphize/mod.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, HashMap}; 2 | 3 | use crate::{ 4 | hir::{HirId, Root}, 5 | resolver::ResolutionMap, 6 | }; 7 | 8 | use self::monomorphizer::Monomorphizer; 9 | 10 | mod monomorphizer; 11 | 12 | pub fn monomophize( 13 | root: &mut Root, 14 | tmp_resolutions: BTreeMap>, 15 | ) -> Root { 16 | Monomorphizer { 17 | root, 18 | trans_resolutions: ResolutionMap::default(), 19 | new_resolutions: ResolutionMap::default(), 20 | old_ordered_resolutions: HashMap::new(), 21 | body_arguments: BTreeMap::new(), 22 | generated_fn_hir_id: HashMap::new(), 23 | structs: HashMap::new(), 24 | tmp_resolutions, 25 | } 26 | .run() 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/infer/state.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, HashMap}; 2 | 3 | use crate::{ 4 | diagnostics::{Diagnostic, Diagnostics}, 5 | hir::*, 6 | parser::span::Span, 7 | ty::*, 8 | }; 9 | 10 | pub type Env = BTreeMap; 11 | 12 | #[derive(Debug, Default, Clone)] 13 | pub struct Envs { 14 | fns: BTreeMap>, 15 | current_fn: (HirId, FuncType), 16 | pub spans: HashMap, 17 | pub diagnostics: Diagnostics, 18 | } 19 | 20 | impl Envs { 21 | pub fn new(diagnostics: Diagnostics, spans: HashMap) -> Self { 22 | Self { 23 | diagnostics, 24 | spans, 25 | ..Self::default() 26 | } 27 | } 28 | pub fn get_current_env_mut(&mut self) -> Option<&mut BTreeMap> { 29 | self.fns 30 | .get_mut(&self.current_fn.0)? 31 | .get_mut(&self.current_fn.1) 32 | } 33 | 34 | pub fn get_current_env(&self) -> Option<&BTreeMap> { 35 | self.fns 36 | .get(&self.current_fn.0) 37 | .and_then(|map| map.get(&self.current_fn.1)) 38 | } 39 | 40 | pub fn set_current_fn(&mut self, f: (HirId, FuncType)) -> bool { 41 | self.fns 42 | .entry(f.0.clone()) 43 | .or_insert_with(HashMap::new) 44 | .entry(f.1.clone()) 45 | .or_insert_with(Env::default); 46 | 47 | self.current_fn = f; 48 | 49 | true 50 | } 51 | 52 | pub fn get_current_fn(&self) -> (HirId, FuncType) { 53 | self.current_fn.clone() 54 | } 55 | 56 | fn set_type_alone(&mut self, dest: &HirId, src: &Type) -> Option { 57 | if let Type::ForAll(_) = src { 58 | warn!("set_type requires `src: &Type` to be solved"); 59 | 60 | return None; 61 | } 62 | 63 | self.get_current_env_mut() 64 | .unwrap() 65 | .insert(dest.clone(), src.clone()) 66 | } 67 | 68 | pub fn set_type(&mut self, dest: &HirId, src: &Type) { 69 | let previous = self.set_type_alone(dest, src); 70 | 71 | match (src, previous.clone()) { 72 | (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { 73 | if prev_f.is_solved() && src_f.is_solved() { 74 | self.diagnostics.push_error(Diagnostic::new_type_conflict( 75 | self.spans.get(dest).unwrap().clone().into(), 76 | previous.clone().unwrap(), 77 | src.clone(), 78 | previous.unwrap(), 79 | src.clone(), 80 | )); 81 | } 82 | } 83 | (src, Some(previous)) if !src.eq(&previous) => { 84 | if previous.is_solved() && src.is_solved() { 85 | self.diagnostics.push_error(Diagnostic::new_type_conflict( 86 | self.spans.get(dest).unwrap().clone().into(), 87 | src.clone(), 88 | previous.clone(), 89 | src.clone(), 90 | previous, 91 | )); 92 | } 93 | } 94 | _ => (), 95 | } 96 | } 97 | 98 | pub fn set_type_eq(&mut self, dest: &HirId, src: &HirId) -> Option<()> { 99 | // we short-circuit if the type is not found 100 | // this is useful only when some diagnostics has been emited 101 | // but we want to continue to infer the rest of the types 102 | let src_t_opt = self.get_type(src); 103 | if src_t_opt.is_none() { 104 | error!("Cannot set the type of `{}` to `{}`", dest, src); 105 | 106 | return None; 107 | } 108 | 109 | let src_t = src_t_opt?.clone(); 110 | let previous = self.set_type_alone(dest, &src_t); 111 | 112 | match (src_t.clone(), previous.clone()) { 113 | (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { 114 | if prev_f.is_solved() && src_f.is_solved() { 115 | self.diagnostics.push_error(Diagnostic::new_type_conflict( 116 | self.spans.get(src).unwrap().clone().into(), 117 | previous.clone().unwrap(), 118 | src_t.clone(), 119 | previous.unwrap(), 120 | src_t.clone(), 121 | )); 122 | } 123 | } 124 | (src_t, Some(previous)) if !src_t.eq(&previous) => { 125 | if previous.is_solved() && src_t.is_solved() { 126 | self.diagnostics.push_error(Diagnostic::new_type_conflict( 127 | self.spans.get(src).unwrap().clone().into(), 128 | previous.clone(), 129 | src_t.clone(), 130 | previous, 131 | src_t, 132 | )); 133 | } 134 | } 135 | _ => (), 136 | } 137 | 138 | Some(()) 139 | } 140 | 141 | pub fn get_type(&self, hir_id: &HirId) -> Option<&Type> { 142 | self.get_current_env().and_then(|env| env.get(hir_id)) 143 | } 144 | 145 | pub fn apply_args_type(&mut self, f: &FunctionDecl) { 146 | f.arguments 147 | .clone() 148 | .into_iter() 149 | .enumerate() 150 | .for_each(|(i, arg)| { 151 | self.set_type( 152 | &arg.get_hir_id(), 153 | &self.current_fn.1.arguments.get(i).unwrap().clone(), 154 | ) 155 | }); 156 | } 157 | 158 | #[allow(dead_code)] 159 | pub fn get_fn_types(&self, f: &HirId) -> Option<&HashMap> { 160 | self.fns.get(f) 161 | } 162 | 163 | pub fn get_inner(&self) -> &BTreeMap> { 164 | &self.fns 165 | } 166 | 167 | #[allow(dead_code)] 168 | pub fn add_empty(&mut self, hir_id: &HirId) { 169 | self.fns.entry(hir_id.clone()).or_insert_with(HashMap::new); 170 | } 171 | 172 | pub fn amend_current_sig(&mut self, new_sig: &FuncType) { 173 | if self.current_fn.1 == *new_sig { 174 | return; 175 | } 176 | 177 | let env = self.get_current_env().unwrap().clone(); 178 | 179 | self.fns 180 | .get_mut(&self.current_fn.0) 181 | .unwrap() 182 | .insert(new_sig.clone(), env); 183 | 184 | self.fns 185 | .get_mut(&self.current_fn.0) 186 | .unwrap() 187 | .remove(&self.current_fn.1); 188 | 189 | self.current_fn.1 = new_sig.clone(); 190 | } 191 | 192 | pub fn get_diagnostics(self) -> Diagnostics { 193 | self.diagnostics 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/lib/infer/trait_solver.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, BTreeSet}; 2 | 3 | use crate::{ 4 | ast::{Impl, NodeId}, 5 | ty::Type, 6 | }; 7 | 8 | #[derive(Debug, Default, Clone)] 9 | pub struct TraitSolver { 10 | pub implemented_trait: BTreeMap>, // implementors -> trait 11 | pub implemented_fns: BTreeMap>, // implementor -> (fn_hir_id, fn_name) 12 | pub trait_methods: BTreeMap>, // trait/struct -> (method_hir_id, method_name) 13 | } 14 | 15 | impl TraitSolver { 16 | pub fn new() -> TraitSolver { 17 | TraitSolver { 18 | implemented_trait: BTreeMap::new(), 19 | trait_methods: BTreeMap::new(), 20 | implemented_fns: BTreeMap::new(), 21 | } 22 | } 23 | 24 | pub fn add_impl(&mut self, tr: &Impl) { 25 | let effective_type = if tr.types.is_empty() { 26 | tr.name.get_name() 27 | } else { 28 | tr.types[0].get_name() 29 | }; 30 | 31 | self.implemented_fns 32 | .entry(effective_type) 33 | .or_insert(BTreeMap::new()) 34 | .extend( 35 | tr.defs 36 | .iter() 37 | .map(|fundecl| (fundecl.node_id, fundecl.name.name.clone())) 38 | .collect::>(), 39 | ); 40 | 41 | self.trait_methods 42 | .entry(tr.name.get_name()) 43 | .or_insert(BTreeMap::new()) 44 | .extend( 45 | tr.defs 46 | .iter() 47 | .map(|fundecl| (fundecl.node_id, fundecl.name.to_string())) 48 | .collect::>(), 49 | ); 50 | } 51 | 52 | pub fn add_implementor(&mut self, implementor_type: Type, trait_type: Type) { 53 | self.implemented_trait 54 | .entry(implementor_type.get_name()) 55 | .or_insert_with(BTreeSet::new) 56 | .insert(trait_type.get_name()); 57 | } 58 | 59 | pub fn node_id_of_fn_implementor( 60 | &self, 61 | implementor_type: &Type, 62 | fn_name: String, 63 | ) -> Option { 64 | self.implemented_fns 65 | .get(&implementor_type.get_name()) 66 | .and_then(|set| { 67 | set.iter() 68 | .find(|(_, name)| **name == fn_name) 69 | .map(|(id, _)| id.clone()) 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/lib/parser/default_impl_populator.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use crate::{ast::visit_mut::*, ast::*}; 4 | 5 | #[derive(Debug)] 6 | pub struct DefaultImplPopulator { 7 | pub traits: BTreeMap, 8 | } 9 | 10 | impl<'a> VisitorMut<'a> for DefaultImplPopulator { 11 | fn visit_trait(&mut self, trait_: &mut Trait) { 12 | self.traits.insert(trait_.name.get_name(), trait_.clone()); 13 | } 14 | 15 | fn visit_impl(&mut self, i: &'a mut Impl) { 16 | // If this is not a Trait impl (but a simple impl) 17 | // then we don't need to do anything. 18 | if i.types.is_empty() { 19 | return; 20 | } 21 | 22 | let trait_name = i.name.get_name(); 23 | let trait_ = self.traits.get(&trait_name).unwrap(); 24 | 25 | // We remove any default implementation that has been overriden 26 | let default_impl: Vec<_> = trait_ 27 | .default_impl 28 | .clone() 29 | .into_iter() 30 | .filter(|default_impl| { 31 | i.defs 32 | .iter() 33 | .find(|f| f.name.name == default_impl.name.name) 34 | .is_none() 35 | }) 36 | .collect(); 37 | 38 | i.defs.extend(default_impl); 39 | } 40 | } 41 | 42 | pub fn populate_default_impl(root: &mut Root) { 43 | DefaultImplPopulator { 44 | traits: BTreeMap::new(), 45 | } 46 | .visit_root(root); 47 | } 48 | -------------------------------------------------------------------------------- /src/lib/parser/parsing_context.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeMap, HashMap}, 3 | path::{Component, PathBuf}, 4 | }; 5 | 6 | use colored::*; 7 | 8 | use crate::{ 9 | ast::{Identifier, NodeId}, 10 | diagnostics::{Diagnostic, DiagnosticType, Diagnostics}, 11 | parser::span::Span, 12 | Config, 13 | }; 14 | 15 | use super::SourceFile; 16 | 17 | #[derive(Default, Debug)] 18 | pub struct ParsingCtx { 19 | pub files: HashMap, 20 | pub config: Config, 21 | pub current_file: Option, 22 | pub diagnostics: Diagnostics, 23 | pub operators_list: HashMap, 24 | pub identities: BTreeMap, 25 | } 26 | 27 | impl ParsingCtx { 28 | pub fn new(config: &Config) -> Self { 29 | ParsingCtx { 30 | config: config.clone(), 31 | ..Default::default() 32 | } 33 | } 34 | 35 | pub fn add_file(&mut self, file: &SourceFile) { 36 | self.current_file = Some(file.file_path.clone()); 37 | 38 | self.files.insert(file.file_path.clone(), file.clone()); 39 | } 40 | 41 | pub fn get_current_file(&self) -> SourceFile { 42 | self.files 43 | .get(&self.current_file.clone().unwrap()) 44 | .unwrap() 45 | .clone() 46 | } 47 | 48 | pub fn print_diagnostics(&self) { 49 | if self.config.quiet { 50 | return; 51 | } 52 | 53 | self.diagnostics.print(&self.files); 54 | } 55 | 56 | pub fn print_success_diagnostics(&self) { 57 | if self.config.quiet { 58 | return; 59 | } 60 | 61 | self.print_diagnostics(); 62 | 63 | if !self.diagnostics.list.is_empty() { 64 | let diag_type_str = format!( 65 | "{}{}{}", 66 | "[".bright_black(), 67 | "Success".green(), 68 | "]".bright_black(), 69 | ); 70 | 71 | println!( 72 | "{} {} {} {} {} {}", 73 | diag_type_str, 74 | "Compilation".bright_black(), 75 | "successful".bright_green(), 76 | "with".bright_black(), 77 | self.diagnostics.list.len().to_string().yellow(), 78 | "warnings".bright_yellow(), 79 | ); 80 | } else if self.config.verbose { 81 | let diag_type_str = format!( 82 | "{}{}{}", 83 | "[".bright_black(), 84 | "Success".green(), 85 | "]".bright_black(), 86 | ); 87 | 88 | println!( 89 | "{} {}", 90 | diag_type_str, 91 | "Compilation successful".bright_black(), 92 | ); 93 | } 94 | } 95 | 96 | pub fn return_if_error(&self) -> Result<(), Diagnostic> { 97 | if self.diagnostics.must_stop { 98 | self.print_diagnostics(); 99 | 100 | let (errors, warnings): (Vec<_>, Vec<_>) = self 101 | .diagnostics 102 | .list 103 | .iter() 104 | .enumerate() 105 | .partition(|(i, _diag)| { 106 | matches!( 107 | *self.diagnostics.list_types.get(*i).unwrap(), 108 | DiagnosticType::Error 109 | ) 110 | }); 111 | 112 | let diag_type_str = format!( 113 | "{}{}{}", 114 | "[".bright_black(), 115 | "Error".red(), 116 | "]".bright_black(), 117 | ); 118 | 119 | if !self.config.quiet { 120 | println!( 121 | "{} {} {} {} {} {} {} {} {}", 122 | diag_type_str, 123 | "Compilation".bright_black(), 124 | "stopped".bright_red(), 125 | "with".bright_black(), 126 | errors.len().to_string().red(), 127 | "errors".bright_red(), 128 | "and".bright_black(), 129 | warnings.len().to_string().yellow(), 130 | "warnings".bright_yellow(), 131 | ); 132 | } 133 | 134 | return Err(Diagnostic::new_empty()); 135 | } 136 | 137 | Ok(()) 138 | } 139 | 140 | pub fn new_span(&self, start: usize, end: usize) -> Span { 141 | Span { 142 | file_path: self.get_current_file().file_path, 143 | start, 144 | end, 145 | } 146 | } 147 | 148 | pub fn resolve_and_add_file(&mut self, name: String) -> Result { 149 | let current_file = self.get_current_file(); 150 | 151 | let new_file = current_file.resolve_new(name).map_err(|m| { 152 | // Placeholder span, to be overriden by calling mod (TopLevel::parse()) 153 | Diagnostic::new_module_not_found( 154 | Span { 155 | file_path: current_file.file_path.clone(), 156 | start: 0, 157 | end: 0, 158 | } 159 | .into(), 160 | m, 161 | ) 162 | })?; 163 | 164 | if self.config.verbose { 165 | println!( 166 | " -> Compiling {}", 167 | new_file 168 | .mod_path 169 | .components() 170 | .map(|m| { 171 | match m { 172 | Component::RootDir => "main", 173 | Component::Normal(m) => m.to_str().unwrap(), 174 | _ => "", 175 | } 176 | .green() 177 | .to_string() 178 | }) 179 | .collect::>() 180 | .join(" -> "), 181 | ); 182 | } 183 | 184 | self.add_file(&new_file); 185 | 186 | Ok(new_file) 187 | } 188 | 189 | pub fn operator_exists(&self, name: &Identifier) -> bool { 190 | self.operators_list.contains_key(&name.name) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/lib/parser/source_file.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fs, 3 | path::{Path, PathBuf}, 4 | }; 5 | 6 | use regex::Regex; 7 | 8 | use crate::diagnostics::Diagnostic; 9 | 10 | use super::span::Span; 11 | 12 | #[derive(Default, Debug, Clone)] 13 | pub struct SourceFile { 14 | pub file_path: PathBuf, 15 | pub mod_path: PathBuf, 16 | pub content: String, 17 | } 18 | 19 | impl SourceFile { 20 | pub fn from_file(in_name: String) -> Result { 21 | let content = if let Some(content) = super::STDLIB_FILES.get(&in_name) { 22 | content.to_string() 23 | } else { 24 | fs::read_to_string(in_name.clone()).map_err(|_| { 25 | Diagnostic::new_file_not_found(Span::new_placeholder(), in_name.clone()) 26 | })? 27 | }; 28 | 29 | let content = Self::sanitize_content(&content); 30 | 31 | let content = content.replace("^[ \t]*\n", "\n"); 32 | 33 | let mut mod_path = PathBuf::from(in_name.clone()); 34 | 35 | mod_path.set_extension(""); 36 | 37 | Ok(SourceFile { 38 | file_path: PathBuf::from(in_name), 39 | mod_path, 40 | content, 41 | }) 42 | } 43 | 44 | pub fn from_str(path: &str, content: &str) -> Result { 45 | let mut mod_path = PathBuf::from(path.clone()); 46 | 47 | mod_path.set_extension(""); 48 | 49 | let content = Self::sanitize_content(&content); 50 | 51 | Ok(SourceFile { 52 | file_path: PathBuf::from(path.clone()), 53 | mod_path, 54 | content, 55 | }) 56 | } 57 | 58 | pub fn from_expr( 59 | top_levels: String, 60 | mut expr: String, 61 | do_print: bool, 62 | ) -> Result { 63 | let print_str = if do_print { "print " } else { "" }; 64 | 65 | if expr.is_empty() { 66 | expr = " 0".to_string(); 67 | } 68 | 69 | let top_levels = r##"mod lib 70 | use lib::prelude::(*) 71 | "## 72 | .to_owned() 73 | + &top_levels 74 | + r##" 75 | 76 | main = 77 | "## + &print_str.to_string() 78 | + &r##"custom() 79 | 0 80 | custom = 81 | "## 82 | .to_owned() 83 | + &expr; 84 | 85 | let content = Self::sanitize_content(&top_levels); 86 | 87 | Ok(SourceFile { 88 | file_path: PathBuf::from("./src/main.rk"), 89 | mod_path: PathBuf::from("root"), 90 | content, 91 | }) 92 | } 93 | 94 | pub fn resolve_new(&self, name: String) -> Result { 95 | let mut file_path = self.file_path.parent().unwrap().join(Path::new(&name)); 96 | 97 | file_path.set_extension("rk"); 98 | 99 | let mod_path = self.mod_path.as_path().join(Path::new(&name)); 100 | 101 | let content = match fs::read_to_string(file_path.to_str().unwrap().to_string()) { 102 | Ok(content) => content, 103 | Err(_) => return Err(mod_path.as_path().to_str().unwrap().to_string()), 104 | }; 105 | 106 | let content = Self::sanitize_content(&content); 107 | 108 | Ok(Self { 109 | file_path, 110 | mod_path, 111 | content, 112 | }) 113 | } 114 | 115 | // This function Remove all the comments 116 | // Then replace the lines containing only whitespaces and tabs with a newline 117 | // And append a \n at the end of file to avoid out of bounds error as the parser requires 118 | // a newline at the end of the file 119 | fn sanitize_content(content: &str) -> String { 120 | let without_comments = Regex::new(r#"#.*\n"#).unwrap().replace_all(content, "\n"); 121 | 122 | Regex::new(r"[ \t]+\n") 123 | .unwrap() 124 | .replace_all(&without_comments, "\n\n") 125 | .to_string() 126 | + "\n" 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/lib/parser/span.rs: -------------------------------------------------------------------------------- 1 | use crate::parser::Parser; 2 | use std::path::PathBuf; 3 | 4 | #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] 5 | pub struct Span { 6 | pub file_path: PathBuf, 7 | pub start: usize, 8 | pub end: usize, 9 | } 10 | 11 | impl Span { 12 | pub fn new(file_path: PathBuf, start: usize, end: usize) -> Self { 13 | Self { 14 | start, 15 | end, 16 | file_path, 17 | } 18 | } 19 | 20 | pub fn new_placeholder() -> Self { 21 | Self { 22 | start: 0, 23 | end: 0, 24 | file_path: PathBuf::new(), 25 | } 26 | } 27 | } 28 | 29 | impl<'a> From> for Span { 30 | fn from(source: Parser<'a>) -> Self { 31 | Self { 32 | start: source.location_offset(), 33 | end: source.to_string().len() + source.location_offset(), 34 | file_path: source.extra.current_file_path().clone(), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/lib/resolver/mod.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::{ 4 | ast::tree::{IdentifierPath, Root}, 5 | diagnostics::Diagnostic, 6 | helpers::scopes::Scopes, 7 | infer::trait_solver::TraitSolver, 8 | parser::ParsingCtx, 9 | }; 10 | 11 | mod resolution_map; 12 | mod resolve_ctx; 13 | mod unused_collector; 14 | 15 | pub use resolution_map::*; 16 | pub use resolve_ctx::*; 17 | 18 | pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diagnostic> { 19 | let mut scopes = HashMap::new(); 20 | 21 | scopes.insert(IdentifierPath::new_root(), Scopes::new()); 22 | 23 | let (resolutions, trait_solver) = { 24 | let mut ctx = ResolveCtx { 25 | parsing_ctx, 26 | scopes, 27 | cur_scope: IdentifierPath::new_root(), 28 | resolutions: ResolutionMap::default(), 29 | trait_solver: TraitSolver::new(), 30 | }; 31 | 32 | ctx.run(root); 33 | 34 | (ctx.resolutions, ctx.trait_solver) 35 | }; 36 | 37 | root.resolutions = resolutions; 38 | root.trait_solver = trait_solver; 39 | 40 | let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); 41 | 42 | for unused_fn in &unused_fns { 43 | let span = parsing_ctx.identities.get(unused_fn).unwrap(); 44 | 45 | parsing_ctx 46 | .diagnostics 47 | .push_warning(Diagnostic::new_unused_function(span.clone())); 48 | } 49 | 50 | unused_fns.extend(unused_methods); 51 | 52 | parsing_ctx.return_if_error() 53 | } 54 | -------------------------------------------------------------------------------- /src/lib/resolver/resolution_map.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; 4 | 5 | #[derive(Clone, Default, Debug, Serialize, Deserialize)] 6 | pub struct ResolutionMap(HashMap) 7 | where 8 | T: Eq + Clone + std::hash::Hash + Default; 9 | 10 | impl ResolutionMap { 11 | pub fn new() -> Self { 12 | ResolutionMap(HashMap::new()) 13 | } 14 | 15 | pub fn insert(&mut self, pointer_id: T, pointee_id: T) { 16 | if self.0.insert(pointer_id, pointee_id).is_some() { 17 | debug!("Overriding resolution"); 18 | } 19 | } 20 | 21 | pub fn get(&self, pointer_id: &T) -> Option { 22 | self.0.get(pointer_id).cloned() 23 | } 24 | 25 | pub fn get_recur(&self, pointer_id: &T) -> Option { 26 | self.get(pointer_id).and_then(|pointee_id| { 27 | if *pointer_id == pointee_id { 28 | warn!("Resolution loop"); 29 | 30 | Some(pointee_id) 31 | } else { 32 | self.get_recur(&pointee_id).or(Some(pointee_id)) 33 | } 34 | }) 35 | } 36 | 37 | pub fn get_map(&self) -> HashMap { 38 | self.0.clone() 39 | } 40 | 41 | #[allow(dead_code)] 42 | pub fn clear(&mut self) { 43 | self.0.clear() 44 | } 45 | 46 | pub fn remove(&mut self, item: &T) { 47 | self.0.remove(item); 48 | } 49 | 50 | pub fn extend(&mut self, other: Self) { 51 | self.0.extend(other.0); 52 | } 53 | 54 | pub fn inner(&self) -> &HashMap { 55 | &self.0 56 | } 57 | } 58 | 59 | impl ResolutionMap { 60 | pub fn lower_resolution_map(&self, hir_map: &HirMap) -> ResolutionMap { 61 | ResolutionMap( 62 | self.0 63 | .iter() 64 | // FIXME: Code smell, we silently delete unknown references 65 | .filter_map(|(k, v)| Some((hir_map.get_hir_id(*k)?, hir_map.get_hir_id(*v)?))) 66 | .collect(), 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/lib/resolver/unused_collector.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::{ 4 | ast::{tree::*, visit::*, NodeId}, 5 | resolver::ResolutionMap, 6 | }; 7 | 8 | #[derive(Debug, Default)] 9 | pub struct UnusedCollector { 10 | resolutions: ResolutionMap, 11 | fn_list: HashMap, 12 | method_list: HashMap, 13 | } 14 | 15 | impl UnusedCollector { 16 | pub fn new(resolutions: ResolutionMap) -> Self { 17 | Self { 18 | resolutions, 19 | ..Default::default() 20 | } 21 | } 22 | 23 | // (fns, methods) 24 | pub fn take_unused(self) -> (Vec, Vec) { 25 | ( 26 | self.fn_list 27 | .into_iter() 28 | .filter_map(|(id, used)| if !used { Some(id + 1) } else { None }) // +1 to get the 29 | // fn identifier's node_id, as it always follows the fn node_id 30 | .collect(), 31 | self.method_list 32 | .into_iter() 33 | .filter_map(|(id, used)| if !used { Some(id) } else { None }) 34 | .collect(), 35 | ) 36 | } 37 | } 38 | 39 | impl<'a> Visitor<'a> for UnusedCollector { 40 | fn visit_mod(&mut self, m: &'a Mod) { 41 | // We add every top level first 42 | 43 | for top in &m.top_levels { 44 | match &top { 45 | TopLevel::Extern(_p) => {} 46 | TopLevel::FnSignature(_p) => {} 47 | TopLevel::Use(_u) => (), 48 | TopLevel::Trait(t) => { 49 | for f in &t.defs { 50 | self.method_list.insert(f.node_id, false); 51 | } 52 | } 53 | TopLevel::Impl(_i) => {} 54 | TopLevel::Struct(_s) => {} 55 | TopLevel::Mod(_, _m) => (), 56 | TopLevel::Infix(_, _) => (), 57 | TopLevel::Function(f) => { 58 | self.fn_list.insert(f.node_id, false); 59 | 60 | if f.name.name == *"main" { 61 | self.fn_list.insert(f.node_id, true); 62 | } 63 | } 64 | } 65 | } 66 | 67 | walk_list!(self, visit_top_level, &m.top_levels); 68 | } 69 | 70 | fn visit_top_level(&mut self, top_level: &'a TopLevel) { 71 | match &top_level { 72 | TopLevel::Extern(p) => self.visit_prototype(p), 73 | TopLevel::FnSignature(p) => self.visit_prototype(p), 74 | TopLevel::Use(_u) => (), 75 | TopLevel::Trait(t) => self.visit_trait(t), 76 | TopLevel::Impl(i) => self.visit_impl(i), 77 | TopLevel::Struct(i) => self.visit_struct_decl(i), 78 | TopLevel::Mod(name, m) => { 79 | self.visit_identifier(name); 80 | self.visit_mod(m); 81 | } 82 | TopLevel::Function(f) => self.visit_function_decl(f), 83 | TopLevel::Infix(_ident, _) => (), 84 | }; 85 | } 86 | 87 | fn visit_prototype(&mut self, prototype: &'a Prototype) { 88 | self.visit_func_type(&prototype.signature); 89 | } 90 | 91 | fn visit_function_decl(&mut self, f: &'a FunctionDecl) { 92 | walk_list!(self, visit_identifier, &f.arguments); 93 | 94 | self.visit_body(&f.body); 95 | } 96 | 97 | fn visit_identifier(&mut self, id: &'a Identifier) { 98 | if let Some(reso) = self.resolutions.get_recur(&id.node_id) { 99 | if let Some(used) = self.fn_list.get_mut(&reso) { 100 | *used = true; 101 | } else if let Some(used) = self.method_list.get_mut(&reso) { 102 | *used = true; 103 | } 104 | } 105 | } 106 | } 107 | 108 | pub fn collect_unused(root: &Root) -> (Vec, Vec) { 109 | let mut unused_collector = UnusedCollector::new(root.resolutions.clone()); 110 | 111 | unused_collector.visit_root(root); 112 | 113 | unused_collector.take_unused() 114 | } 115 | -------------------------------------------------------------------------------- /src/lib/rock.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate serde_derive; 3 | 4 | #[macro_use] 5 | extern crate lazy_static; 6 | 7 | #[macro_use] 8 | extern crate log; 9 | 10 | #[macro_use] 11 | extern crate nom_locate; 12 | 13 | use std::path::PathBuf; 14 | 15 | #[macro_use] 16 | mod helpers; 17 | 18 | #[macro_use] 19 | mod ast; 20 | #[macro_use] 21 | mod infer; 22 | 23 | mod ast_lowering; 24 | mod codegen; 25 | pub mod diagnostics; 26 | mod hir; 27 | mod parser; 28 | mod resolver; 29 | mod tests; 30 | mod ty; 31 | 32 | use diagnostics::Diagnostic; 33 | pub use helpers::config::Config; 34 | use parser::{ParsingCtx, SourceFile}; 35 | 36 | pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { 37 | let mut source_file = SourceFile::from_file(in_name)?; 38 | 39 | if config.std { 40 | source_file.content = "mod std\nuse std::prelude::(*)\n".to_owned() + &source_file.content; 41 | } 42 | 43 | source_file.mod_path = PathBuf::from("root"); 44 | 45 | compile_str(&source_file, config) 46 | } 47 | 48 | pub fn compile_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic> { 49 | let mut parsing_ctx = ParsingCtx::new(config); 50 | 51 | parsing_ctx.add_file(input); 52 | 53 | let hir = parse_str(&mut parsing_ctx, config)?; 54 | 55 | generate_ir(hir, config)?; 56 | 57 | parsing_ctx.print_success_diagnostics(); 58 | 59 | Ok(()) 60 | } 61 | 62 | pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { 63 | // Text to Ast 64 | debug!(" -> Parsing"); 65 | let mut ast = parser::parse(parsing_ctx)?; 66 | 67 | // Name resolving 68 | debug!(" -> Resolving"); 69 | resolver::resolve(&mut ast, parsing_ctx)?; 70 | 71 | // Lowering to HIR 72 | debug!(" -> Lowering to HIR"); 73 | let mut hir = ast_lowering::lower_crate(&ast); 74 | 75 | // Infer Hir 76 | debug!(" -> Infer HIR"); 77 | let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; 78 | 79 | Ok(new_hir) 80 | } 81 | 82 | pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { 83 | // Generate code 84 | debug!(" -> Lower to LLVM IR"); 85 | codegen::generate(config, hir)?; 86 | 87 | Ok(()) 88 | } 89 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/0_arg_fn/main.rk: -------------------------------------------------------------------------------- 1 | f: -> 42 2 | main: -> f() 3 | 4 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/0_arg_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/0_arg_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/0_arg_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/1_arg_fn/main.rk: -------------------------------------------------------------------------------- 1 | f: a -> a 2 | main: -> f 42 3 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/1_arg_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/1_arg_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/1_arg_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/2_arg_fn/main.rk: -------------------------------------------------------------------------------- 1 | f: a, b -> ~IAdd a b 2 | main: -> f 20, 22 3 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/2_arg_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/2_arg_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/2_arg_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/array/main.rk: -------------------------------------------------------------------------------- 1 | id: a -> [a, 2] 2 | duo: a, b -> [a, b] 3 | main: -> 4 | let a = id 1 5 | let b = duo 2.2, 3.3 6 | 42 7 | 8 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/array/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/array/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/array/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_false/main.rk: -------------------------------------------------------------------------------- 1 | main: -> false 2 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_false/main.rk.out: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_false/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/bool_false/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_true/main.rk: -------------------------------------------------------------------------------- 1 | main: -> true 2 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_true/main.rk.out: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /src/lib/testcases/basic/bool_true/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/bool_true/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/deep_monomorph/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/deep_monomorph/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/dot_assign/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | foo: Int64 3 | 4 | main: -> 5 | let inst = Foo 6 | foo: 5 7 | 8 | inst.foo = 42 9 | 10 | inst.foo 11 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/dot_assign/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/dot_assign/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/dot_assign/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/early_return/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | let a = 42 3 | return a 4 | 28 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/early_return/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/early_return/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/early_return/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/escaped_string/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | let str = "He\rl\'l\no, W\\or\"ld\0!n" 3 | 42 4 | 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/escaped_string/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/escaped_string/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/escaped_string/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/extern/main.rk: -------------------------------------------------------------------------------- 1 | extern puts: String => Int64 2 | 3 | main: -> puts "hello" 4 | 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/extern/main.rk.out: -------------------------------------------------------------------------------- 1 | 6 -------------------------------------------------------------------------------- /src/lib/testcases/basic/extern/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/extern/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg/main.rk: -------------------------------------------------------------------------------- 1 | func: a -> a 2 | exec: f, a -> f a 3 | main: -> exec func, 42 4 | 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/fn_arg/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg_array/main.rk: -------------------------------------------------------------------------------- 1 | x: a -> a[0] 2 | 3 | exec: f, a -> f a 4 | 5 | main: -> 6 | exec x, [2.2, 3.3] 7 | exec x, [42, 2] 8 | 9 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg_array/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_arg_array/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/fn_arg_array/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_generic_sig/main.rk: -------------------------------------------------------------------------------- 1 | f: a => a => Int64 2 | f: x, y -> x 3 | main: -> f 42, 42 4 | 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_generic_sig/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_generic_sig/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/fn_generic_sig/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_sig/main.rk: -------------------------------------------------------------------------------- 1 | f: Int64 => Int64 => Int64 2 | f: x, y -> x 3 | main: -> f 42, 42 4 | 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_sig/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/fn_sig/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/fn_sig/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/if_else/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | if true 3 | then 42 4 | else 43 5 | 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/if_else/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/if_else/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/if_else/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/impl_self/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | bar: Int64 3 | 4 | impl Foo 5 | @getbar: -> @bar 6 | @me: -> @ 7 | 8 | main: -> 9 | let foo = Foo 10 | bar: 42 11 | 12 | foo.me().getbar() 13 | 14 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/impl_self/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/impl_self/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/impl_self/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/indice_assign/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | let a = [2, 3] 3 | a[0] = 42 4 | a[0] 5 | 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/indice_assign/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/indice_assign/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/indice_assign/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/let/main.rk: -------------------------------------------------------------------------------- 1 | id: d -> d 2 | main: -> 3 | let a = 41 4 | let b = 1 5 | let c = ~IAdd a b 6 | id c 7 | 8 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/let/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/let/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/let/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/main/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 42 2 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/main/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/main/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/main/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph/main.rk: -------------------------------------------------------------------------------- 1 | id: a -> a 2 | 3 | main: -> 4 | id true 5 | id 42 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/monomorph/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph_in_trait/main.rk: -------------------------------------------------------------------------------- 1 | id: a -> a 2 | 3 | trait Foo 4 | @foo: @ 5 | 6 | impl Foo Int64 7 | @foo: -> id @ 8 | 9 | impl Foo Bool 10 | @foo: -> id @ 11 | 12 | main: -> 13 | true.foo() 14 | (42).foo() 15 | 16 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph_in_trait/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/monomorph_in_trait/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/monomorph_in_trait/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/multi_style_struct_ctor/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | bar: Int64 3 | bar2: String 4 | main: -> 5 | let foo = Foo bar: 42, bar2: "hello" 6 | let foo2 = 7 | Foo 8 | bar: 3 9 | bar2: "world" 10 | let foo3 = Foo 11 | bar: 4 12 | bar2: "world2" 13 | foo.bar 14 | 15 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/multi_style_struct_ctor/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/multi_style_struct_ctor/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/multi_style_struct_ctor/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/multiline_struct_const/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | toto: Int64 3 | titi: Float64 4 | 5 | main: -> 6 | let lol = Foo 7 | toto: 42 8 | titi: 10.2 9 | 10 | lol.toto 11 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/multiline_struct_const/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/multiline_struct_const/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/multiline_struct_const/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/0_arg_fn/main.rk: -------------------------------------------------------------------------------- 1 | f: -> 42 2 | main: -> f() 3 | 4 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/0_arg_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/0_arg_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/negative_floats/0_arg_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/main.rk: -------------------------------------------------------------------------------- 1 | infix + 5 2 | infix - 5 3 | infix * 4 4 | infix == 3 5 | +: a, b -> ~FAdd a b 6 | -: a, b -> ~FSub a b 7 | *: a, b -> ~FMul a b 8 | ==: a, b -> ~FEq a b 9 | f: -> -42.0 10 | main: -> 11 | if f() * -1.0 + 1.0 - 1.0 == 42.0 12 | then 42 13 | else 0 14 | 15 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_floats/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/negative_floats/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/0_arg_fn/main.rk: -------------------------------------------------------------------------------- 1 | f: -> 42 2 | main: -> f() 3 | 4 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/0_arg_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/0_arg_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/negative_numbers/0_arg_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/main.rk: -------------------------------------------------------------------------------- 1 | infix + 5 2 | infix - 5 3 | infix * 4 4 | +: a, b -> ~IAdd a b 5 | -: a, b -> ~ISub a b 6 | *: a, b -> ~IMul a b 7 | f: -> -42 8 | main: -> f() * -1 + 1 - 1 9 | 10 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/negative_numbers/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/negative_numbers/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_array/main.rk: -------------------------------------------------------------------------------- 1 | main: -> [[12, 24], [42, 0]][1][0] 2 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_array/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_array/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/nested_array/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct/main.rk: -------------------------------------------------------------------------------- 1 | struct Bar 2 | toto: Int64 3 | 4 | struct Foo 5 | bar: Bar 6 | 7 | struct Toto 8 | foo: Foo 9 | 10 | main: -> 11 | let b = Bar 12 | toto: 42 13 | 14 | let a = Foo 15 | bar: b 16 | 17 | let lol = Toto 18 | foo: a 19 | 20 | lol.foo.bar.toto 21 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/nested_struct/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct_dect_multiline/main.rk: -------------------------------------------------------------------------------- 1 | struct Bar 2 | mdr: Int64 3 | 4 | struct Foo 5 | toto: Bar 6 | titi: Float64 7 | 8 | main: -> 9 | let lol = Foo 10 | toto: Bar 11 | mdr: 42 12 | titi: 10.2 13 | 14 | lol.toto.mdr 15 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/no_newline_end/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | 42 3 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/no_newline_end/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/no_newline_end/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/no_newline_end/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/op_func/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | +: a, b -> ~IAdd a b 3 | add: a, b -> a + b 4 | main: -> add 20, 22 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/op_func/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/op_func/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/op_func/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/operator_precedence/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix - 4 3 | infix * 5 4 | infix / 5 5 | 6 | +: a, b -> ~IAdd a b 7 | -: a, b -> ~ISub a b 8 | *: a, b -> ~IMul a b 9 | /: a, b -> ~IDiv a b 10 | main: -> 3 + 20 / 2 * 2 * 2 - 2 + 1 11 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/operator_precedence/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/operator_precedence/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/operator_precedence/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign/main.rk: -------------------------------------------------------------------------------- 1 | id: a -> a 2 | main: -> 3 | let a = id 2 4 | a = id 42 5 | a 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/reassign/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_return/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | +: a, b -> ~IAdd a b 3 | 4 | main: -> 5 | let i = 21 6 | i = i + 21 7 | i 8 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_return/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_return/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/reassign_return/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_self/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | let a = 21 3 | a = ~IAdd a a 4 | a 5 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_self/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/reassign_self/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/reassign_self/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/recur/main.rk: -------------------------------------------------------------------------------- 1 | infix - 4 2 | -: a, b -> ~ISub a b 3 | 4 | infix == 4 5 | ==: a, b -> ~IEq a b 6 | 7 | recur: a -> 8 | if a == 0 9 | then a 10 | else recur (a - 1) 11 | 12 | main: -> recur 2 13 | 14 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/recur/main.rk.out: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /src/lib/testcases/basic/recur/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/recur/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/self_returning_fn/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | +: a, b -> ~IAdd a b 3 | 4 | struct Foo 5 | bar: Int64 6 | 7 | impl Foo 8 | new: -> Foo bar: 40 9 | @inc: @-> @bar = @bar + 1 10 | 11 | main: -> 12 | Foo::new!.inc!.inc!.bar 13 | 14 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/self_returning_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/self_returning_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/self_returning_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_char/main.rk: -------------------------------------------------------------------------------- 1 | main: -> 2 | let a = 'a' 3 | let star = '*' 4 | let bn = '\n' 5 | star 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_char/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_char/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/simple_char/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_struct/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | bar: Int64 3 | toto: String 4 | 5 | main: -> 42 6 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_struct/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/simple_struct/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/simple_struct/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/spaced_dot/main.rk: -------------------------------------------------------------------------------- 1 | struct Toto 2 | lol: Int64 3 | 4 | impl Toto 5 | new: x -> Toto 6 | lol: x 7 | @me: -> @ 8 | @get: a -> @lol 9 | 10 | main: -> 11 | Toto::new 42 .me!.me!.get 2 12 | Toto::new 42 13 | .me! 14 | .me! 15 | .get 2 16 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/spaced_dot/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/spaced_dot/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/spaced_dot/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/string_index/main.rk: -------------------------------------------------------------------------------- 1 | f: -> "hell* world" 2 | main: -> f![4] 3 | 4 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/string_index/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/string_index/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/string_index/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_array_field/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | toto: [Int64] 3 | titi: Float64 4 | 5 | main: -> 6 | let lol = Foo 7 | titi: 10.2 8 | toto: [10, 42] 9 | 10 | lol.toto[1] 11 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_array_field/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_array_field/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/struct_array_field/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_impl/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | bar: Int64 3 | toto: String 4 | 5 | impl Foo 6 | new: a -> 7 | Foo 8 | bar: a 9 | toto: "Default" 10 | @getbar: -> @bar 11 | 12 | main: -> 13 | let foo = Foo::new 42 14 | foo.getbar! 15 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_impl/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_impl/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/struct_impl/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_index/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | bar: Int64 3 | toto: String 4 | 5 | main: -> 6 | let a = Foo 7 | bar: 42 8 | toto: "lol" 9 | let b = a.bar 10 | b 11 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_index/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/struct_index/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/struct_index/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_monomorph/main.rk: -------------------------------------------------------------------------------- 1 | trait Toto 2 | @toto: String 3 | 4 | impl Toto Int64 5 | @toto: -> "1" 6 | 7 | impl Toto Bool 8 | @toto: -> "true" 9 | 10 | print: a -> a.toto() 11 | 12 | main: -> 13 | print true 14 | print 4 15 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_monomorph/main.rk.out: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_monomorph/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/trait_monomorph/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_use_before_decl/main.rk: -------------------------------------------------------------------------------- 1 | puts: a -> a 2 | 3 | struct Bar 4 | toto: Int64 5 | mdr: String 6 | 7 | trait Show 8 | @show: String 9 | 10 | impl Show Int64 11 | @show: -> "2" 12 | 13 | print: a -> puts a.show() 14 | 15 | impl Show Bar 16 | @show: -> 17 | @toto.show() 18 | 19 | main: -> 20 | let bar = Bar 21 | toto: 42 22 | mdr: "haha" 23 | 24 | print bar 25 | 26 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_use_before_decl/main.rk.out: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /src/lib/testcases/basic/trait_use_before_decl/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/trait_use_before_decl/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/basic/while/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | +: a, b -> ~IAdd a b 3 | 4 | infix < 3 5 | <: a, b -> ~Ilt a b 6 | 7 | main: -> 8 | let i = 0 9 | let x = 42 10 | while i < x 11 | i = i + 1 12 | i 13 | -------------------------------------------------------------------------------- /src/lib/testcases/basic/while/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/basic/while/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/basic/while/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg/main.rk: -------------------------------------------------------------------------------- 1 | f: Int64 => Float64 2 | f: a -> a 3 | 4 | main: -> f 2.2 5 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk: -------------------------------------------------------------------------------- 1 | f a = a 2 | 3 | main = f 2, 2 4 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk: -------------------------------------------------------------------------------- 1 | f: a, b -> a 2 | 3 | main: -> f 2 4 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_orpheline_sig/main.rk: -------------------------------------------------------------------------------- 1 | d: a => a 2 | 3 | f: Int64 => Float64 4 | f: a -> a 5 | 6 | main: -> f 2.2 7 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_orpheline_sig/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_orpheline_sig/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/fn_orpheline_sig/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_sig/main.rk: -------------------------------------------------------------------------------- 1 | f: Int64 => Float64 2 | f: a -> a 3 | 4 | main: -> f 2.2 5 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_sig/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/fn_sig/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/fn_sig/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/struct_bad_field_type/main.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | toto: Int64 3 | titi: Float64 4 | 5 | main: -> 6 | let lol = 7 | Foo 8 | toto: 10.2 9 | titi: 10.2 10 | 11 | lol.toto 12 | -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.out: -------------------------------------------------------------------------------- 1 | -1 -------------------------------------------------------------------------------- /src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/basic_mod/_std.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix * 5 3 | 4 | trait Num 5 | +: @ => @ => @ 6 | *: @ => @ => @ 7 | 8 | impl Num Int64 9 | +: a, b -> ~IAdd a b 10 | *: a, b -> ~IMul a b 11 | 12 | impl Num Float64 13 | +: c, d -> ~FAdd c d 14 | *: c, d -> ~FMul c d 15 | 16 | use Num::(*) 17 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/basic_mod/main.rk: -------------------------------------------------------------------------------- 1 | mod _std 2 | 3 | use _std::(*) 4 | 5 | test: g, h, i, j -> g 6 | 7 | main: -> test (41 + 1), (2 * 2), (3.3 + 3.3), (4.4 * 4.4) 8 | 9 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/basic_mod/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/basic_mod/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/basic_mod/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/build/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/build/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/full_fact/main.rk: -------------------------------------------------------------------------------- 1 | mod std 2 | 3 | use std::prelude::(*) 4 | 5 | fact: a -> 6 | if a <= 1 7 | then 1 8 | else a * fact (a - 1) 9 | 10 | main: -> fact 4 11 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/full_fact/main.rk.out: -------------------------------------------------------------------------------- 1 | 24 -------------------------------------------------------------------------------- /src/lib/testcases/mods/full_fact/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/full_fact/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/func_arg_resolution/_std.rk: -------------------------------------------------------------------------------- 1 | infix |> 1 2 | infix + 4 3 | 4 | |>: a, b -> b a 5 | +: a, b -> ~IAdd a b 6 | 7 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/func_arg_resolution/main.rk: -------------------------------------------------------------------------------- 1 | mod _std 2 | 3 | use _std::(*) 4 | 5 | f: a -> a + 2 6 | 7 | main: -> 40 |> f 8 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/func_arg_resolution/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/func_arg_resolution/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/func_arg_resolution/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/nested_trait_resolution/_std.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix |> 1 3 | 4 | # Helpers 5 | |>: a, b -> b a 6 | 7 | ## Num 8 | trait Num 9 | +: @ => @ => @ 10 | 11 | impl Num Int64 12 | +: a, b -> ~IAdd a b 13 | 14 | use Num::(*) 15 | 16 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/nested_trait_resolution/main.rk: -------------------------------------------------------------------------------- 1 | mod _std 2 | 3 | use _std::(*) 4 | 5 | f: a -> a + 2 6 | main: -> 40 |> f 7 | 8 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/nested_trait_resolution/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/nested_trait_resolution/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/nested_trait_resolution/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/struct_new/lib.rk: -------------------------------------------------------------------------------- 1 | struct Foo 2 | i: Int64 3 | s: String 4 | 5 | new_foo: str -> 6 | Foo 7 | i: 42 8 | s: str 9 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/struct_new/main.rk: -------------------------------------------------------------------------------- 1 | mod lib 2 | 3 | use lib::(*) 4 | 5 | main: -> 6 | let foo = new_foo "bar" 7 | foo.i 8 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/struct_new/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/struct_new/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/struct_new/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_fn/_std.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix * 5 3 | infix - 4 4 | 5 | +: a, b -> ~IAdd a b 6 | *: a, b -> ~IMul a b 7 | -: a, b -> ~ISub a b 8 | 9 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_fn/main.rk: -------------------------------------------------------------------------------- 1 | mod _std 2 | 3 | use _std::(*) 4 | 5 | test: g, h -> g 6 | 7 | main: -> test (41 + 1), (2 * 2) 8 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/unused_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_impl_fn/_std.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix * 5 3 | infix - 4 4 | 5 | trait Num 6 | +: @ => @ => @ 7 | *: @ => @ => @ 8 | -: @ => @ => @ 9 | 10 | impl Num Int64 11 | +: a, b -> ~IAdd a b 12 | *: a, b -> ~IMul a b 13 | -: a, b -> ~ISub a b 14 | 15 | impl Num Float64 16 | +: c, d -> ~FAdd c d 17 | *: c, d -> ~FMul c d 18 | -: c, d -> ~FSub c d 19 | 20 | use Num::(*) 21 | 22 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_impl_fn/main.rk: -------------------------------------------------------------------------------- 1 | mod _std 2 | 3 | use _std::(*) 4 | 5 | test: g, h, i, j -> g 6 | 7 | main: -> test (41 + 1), (2 * 2), 3, 4 8 | -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_impl_fn/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/mods/unused_impl_fn/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/mods/unused_impl_fn/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/test_template: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn {name}() {{ 3 | run("{path}", include_str!("{path}"), include_str!("{path}.out"), include_str!("{path}.stdout")); 4 | }} 5 | -------------------------------------------------------------------------------- /src/lib/testcases/tests_loader.rs: -------------------------------------------------------------------------------- 1 | // include tests generated by `build.rs`, one test per directory in tests/data 2 | include!("../src/lib/tests.rs"); 3 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/build/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/build/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method/main.rk: -------------------------------------------------------------------------------- 1 | trait Test 2 | @test: -> @ 3 | 4 | impl Test Int64 5 | 6 | main: -> (42).test! 7 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/default_method/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method_override/main.rk: -------------------------------------------------------------------------------- 1 | trait Test 2 | @test: -> @ 3 | 4 | impl Test Int64 5 | @test: -> 42 6 | 7 | main: -> (21).test! 8 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method_override/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/trait/default_method_override/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/default_method_override/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/trait/late_resolution/main.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | 3 | trait Num 4 | +: @ => @ => @ 5 | 6 | impl Num Int64 7 | +: a, b -> ~IAdd a b 8 | 9 | use Num::(*) 10 | 11 | add: a, b -> a + b 12 | 13 | main: -> add 2, 40 14 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/late_resolution/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/trait/late_resolution/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/late_resolution/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/trait/multi_resolution/main.rk: -------------------------------------------------------------------------------- 1 | extern puts: String => Int64 2 | 3 | infix == 3 4 | 5 | trait Eq 6 | ==: @ => @ => Bool 7 | 8 | impl Eq Int64 9 | ==: e, f -> ~IEq e f 10 | 11 | impl Eq Bool 12 | ==: i, j -> ~BEq i j 13 | 14 | use Eq::(*) 15 | 16 | trait Print 17 | @print: Int64 18 | 19 | impl Print Bool 20 | @print: -> 21 | if @ 22 | then puts "true" 23 | else puts "false" 24 | 25 | mdr: a, b -> a == b 26 | mdr2: a, b -> a == b 27 | lol: a, b -> mdr a, b == mdr2 2, 2 28 | 29 | main: -> lol(2, 2).print() 30 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/multi_resolution/main.rk.out: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /src/lib/testcases/trait/multi_resolution/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/multi_resolution/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/testcases/trait/nested_fn_sig/main.rk: -------------------------------------------------------------------------------- 1 | trait MyTrait 2 | @my_func: (@ => a) => a 3 | 4 | impl MyTrait Int64 5 | @my_func: f -> f @ 6 | 7 | handler: x -> x 8 | 9 | main: -> (42).my_func handler 10 | -------------------------------------------------------------------------------- /src/lib/testcases/trait/nested_fn_sig/main.rk.out: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /src/lib/testcases/trait/nested_fn_sig/main.rk.stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Champii/Rock/72cf7b755460920e106b2243573ca2dd1767d9a2/src/lib/testcases/trait/nested_fn_sig/main.rk.stdout -------------------------------------------------------------------------------- /src/lib/ty/mod.rs: -------------------------------------------------------------------------------- 1 | mod func_type; 2 | mod primitive_type; 3 | mod struct_type; 4 | mod r#type; 5 | 6 | pub use func_type::*; 7 | pub use primitive_type::*; 8 | pub use r#type::*; 9 | pub use struct_type::*; 10 | -------------------------------------------------------------------------------- /src/lib/ty/primitive_type.rs: -------------------------------------------------------------------------------- 1 | use super::Type; 2 | 3 | #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] 4 | pub enum PrimitiveType { 5 | Void, 6 | Bool, 7 | Int8, 8 | Int16, 9 | Int32, 10 | Int64, 11 | Float64, 12 | String, 13 | Array(Box, usize), 14 | Char, 15 | } 16 | 17 | impl PrimitiveType { 18 | pub fn is_solved(&self) -> bool { 19 | if let PrimitiveType::Array(t, _) = self { 20 | t.is_solved() 21 | } else { 22 | true 23 | } 24 | } 25 | 26 | pub fn get_name(&self) -> String { 27 | match self { 28 | Self::Void => "Void".to_string(), 29 | Self::Bool => "Bool".to_string(), 30 | Self::Int8 => "Int8".to_string(), 31 | Self::Int16 => "Int16".to_string(), 32 | Self::Int32 => "Int32".to_string(), 33 | Self::Int64 => "Int64".to_string(), 34 | Self::Float64 => "Float64".to_string(), 35 | Self::String => "String".to_string(), 36 | Self::Array(t, _size) => format!("[{}]", t.get_name()), 37 | Self::Char => "Char".to_string(), 38 | } 39 | } 40 | 41 | pub fn from_name(s: &str) -> Option { 42 | match s { 43 | "Void" => Some(Self::Void), 44 | "Bool" => Some(Self::Bool), 45 | "Int8" => Some(Self::Int8), 46 | "Int16" => Some(Self::Int16), 47 | "Int32" => Some(Self::Int32), 48 | "Int64" => Some(Self::Int64), 49 | "Float64" => Some(Self::Float64), 50 | "String" => Some(Self::String), 51 | "Char" => Some(Self::Char), 52 | _ => None, 53 | } 54 | } 55 | 56 | pub fn is_bool(&self) -> bool { 57 | matches!(self, PrimitiveType::Bool) 58 | } 59 | 60 | pub fn is_int8(&self) -> bool { 61 | matches!(self, PrimitiveType::Int8) 62 | } 63 | 64 | pub fn is_int16(&self) -> bool { 65 | matches!(self, PrimitiveType::Int16) 66 | } 67 | 68 | pub fn is_int32(&self) -> bool { 69 | matches!(self, PrimitiveType::Int32) 70 | } 71 | 72 | pub fn is_int64(&self) -> bool { 73 | matches!(self, PrimitiveType::Int64) 74 | } 75 | 76 | pub fn is_float64(&self) -> bool { 77 | matches!(self, PrimitiveType::Float64) 78 | } 79 | 80 | pub fn is_string(&self) -> bool { 81 | matches!(self, PrimitiveType::String) 82 | } 83 | 84 | pub fn is_array(&self) -> bool { 85 | matches!(self, PrimitiveType::Array(_, _)) 86 | } 87 | 88 | pub fn is_char(&self) -> bool { 89 | matches!(self, PrimitiveType::Char) 90 | } 91 | 92 | pub fn try_as_array(&self) -> Option<(Type, usize)> { 93 | if let PrimitiveType::Array(t, s) = self { 94 | Some((*t.clone(), *s)) 95 | } else { 96 | None 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/lib/ty/struct_type.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::BTreeMap, fmt}; 2 | 3 | use colored::*; 4 | 5 | use crate::{ast, hir}; 6 | 7 | use super::Type; 8 | 9 | #[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] 10 | pub struct StructType { 11 | pub name: String, 12 | pub defs: BTreeMap>, 13 | pub fields_order: Vec, 14 | } 15 | 16 | impl StructType { 17 | pub fn ordered_defs(&self) -> Vec<(String, Box)> { 18 | self.fields_order 19 | .iter() 20 | .map(|name| (name.clone(), self.defs.get(name).unwrap().clone())) 21 | .collect() 22 | } 23 | } 24 | 25 | impl fmt::Debug for StructType { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | write!( 28 | f, 29 | "{} {} {} {}", 30 | self.name.yellow(), 31 | "{".green(), 32 | self.defs 33 | .iter() 34 | .map(|(n, b)| format!("{}: {:?}", n, b)) 35 | .collect::>() 36 | .join(", "), 37 | "}".green(), 38 | ) 39 | } 40 | } 41 | 42 | impl From<&ast::tree::StructDecl> for StructType { 43 | fn from(s: &ast::tree::StructDecl) -> Self { 44 | s.into() 45 | } 46 | } 47 | 48 | impl From for StructType { 49 | fn from(s: ast::tree::StructDecl) -> Self { 50 | StructType { 51 | name: s.name.to_string(), 52 | fields_order: s.defs.iter().map(|f| f.name.to_string()).collect(), 53 | defs: s 54 | .defs 55 | .iter() 56 | .map(|proto| { 57 | if proto.signature.arguments.is_empty() { 58 | (proto.name.name.clone(), proto.signature.ret.clone()) 59 | } else { 60 | ( 61 | proto.name.name.clone(), 62 | Box::new(proto.signature.clone().into()), 63 | ) 64 | } 65 | }) 66 | .collect(), 67 | } 68 | } 69 | } 70 | 71 | impl From for StructType { 72 | fn from(s: hir::StructDecl) -> Self { 73 | StructType { 74 | name: s.name.name, 75 | fields_order: s.defs.iter().map(|f| f.name.to_string()).collect(), 76 | defs: s 77 | .defs 78 | .iter() 79 | .map(|proto| { 80 | if proto.signature.arguments.is_empty() { 81 | (proto.name.name.clone(), proto.signature.ret.clone()) 82 | } else { 83 | ( 84 | proto.name.name.clone(), 85 | Box::new(proto.signature.clone().into()), 86 | ) 87 | } 88 | }) 89 | .collect(), 90 | } 91 | } 92 | } 93 | 94 | impl StructType { 95 | // pub fn 96 | } 97 | -------------------------------------------------------------------------------- /src/lib/ty/type.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::{ast, hir}; 4 | 5 | use super::{FuncType, PrimitiveType, StructType}; 6 | 7 | #[derive(Clone, Eq, Serialize, Deserialize)] 8 | pub enum Type { 9 | Primitive(PrimitiveType), 10 | Func(FuncType), 11 | Struct(StructType), 12 | Trait(String), 13 | ForAll(String), 14 | Undefined(u64), // FIXME: To remove 15 | } 16 | 17 | impl std::hash::Hash for Type { 18 | fn hash(&self, state: &mut H) { 19 | core::mem::discriminant(self).hash(state); 20 | } 21 | } 22 | 23 | impl PartialEq for Type { 24 | fn eq(&self, other: &Type) -> bool { 25 | match self { 26 | Self::Func(func_type) => match other { 27 | Self::Func(other_func_type) => { 28 | func_type.arguments.len() == other_func_type.arguments.len() 29 | } 30 | _ => panic!("Expected func type"), 31 | }, 32 | _ => self.get_name() == other.get_name(), 33 | } 34 | } 35 | } 36 | 37 | macro_rules! generate_primitive_is_check { 38 | ($e:tt) => { 39 | pub fn $e(&self) -> bool { 40 | self.try_as_primitive_type() 41 | .map(|p| p.$e()) 42 | .unwrap_or(false) 43 | } 44 | }; 45 | } 46 | 47 | macro_rules! generate_primitive_checks { 48 | ($($e:tt),+) => { 49 | $( 50 | generate_primitive_is_check!($e); 51 | )+ 52 | }; 53 | } 54 | 55 | impl Type { 56 | pub fn int64() -> Self { 57 | Self::Primitive(PrimitiveType::Int64) 58 | } 59 | 60 | pub fn float64() -> Self { 61 | Self::Primitive(PrimitiveType::Float64) 62 | } 63 | 64 | pub fn forall(t: &str) -> Self { 65 | Self::ForAll(String::from(t)) 66 | } 67 | 68 | pub fn is_solved(&self) -> bool { 69 | match self { 70 | Type::Primitive(p) => p.is_solved(), 71 | Type::Func(ft) => ft.is_solved(), 72 | Type::Struct(_) => true, 73 | Type::Trait(_) => true, 74 | Type::ForAll(_) => false, 75 | Type::Undefined(_) => false, 76 | } 77 | } 78 | 79 | pub fn is_primitive(&self) -> bool { 80 | matches!(self, Self::Primitive(_x)) 81 | } 82 | 83 | generate_primitive_checks!( 84 | is_bool, is_int8, is_int16, is_int32, is_float64, is_string, is_array 85 | ); 86 | 87 | pub fn is_struct(&self) -> bool { 88 | matches!(self, Self::Struct(_x)) 89 | } 90 | 91 | pub fn is_trait(&self) -> bool { 92 | matches!(self, Self::Trait(_x)) 93 | } 94 | 95 | pub fn is_func(&self) -> bool { 96 | matches!(self, Self::Func(_x)) 97 | } 98 | 99 | pub fn is_forall(&self) -> bool { 100 | matches!(self, Self::ForAll(_x)) 101 | } 102 | 103 | pub fn get_name(&self) -> String { 104 | match self { 105 | Self::Primitive(p) => p.get_name(), 106 | Self::Func(f) => format!("{:?}", f), 107 | Self::Struct(s) => s.name.clone(), 108 | Self::Trait(t) => t.clone(), 109 | Self::ForAll(n) => String::from(n), 110 | Self::Undefined(s) => s.to_string(), 111 | } 112 | } 113 | 114 | pub fn as_struct_type(&self) -> StructType { 115 | if let Type::Struct(t) = self { 116 | t.clone() 117 | } else { 118 | panic!("Not a struct type"); 119 | } 120 | } 121 | 122 | pub fn as_func_type(&self) -> FuncType { 123 | if let Type::Func(f) = self { 124 | f.clone() 125 | } else { 126 | panic!("Not a func type"); 127 | } 128 | } 129 | 130 | pub fn as_primitive_type(&self) -> PrimitiveType { 131 | if let Type::Primitive(p) = self { 132 | p.clone() 133 | } else { 134 | panic!("Not a primitive"); 135 | } 136 | } 137 | 138 | pub fn try_as_struct_type(&self) -> Option { 139 | match self { 140 | Type::Struct(t) => Some(t.clone()), 141 | _ => None, 142 | } 143 | } 144 | 145 | pub fn try_as_func_type(&self) -> Option { 146 | match self { 147 | Type::Func(f) => Some(f.clone()), 148 | _ => None, 149 | } 150 | } 151 | 152 | pub fn try_as_primitive_type(&self) -> Option { 153 | match self { 154 | Type::Primitive(p) => Some(p.clone()), 155 | _ => None, 156 | } 157 | } 158 | } 159 | 160 | impl fmt::Debug for Type { 161 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 162 | use colored::Colorize; 163 | 164 | let s = match self { 165 | // Self::Primitive(p) => format!("{:?}", p), 166 | Self::Func(f) => format!("{:?}", f), 167 | Self::Struct(s) => format!("{:?}", s), 168 | Self::Trait(t) => format!("Trait {:?}", t), 169 | Self::ForAll(t) => format!("forall. {:?}", t).yellow().to_string(), 170 | Self::Undefined(t) => format!("UNDEFINED {:?}", t), 171 | _ => self.get_name().cyan().to_string(), 172 | }; 173 | 174 | write!(f, "{}", s) 175 | } 176 | } 177 | 178 | impl fmt::Display for Type { 179 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 180 | write!(f, "{}", self.get_name()) 181 | } 182 | } 183 | 184 | impl From for Type { 185 | fn from(t: PrimitiveType) -> Self { 186 | Type::Primitive(t) 187 | } 188 | } 189 | 190 | impl From for Type { 191 | fn from(t: FuncType) -> Self { 192 | Type::Func(t) 193 | } 194 | } 195 | 196 | impl From<&FuncType> for Type { 197 | fn from(t: &FuncType) -> Self { 198 | Type::Func(t.clone()) 199 | } 200 | } 201 | 202 | impl From for Type { 203 | fn from(t: StructType) -> Self { 204 | Type::Struct(t) 205 | } 206 | } 207 | 208 | impl From for Type { 209 | fn from(t: ast::StructDecl) -> Self { 210 | StructType::from(t).into() 211 | } 212 | } 213 | 214 | impl From<&ast::StructDecl> for Type { 215 | fn from(t: &ast::StructDecl) -> Self { 216 | StructType::from(t.clone()).into() 217 | } 218 | } 219 | 220 | impl From for Type { 221 | fn from(t: hir::StructDecl) -> Self { 222 | Type::Struct(t.into()) 223 | } 224 | } 225 | 226 | impl From<&hir::StructDecl> for Type { 227 | fn from(t: &hir::StructDecl) -> Self { 228 | t.clone().into() 229 | } 230 | } 231 | 232 | impl From for Type { 233 | fn from(t: String) -> Self { 234 | if t.len() == 1 && (t.chars().next().unwrap()).is_lowercase() { 235 | Type::ForAll(t) 236 | } else if t.chars().next().unwrap() == '[' { 237 | Type::Primitive(PrimitiveType::Array( 238 | Box::new(Type::from( 239 | t.trim_matches('[').trim_matches(']').to_string(), 240 | )), 241 | 0, // FIXME 242 | )) 243 | } else if PrimitiveType::from_name(&t).is_some() { 244 | Type::Primitive(PrimitiveType::from_name(&t).unwrap()) 245 | } else { 246 | Type::Trait(t) 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /std/Rock.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "std" 3 | version = "0.0.1" 4 | type = "lib" 5 | -------------------------------------------------------------------------------- /std/src/clone.rk: -------------------------------------------------------------------------------- 1 | use super::externs::malloc 2 | use super::externs::strcpy 3 | use super::externs::strlen 4 | 5 | trait Clone 6 | @clone: @ 7 | 8 | impl Clone Int64 9 | @clone: -> @ 10 | 11 | impl Clone Float64 12 | @clone: -> @ 13 | 14 | impl Clone String 15 | @clone: -> 16 | let s = malloc strlen @ 17 | strcpy s, @ 18 | s 19 | 20 | use super::functor::(*) 21 | 22 | impl Clone [Int64] 23 | @clone: -> map clone, @ 24 | 25 | -------------------------------------------------------------------------------- /std/src/eq.rk: -------------------------------------------------------------------------------- 1 | infix == 3 2 | infix <= 3 3 | infix >= 3 4 | infix < 3 5 | infix > 3 6 | 7 | trait Eq 8 | == : @ => @ => Bool 9 | <= : @ => @ => Bool 10 | >= : @ => @ => Bool 11 | < : @ => @ => Bool 12 | > : @ => @ => Bool 13 | 14 | impl Eq Int64 15 | ==: e, f -> ~IEq e f 16 | <=: e, f -> ~Ile e f 17 | >=: e, f -> ~Ige e f 18 | < : e, f -> ~Ilt e f 19 | > : e, f -> ~Igt e f 20 | 21 | impl Eq Float64 22 | ==: g, h -> ~FEq g h 23 | <=: g, h -> ~Fle g h 24 | >=: g, h -> ~Fge g h 25 | < : g, h -> ~Flt g h 26 | > : g, h -> ~Fgt g h 27 | 28 | impl Eq Bool 29 | ==: i, j -> ~BEq i j 30 | <=: i, j -> ~BEq i j 31 | >=: i, j -> ~BEq i j 32 | < : i, j -> ~BEq i j 33 | > : i, j -> ~BEq i j 34 | 35 | impl Eq Char 36 | ==: e, f -> ~IEq e f 37 | <=: e, f -> ~Ile e f 38 | >=: e, f -> ~Ige e f 39 | < : e, f -> ~Ilt e f 40 | > : e, f -> ~Igt e f 41 | 42 | use super::externs::strcmp 43 | 44 | impl Eq String 45 | ==: k, l -> strcmp k, l == 0 46 | 47 | use Eq::(*) 48 | 49 | -------------------------------------------------------------------------------- /std/src/externs.rk: -------------------------------------------------------------------------------- 1 | extern malloc: Int64 => String 2 | extern memcpy: String => String => Int64 => String 3 | 4 | # Str 5 | 6 | extern strlen: String => Int64 7 | extern strcat: String => String => String 8 | extern strcpy: String => String => String 9 | extern strncpy: String => String => Int64 => String 10 | extern strcmp: String => String => Int64 11 | extern strtol: String => Int64 => Int64 => Int64 12 | 13 | # Fs 14 | 15 | extern open: String => Int64 => Int64 => Int64 16 | extern close: Int64 => Int64 17 | extern read: Int64 => String => Int64 => Int64 18 | extern write: Int64 => String => Int64 => Int64 19 | 20 | # Print 21 | 22 | extern sprintf: String => String => Int64 => Int64 23 | extern printf: String => String => Int64 24 | extern puts: String => Int64 25 | extern fflush: Int64 => Int64 26 | 27 | # Num 28 | 29 | extern gcvt: Float64 => Int64 => String => String => String 30 | 31 | -------------------------------------------------------------------------------- /std/src/fs.rk: -------------------------------------------------------------------------------- 1 | use super::externs::malloc 2 | use super::externs::strtol 3 | 4 | use super::num::(*) 5 | use super::eq::(*) 6 | use super::show::(*) 7 | 8 | struct File 9 | fd: Int64 10 | path: String 11 | 12 | impl Show File 13 | @show: -> 14 | "File { fd: " + @fd.show! + ", path: " + @path + " }" 15 | 16 | impl File 17 | open: p -> 18 | File 19 | fd: super::externs::open p, 0, oct_to_dec "0777" 20 | path: p 21 | 22 | @read: -> 23 | let s = malloc 100 24 | let len = super::externs::read @fd, s, 100 25 | s 26 | 27 | @close: -> super::externs::close @fd 28 | 29 | oct_to_dec: oct -> strtol oct, 0, 8 30 | 31 | -------------------------------------------------------------------------------- /std/src/functor.rk: -------------------------------------------------------------------------------- 1 | use super::num::(*) 2 | use super::eq::(*) 3 | 4 | map: f, arr -> 5 | let i = 0 6 | let arr2 = arr 7 | while i < (~Len arr arr) 8 | arr2[i] = f arr[i] 9 | i = i + 1 10 | arr2 11 | 12 | foreach: f, arr -> 13 | let i = 0 14 | while i < (~Len arr arr) 15 | f arr[i] 16 | i = i + 1 17 | arr 18 | 19 | _shut_up_warnings: -> 20 | map 0, 0 21 | foreach 0, 0 22 | _shut_up_warnings! 23 | 24 | -------------------------------------------------------------------------------- /std/src/helpers.rk: -------------------------------------------------------------------------------- 1 | infix >> 2 2 | infix << 2 3 | infix |> 1 4 | 5 | >>: x, y -> y 6 | <<: x, y -> x 7 | |>: k, l -> l k 8 | 9 | _shutup_warnings: x -> 10 | 1 >> 1 11 | 1 << 1 12 | 0 |> _shutup_warnings 13 | 14 | -------------------------------------------------------------------------------- /std/src/lib.rk: -------------------------------------------------------------------------------- 1 | mod externs 2 | 3 | mod num 4 | mod eq 5 | mod show 6 | mod print 7 | mod fs 8 | mod functor 9 | mod clone 10 | mod vec 11 | mod helpers 12 | 13 | mod prelude 14 | -------------------------------------------------------------------------------- /std/src/num.rk: -------------------------------------------------------------------------------- 1 | infix + 4 2 | infix - 4 3 | infix * 5 4 | infix / 5 5 | 6 | trait Num 7 | + : @ => @ => @ 8 | - : @ => @ => @ 9 | * : @ => @ => @ 10 | / : @ => @ => @ 11 | 12 | impl Num Int64 13 | +: a, b -> ~IAdd a b 14 | -: a, b -> ~ISub a b 15 | *: a, b -> ~IMul a b 16 | /: a, b -> ~IDiv a b 17 | 18 | impl Num Float64 19 | +: c, d -> ~FAdd c d 20 | -: c, d -> ~FSub c d 21 | *: c, d -> ~FMul c d 22 | /: c, d -> ~FDiv c d 23 | 24 | impl Num Char 25 | +: a, b -> ~IAdd a b 26 | -: a, b -> ~ISub a b 27 | *: a, b -> ~IMul a b 28 | /: a, b -> ~IDiv a b 29 | 30 | use super::externs::malloc 31 | use super::externs::strlen 32 | use super::externs::strcpy 33 | use super::externs::strcat 34 | 35 | impl Num String 36 | +: a, b -> 37 | let s = malloc (strlen a + strlen b) 38 | strcpy s, a 39 | strcat s, b 40 | s 41 | 42 | use Num::(*) 43 | -------------------------------------------------------------------------------- /std/src/prelude.rk: -------------------------------------------------------------------------------- 1 | use super::num::(*) 2 | use super::eq::(*) 3 | use super::functor::(*) 4 | use super::clone::(*) 5 | use super::fs::(*) 6 | use super::vec::(*) 7 | use super::helpers::(*) 8 | -------------------------------------------------------------------------------- /std/src/print.rk: -------------------------------------------------------------------------------- 1 | use super::externs::puts 2 | use super::externs::printf 3 | use super::externs::fflush 4 | use super::show::(*) 5 | use super::eq::(*) 6 | use super::num::(*) 7 | 8 | trait Print 9 | @print: -> puts @show! 10 | @putstr: -> 11 | printf "%s", @show! 12 | fflush 0 13 | 14 | # Here we would need generic impl 15 | impl Print Bool 16 | impl Print Int64 17 | impl Print Float64 18 | impl Print String 19 | impl Print Char 20 | 21 | -------------------------------------------------------------------------------- /std/src/show.rk: -------------------------------------------------------------------------------- 1 | use super::externs::malloc 2 | use super::externs::sprintf 3 | use super::externs::gcvt 4 | use super::externs::strcpy 5 | use super::externs::strcat 6 | use super::externs::strlen 7 | use super::num::(*) 8 | use super::eq::(*) 9 | 10 | itoa: a -> 11 | let s = malloc 10 12 | sprintf s, "%d", a 13 | s 14 | 15 | ftoa: c -> 16 | gcvt c, 10, (malloc 4), (malloc 4) 17 | 18 | trait Show 19 | @show: String 20 | 21 | impl Show Int64 22 | @show: -> itoa @ 23 | 24 | impl Show Float64 25 | @show: -> ftoa @ 26 | 27 | impl Show Bool 28 | @show: -> 29 | if @ 30 | then "true" 31 | else "false" 32 | 33 | impl Show String 34 | @show: -> 35 | let s = malloc strlen @ 36 | strcpy s, @ 37 | s 38 | 39 | impl Show Char 40 | @show: -> 41 | let s = malloc 2 42 | s[0] = @ 43 | s 44 | 45 | show_arr: a -> 46 | let s = malloc 100 47 | strcpy s, "[" 48 | let i = 0 49 | let len = ~Len a a 50 | while i < len 51 | strcat s, a[i].show! 52 | strcat s, ", " 53 | i = i + 1 54 | strcat s, "]" 55 | s 56 | 57 | impl Show [Int64] 58 | @show: -> show_arr @ 59 | 60 | impl Show [Float64] 61 | @show: -> show_arr @ 62 | 63 | impl Show [String] 64 | @show: -> show_arr @ 65 | 66 | impl Show [Bool] 67 | @show: -> show_arr @ 68 | 69 | -------------------------------------------------------------------------------- /std/src/vec.rk: -------------------------------------------------------------------------------- 1 | use super::externs::(*) 2 | use super::num::(*) 3 | use super::eq::(*) 4 | 5 | struct Vec 6 | data: String 7 | cap: Int64 8 | len: Int64 9 | 10 | impl Show Vec 11 | @show: -> @len.show! 12 | 13 | impl Vec 14 | new: -> 15 | Vec 16 | data: malloc 4 17 | cap: 1 18 | len: 0 19 | 20 | @realloc: -> 21 | let orig_data = @data 22 | @cap = @cap * 2 23 | @data = malloc (@cap * 4) 24 | memcpy @data, orig_data, @len 25 | 0 26 | 27 | @push: item -> 28 | let d = @data 29 | d[@len] = item 30 | @len = @len + 1 31 | if @len == @cap 32 | then @realloc! 33 | else 0 34 | 35 | --------------------------------------------------------------------------------